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