1/*	$NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $	*/
2/*	from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */
3/*	from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */
4
5/*
6 * Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995
7 *	The Regents of the University of California.  All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*-
35 * Copyright (c) 2002 The NetBSD Foundation, Inc.
36 * All rights reserved.
37 *
38 * This code is derived from software contributed to The NetBSD Foundation
39 * by Luke Mewburn of Wasabi Systems.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 *    notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 *    notice, this list of conditions and the following disclaimer in the
48 *    documentation and/or other materials provided with the distribution.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
61 */
62
63#if HAVE_NBTOOL_CONFIG_H
64#include "nbtool_config.h"
65#endif
66
67#include <sys/cdefs.h>
68__RCSID("$NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $");
69
70#include <sys/param.h>
71
72#include <grp.h>
73#include <limits.h>
74#include <pwd.h>
75#include <stdlib.h>
76#include <stdio.h>
77#include <string.h>
78#include <time.h>
79#include <unistd.h>
80
81#include "extern.h"
82
83static	struct group *	gi_getgrnam(const char *);
84static	struct group *	gi_getgrgid(gid_t);
85static	int		gi_setgroupent(int);
86static	void		gi_endgrent(void);
87static	int		grstart(void);
88static	int		grscan(int, gid_t, const char *);
89static	int		grmatchline(int, gid_t, const char *);
90
91static	struct passwd *	gi_getpwnam(const char *);
92static	struct passwd *	gi_getpwuid(uid_t);
93static	int		gi_setpassent(int);
94static	void		gi_endpwent(void);
95static	int		pwstart(void);
96static	int		pwscan(int, uid_t, const char *);
97static	int		pwmatchline(int, uid_t, const char *);
98
99#define	MAXGRP		200
100#define	MAXLINELENGTH	1024
101
102static	FILE		*_gr_fp;
103static	struct group	_gr_group;
104static	int		_gr_stayopen;
105static	int		_gr_filesdone;
106static	FILE		*_pw_fp;
107static	struct passwd	_pw_passwd;	/* password structure */
108static	int		_pw_stayopen;	/* keep fd's open */
109static	int		_pw_filesdone;
110
111static	char		grfile[MAXPATHLEN];
112static	char		pwfile[MAXPATHLEN];
113
114static	char		*members[MAXGRP];
115static	char		grline[MAXLINELENGTH];
116static	char		pwline[MAXLINELENGTH];
117
118int
119setup_getid(const char *dir)
120{
121	if (dir == NULL)
122		return (0);
123
124				/* close existing databases */
125	gi_endgrent();
126	gi_endpwent();
127
128				/* build paths to new databases */
129	snprintf(grfile, sizeof(grfile), "%s/group", dir);
130	snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir);
131
132				/* try to open new databases */
133	if (!grstart() || !pwstart())
134		return (0);
135
136				/* switch pwcache(3) lookup functions */
137	if (pwcache_groupdb(gi_setgroupent, gi_endgrent,
138			    gi_getgrnam, gi_getgrgid) == -1
139	    || pwcache_userdb(gi_setpassent, gi_endpwent,
140			    gi_getpwnam, gi_getpwuid) == -1)
141		return (0);
142
143	return (1);
144}
145
146
147/*
148 * group lookup functions
149 */
150
151static struct group *
152gi_getgrnam(const char *name)
153{
154	int rval;
155
156	if (!grstart())
157		return NULL;
158	rval = grscan(1, 0, name);
159	if (!_gr_stayopen)
160		endgrent();
161	return (rval) ? &_gr_group : NULL;
162}
163
164static struct group *
165gi_getgrgid(gid_t gid)
166{
167	int rval;
168
169	if (!grstart())
170		return NULL;
171	rval = grscan(1, gid, NULL);
172	if (!_gr_stayopen)
173		endgrent();
174	return (rval) ? &_gr_group : NULL;
175}
176
177static int
178gi_setgroupent(int stayopen)
179{
180
181	if (!grstart())
182		return 0;
183	_gr_stayopen = stayopen;
184	return 1;
185}
186
187static void
188gi_endgrent(void)
189{
190
191	_gr_filesdone = 0;
192	if (_gr_fp) {
193		(void)fclose(_gr_fp);
194		_gr_fp = NULL;
195	}
196}
197
198static int
199grstart(void)
200{
201
202	_gr_filesdone = 0;
203	if (_gr_fp) {
204		rewind(_gr_fp);
205		return 1;
206	}
207	if (grfile[0] == '\0')			/* sanity check */
208		return 0;
209
210	_gr_fp = fopen(grfile, "r");
211	if (_gr_fp != NULL)
212		return 1;
213	warn("Can't open `%s'", grfile);
214	return 0;
215}
216
217
218static int
219grscan(int search, gid_t gid, const char *name)
220{
221
222	if (_gr_filesdone)
223		return 0;
224	for (;;) {
225		if (!fgets(grline, sizeof(grline), _gr_fp)) {
226			if (!search)
227				_gr_filesdone = 1;
228			return 0;
229		}
230		/* skip lines that are too big */
231		if (!strchr(grline, '\n')) {
232			int ch;
233
234			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
235				;
236			continue;
237		}
238		/* skip comments */
239		if (grline[0] == '#')
240			continue;
241		if (grmatchline(search, gid, name))
242			return 1;
243	}
244	/* NOTREACHED */
245}
246
247static int
248grmatchline(int search, gid_t gid, const char *name)
249{
250	unsigned long	id;
251	char		**m;
252	char		*cp, *bp, *ep;
253
254	/* name may be NULL if search is nonzero */
255
256	bp = grline;
257	memset(&_gr_group, 0, sizeof(_gr_group));
258	_gr_group.gr_name = strsep(&bp, ":\n");
259	if (search && name && strcmp(_gr_group.gr_name, name))
260		return 0;
261	_gr_group.gr_passwd = strsep(&bp, ":\n");
262	if (!(cp = strsep(&bp, ":\n")))
263		return 0;
264	id = strtoul(cp, &ep, 10);
265	if (id > GID_MAX || *ep != '\0')
266		return 0;
267	_gr_group.gr_gid = (gid_t)id;
268	if (search && name == NULL && _gr_group.gr_gid != gid)
269		return 0;
270	cp = NULL;
271	if (bp == NULL)
272		return 0;
273	for (_gr_group.gr_mem = m = members;; bp++) {
274		if (m == &members[MAXGRP - 1])
275			break;
276		if (*bp == ',') {
277			if (cp) {
278				*bp = '\0';
279				*m++ = cp;
280				cp = NULL;
281			}
282		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
283			if (cp) {
284				*bp = '\0';
285				*m++ = cp;
286			}
287			break;
288		} else if (cp == NULL)
289			cp = bp;
290	}
291	*m = NULL;
292	return 1;
293}
294
295
296/*
297 * user lookup functions
298 */
299
300static struct passwd *
301gi_getpwnam(const char *name)
302{
303	int rval;
304
305	if (!pwstart())
306		return NULL;
307	rval = pwscan(1, 0, name);
308	if (!_pw_stayopen)
309		endpwent();
310	return (rval) ? &_pw_passwd : NULL;
311}
312
313static struct passwd *
314gi_getpwuid(uid_t uid)
315{
316	int rval;
317
318	if (!pwstart())
319		return NULL;
320	rval = pwscan(1, uid, NULL);
321	if (!_pw_stayopen)
322		endpwent();
323	return (rval) ? &_pw_passwd : NULL;
324}
325
326static int
327gi_setpassent(int stayopen)
328{
329
330	if (!pwstart())
331		return 0;
332	_pw_stayopen = stayopen;
333	return 1;
334}
335
336static void
337gi_endpwent(void)
338{
339
340	_pw_filesdone = 0;
341	if (_pw_fp) {
342		(void)fclose(_pw_fp);
343		_pw_fp = NULL;
344	}
345}
346
347static int
348pwstart(void)
349{
350
351	_pw_filesdone = 0;
352	if (_pw_fp) {
353		rewind(_pw_fp);
354		return 1;
355	}
356	if (pwfile[0] == '\0')			/* sanity check */
357		return 0;
358	_pw_fp = fopen(pwfile, "r");
359	if (_pw_fp != NULL)
360		return 1;
361	warn("Can't open `%s'", pwfile);
362	return 0;
363}
364
365
366static int
367pwscan(int search, uid_t uid, const char *name)
368{
369
370	if (_pw_filesdone)
371		return 0;
372	for (;;) {
373		if (!fgets(pwline, sizeof(pwline), _pw_fp)) {
374			if (!search)
375				_pw_filesdone = 1;
376			return 0;
377		}
378		/* skip lines that are too big */
379		if (!strchr(pwline, '\n')) {
380			int ch;
381
382			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
383				;
384			continue;
385		}
386		/* skip comments */
387		if (pwline[0] == '#')
388			continue;
389		if (pwmatchline(search, uid, name))
390			return 1;
391	}
392	/* NOTREACHED */
393}
394
395static int
396pwmatchline(int search, uid_t uid, const char *name)
397{
398	unsigned long	id;
399	char		*cp, *bp, *ep;
400
401	/* name may be NULL if search is nonzero */
402
403	bp = pwline;
404	memset(&_pw_passwd, 0, sizeof(_pw_passwd));
405	_pw_passwd.pw_name = strsep(&bp, ":\n");		/* name */
406	if (search && name && strcmp(_pw_passwd.pw_name, name))
407		return 0;
408
409	_pw_passwd.pw_passwd = strsep(&bp, ":\n");		/* passwd */
410
411	if (!(cp = strsep(&bp, ":\n")))				/* uid */
412		return 0;
413	id = strtoul(cp, &ep, 10);
414	if (id > UID_MAX || *ep != '\0')
415		return 0;
416	_pw_passwd.pw_uid = (uid_t)id;
417	if (search && name == NULL && _pw_passwd.pw_uid != uid)
418		return 0;
419
420	if (!(cp = strsep(&bp, ":\n")))				/* gid */
421		return 0;
422	id = strtoul(cp, &ep, 10);
423	if (id > GID_MAX || *ep != '\0')
424		return 0;
425	_pw_passwd.pw_gid = (gid_t)id;
426
427	if (!(ep = strsep(&bp, ":")))				/* class */
428		return 0;
429	if (!(ep = strsep(&bp, ":")))				/* change */
430		return 0;
431	if (!(ep = strsep(&bp, ":")))				/* expire */
432		return 0;
433
434	if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n")))	/* gecos */
435		return 0;
436	if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n")))		/* directory */
437		return 0;
438	if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n")))	/* shell */
439		return 0;
440
441	if (strchr(bp, ':') != NULL)
442		return 0;
443
444	return 1;
445}
446
447