xref: /freebsd/contrib/mtree/getid.c (revision a0ee8cc6)
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 
83 static	struct group *	gi_getgrnam(const char *);
84 static	struct group *	gi_getgrgid(gid_t);
85 static	int		gi_setgroupent(int);
86 static	void		gi_endgrent(void);
87 static	int		grstart(void);
88 static	int		grscan(int, gid_t, const char *);
89 static	int		grmatchline(int, gid_t, const char *);
90 
91 static	struct passwd *	gi_getpwnam(const char *);
92 static	struct passwd *	gi_getpwuid(uid_t);
93 static	int		gi_setpassent(int);
94 static	void		gi_endpwent(void);
95 static	int		pwstart(void);
96 static	int		pwscan(int, uid_t, const char *);
97 static	int		pwmatchline(int, uid_t, const char *);
98 
99 #define	MAXGRP		200
100 #define	MAXLINELENGTH	1024
101 
102 static	FILE		*_gr_fp;
103 static	struct group	_gr_group;
104 static	int		_gr_stayopen;
105 static	int		_gr_filesdone;
106 static	FILE		*_pw_fp;
107 static	struct passwd	_pw_passwd;	/* password structure */
108 static	int		_pw_stayopen;	/* keep fd's open */
109 static	int		_pw_filesdone;
110 
111 static	char		grfile[MAXPATHLEN];
112 static	char		pwfile[MAXPATHLEN];
113 
114 static	char		*members[MAXGRP];
115 static	char		grline[MAXLINELENGTH];
116 static	char		pwline[MAXLINELENGTH];
117 
118 int
119 setup_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 
151 static struct group *
152 gi_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 
164 static struct group *
165 gi_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 
177 static int
178 gi_setgroupent(int stayopen)
179 {
180 
181 	if (!grstart())
182 		return 0;
183 	_gr_stayopen = stayopen;
184 	return 1;
185 }
186 
187 static void
188 gi_endgrent(void)
189 {
190 
191 	_gr_filesdone = 0;
192 	if (_gr_fp) {
193 		(void)fclose(_gr_fp);
194 		_gr_fp = NULL;
195 	}
196 }
197 
198 static int
199 grstart(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 
218 static int
219 grscan(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 
247 static int
248 grmatchline(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 
300 static struct passwd *
301 gi_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 
313 static struct passwd *
314 gi_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 
326 static int
327 gi_setpassent(int stayopen)
328 {
329 
330 	if (!pwstart())
331 		return 0;
332 	_pw_stayopen = stayopen;
333 	return 1;
334 }
335 
336 static void
337 gi_endpwent(void)
338 {
339 
340 	_pw_filesdone = 0;
341 	if (_pw_fp) {
342 		(void)fclose(_pw_fp);
343 		_pw_fp = NULL;
344 	}
345 }
346 
347 static int
348 pwstart(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 
366 static int
367 pwscan(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 
395 static int
396 pwmatchline(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