getid.c revision 259065
1/*	$NetBSD: getid.c,v 1.8 2013/10/16 17:27:42 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.8 2013/10/16 17:27:42 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	return (_gr_fp = fopen(grfile, "r")) ? 1 : 0;
210}
211
212
213static int
214grscan(int search, gid_t gid, const char *name)
215{
216
217	if (_gr_filesdone)
218		return 0;
219	for (;;) {
220		if (!fgets(grline, sizeof(grline), _gr_fp)) {
221			if (!search)
222				_gr_filesdone = 1;
223			return 0;
224		}
225		/* skip lines that are too big */
226		if (!strchr(grline, '\n')) {
227			int ch;
228
229			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
230				;
231			continue;
232		}
233		/* skip comments */
234		if (pwline[0] == '#')
235			continue;
236		if (grmatchline(search, gid, name))
237			return 1;
238	}
239	/* NOTREACHED */
240}
241
242static int
243grmatchline(int search, gid_t gid, const char *name)
244{
245	unsigned long	id;
246	char		**m;
247	char		*cp, *bp, *ep;
248
249	/* name may be NULL if search is nonzero */
250
251	bp = grline;
252	memset(&_gr_group, 0, sizeof(_gr_group));
253	_gr_group.gr_name = strsep(&bp, ":\n");
254	if (search && name && strcmp(_gr_group.gr_name, name))
255		return 0;
256	_gr_group.gr_passwd = strsep(&bp, ":\n");
257	if (!(cp = strsep(&bp, ":\n")))
258		return 0;
259	id = strtoul(cp, &ep, 10);
260	if (id > GID_MAX || *ep != '\0')
261		return 0;
262	_gr_group.gr_gid = (gid_t)id;
263	if (search && name == NULL && _gr_group.gr_gid != gid)
264		return 0;
265	cp = NULL;
266	if (bp == NULL)
267		return 0;
268	for (_gr_group.gr_mem = m = members;; bp++) {
269		if (m == &members[MAXGRP - 1])
270			break;
271		if (*bp == ',') {
272			if (cp) {
273				*bp = '\0';
274				*m++ = cp;
275				cp = NULL;
276			}
277		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
278			if (cp) {
279				*bp = '\0';
280				*m++ = cp;
281			}
282			break;
283		} else if (cp == NULL)
284			cp = bp;
285	}
286	*m = NULL;
287	return 1;
288}
289
290
291/*
292 * user lookup functions
293 */
294
295static struct passwd *
296gi_getpwnam(const char *name)
297{
298	int rval;
299
300	if (!pwstart())
301		return NULL;
302	rval = pwscan(1, 0, name);
303	if (!_pw_stayopen)
304		endpwent();
305	return (rval) ? &_pw_passwd : NULL;
306}
307
308static struct passwd *
309gi_getpwuid(uid_t uid)
310{
311	int rval;
312
313	if (!pwstart())
314		return NULL;
315	rval = pwscan(1, uid, NULL);
316	if (!_pw_stayopen)
317		endpwent();
318	return (rval) ? &_pw_passwd : NULL;
319}
320
321static int
322gi_setpassent(int stayopen)
323{
324
325	if (!pwstart())
326		return 0;
327	_pw_stayopen = stayopen;
328	return 1;
329}
330
331static void
332gi_endpwent(void)
333{
334
335	_pw_filesdone = 0;
336	if (_pw_fp) {
337		(void)fclose(_pw_fp);
338		_pw_fp = NULL;
339	}
340}
341
342static int
343pwstart(void)
344{
345
346	_pw_filesdone = 0;
347	if (_pw_fp) {
348		rewind(_pw_fp);
349		return 1;
350	}
351	if (pwfile[0] == '\0')			/* sanity check */
352		return 0;
353	return (_pw_fp = fopen(pwfile, "r")) ? 1 : 0;
354}
355
356
357static int
358pwscan(int search, uid_t uid, const char *name)
359{
360
361	if (_pw_filesdone)
362		return 0;
363	for (;;) {
364		if (!fgets(pwline, sizeof(pwline), _pw_fp)) {
365			if (!search)
366				_pw_filesdone = 1;
367			return 0;
368		}
369		/* skip lines that are too big */
370		if (!strchr(pwline, '\n')) {
371			int ch;
372
373			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
374				;
375			continue;
376		}
377		/* skip comments */
378		if (pwline[0] == '#')
379			continue;
380		if (pwmatchline(search, uid, name))
381			return 1;
382	}
383	/* NOTREACHED */
384}
385
386static int
387pwmatchline(int search, uid_t uid, const char *name)
388{
389	unsigned long	id;
390	char		*cp, *bp, *ep;
391
392	/* name may be NULL if search is nonzero */
393
394	bp = pwline;
395	memset(&_pw_passwd, 0, sizeof(_pw_passwd));
396	_pw_passwd.pw_name = strsep(&bp, ":\n");		/* name */
397	if (search && name && strcmp(_pw_passwd.pw_name, name))
398		return 0;
399
400	_pw_passwd.pw_passwd = strsep(&bp, ":\n");		/* passwd */
401
402	if (!(cp = strsep(&bp, ":\n")))				/* uid */
403		return 0;
404	id = strtoul(cp, &ep, 10);
405	if (id > UID_MAX || *ep != '\0')
406		return 0;
407	_pw_passwd.pw_uid = (uid_t)id;
408	if (search && name == NULL && _pw_passwd.pw_uid != uid)
409		return 0;
410
411	if (!(cp = strsep(&bp, ":\n")))				/* gid */
412		return 0;
413	id = strtoul(cp, &ep, 10);
414	if (id > GID_MAX || *ep != '\0')
415		return 0;
416	_pw_passwd.pw_gid = (gid_t)id;
417
418	if (!(ep = strsep(&bp, ":")))				/* class */
419		return 0;
420	if (!(ep = strsep(&bp, ":")))				/* change */
421		return 0;
422	if (!(ep = strsep(&bp, ":")))				/* expire */
423		return 0;
424
425	if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n")))	/* gecos */
426		return 0;
427	if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n")))		/* directory */
428		return 0;
429	if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n")))	/* shell */
430		return 0;
431
432	if (strchr(bp, ':') != NULL)
433		return 0;
434
435	return 1;
436}
437
438