xref: /netbsd-src/lib/libc/gen/getpwent.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
1 /*	$NetBSD: getpwent.c,v 1.12 1995/02/27 04:13:05 cgd Exp $	*/
2 
3 /*
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by the University of
18  *	California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #if defined(LIBC_SCCS) && !defined(lint)
37 #if 0
38 static char sccsid[] = "@(#)getpwent.c	8.1 (Berkeley) 6/4/93";
39 #else
40 static char rcsid[] = "$NetBSD: getpwent.c,v 1.12 1995/02/27 04:13:05 cgd Exp $";
41 #endif
42 #endif /* LIBC_SCCS and not lint */
43 
44 #include <sys/param.h>
45 #include <fcntl.h>
46 #include <db.h>
47 #include <syslog.h>
48 #include <pwd.h>
49 #include <utmp.h>
50 #include <errno.h>
51 #include <unistd.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <limits.h>
55 #ifdef YP
56 #include <stdio.h>
57 #include <rpc/rpc.h>
58 #include <rpcsvc/yp_prot.h>
59 #include <rpcsvc/ypclnt.h>
60 #endif
61 
62 static struct passwd _pw_passwd;	/* password structure */
63 static DB *_pw_db;			/* password database */
64 static int _pw_keynum;			/* key counter */
65 static int _pw_stayopen;		/* keep fd's open */
66 static int __hashpw(), __initdb();
67 
68 #ifdef YP
69 static char     *__ypcurrent, *__ypdomain;
70 static int      __ypcurrentlen, __ypmode=0;
71 static char	line[1024];
72 
73 static int
74 __ypparse(pw, s)
75 struct passwd *pw;
76 char *s;
77 {
78 	char *bp, *cp;
79 
80 	bp = s;
81 	pw->pw_name = strsep(&bp, ":\n");
82 	pw->pw_passwd = strsep(&bp, ":\n");
83 	if (!(cp = strsep(&bp, ":\n")))
84 		return 1;
85 	pw->pw_uid = atoi(cp);
86 	if (!(cp = strsep(&bp, ":\n")))
87 		return 0;
88 	pw->pw_gid = atoi(cp);
89 	pw->pw_change = 0;
90 	pw->pw_class = "";
91 	pw->pw_gecos = strsep(&bp, ":\n");
92 	pw->pw_dir = strsep(&bp, ":\n");
93 	pw->pw_shell = strsep(&bp, ":\n");
94 	pw->pw_expire = 0;
95 	return 0;
96 }
97 #endif
98 
99 struct passwd *
100 getpwent()
101 {
102 	DBT key;
103 	char bf[sizeof(_pw_keynum) + 1];
104 #ifdef YP
105 	char *bp, *cp;
106 #endif
107 
108 	if (!_pw_db && !__initdb())
109 		return((struct passwd *)NULL);
110 
111 #ifdef YP
112 again:
113 	if(__ypmode) {
114 		char *key, *data;
115 		int keylen, datalen;
116 		int r;
117 
118 		if(!__ypdomain) {
119 			if( _yp_check(&__ypdomain) == 0) {
120 				__ypmode = 0;
121 				goto again;
122 			}
123 		}
124 		if(__ypcurrent) {
125 			r = yp_next(__ypdomain, "passwd.byname",
126 				__ypcurrent, __ypcurrentlen,
127 				&key, &keylen, &data, &datalen);
128 			free(__ypcurrent);
129 			__ypcurrent = NULL;
130 			/*printf("yp_next %d\n", r);*/
131 			switch(r) {
132 			case 0:
133 				break;
134 			default:
135 				__ypcurrent = NULL;
136 				__ypmode = 0;
137 				free(data);
138 				data = NULL;
139 				goto again;
140 			}
141 			__ypcurrent = key;
142 			__ypcurrentlen = keylen;
143 			bcopy(data, line, datalen);
144 			free(data);
145 			data = NULL;
146 		} else {
147 			r = yp_first(__ypdomain, "passwd.byname",
148 				&__ypcurrent, &__ypcurrentlen,
149 				&data, &datalen);
150 			/*printf("yp_first %d\n", r);*/
151 			switch(r) {
152 			case 0:
153 				break;
154 			default:
155 				__ypmode = 0;
156 				free(data);
157 				goto again;
158 			}
159 			bcopy(data, line, datalen);
160 			free(data);
161 			data = NULL;
162 		}
163 		line[datalen] = '\0';
164 		/*printf("line = %s\n", line);*/
165 		bp = line;
166 		goto parse;
167 	}
168 #endif
169 
170 	++_pw_keynum;
171 	bf[0] = _PW_KEYBYNUM;
172 	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
173 	key.data = (u_char *)bf;
174 	key.size = sizeof(_pw_keynum) + 1;
175 	if(__hashpw(&key)) {
176 #ifdef YP
177 		if(strcmp(_pw_passwd.pw_name, "+") == 0) {
178 			__ypmode = 1;
179 			goto again;
180 		}
181 #endif
182 		return &_pw_passwd;
183 	}
184 	return (struct passwd *)NULL;
185 
186 #ifdef YP
187 parse:
188 	_pw_passwd.pw_name = strsep(&bp, ":\n");
189 	_pw_passwd.pw_passwd = strsep(&bp, ":\n");
190 	if (!(cp = strsep(&bp, ":\n")))
191 		goto again;
192 	_pw_passwd.pw_uid = atoi(cp);
193 	if (!(cp = strsep(&bp, ":\n")))
194 		goto again;
195 	_pw_passwd.pw_gid = atoi(cp);
196 	_pw_passwd.pw_change = 0;
197 	_pw_passwd.pw_class = "";
198 	_pw_passwd.pw_gecos = strsep(&bp, ":\n");
199 	_pw_passwd.pw_dir = strsep(&bp, ":\n");
200 	_pw_passwd.pw_shell = strsep(&bp, ":\n");
201 	_pw_passwd.pw_expire = 0;
202 	return &_pw_passwd;
203 #endif
204 }
205 
206 struct passwd *
207 getpwnam(name)
208 	const char *name;
209 {
210 	DBT key;
211 	int len, rval;
212 	char bf[UT_NAMESIZE + 1];
213 
214 	if (!_pw_db && !__initdb())
215 		return((struct passwd *)NULL);
216 
217 #ifdef YP
218 	bf[0] = _PW_KEYBYNAME;
219 	len = strlen("+");
220 	bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
221 	key.data = (u_char *)bf;
222 	key.size = len + 1;
223 
224 	/*
225 	 * If there is a user called "+", then YP is active. In that
226 	 * case we must sequence through the passwd file in sequence.
227 	 */
228 	if ( __hashpw(&key)) {
229 		int r;
230 
231 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
232 			bf[0] = _PW_KEYBYNUM;
233 			bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
234 			key.data = (u_char *)bf;
235 			key.size = sizeof(_pw_keynum) + 1;
236 			if(__hashpw(&key) == 0)
237 				break;
238 			if(strcmp(_pw_passwd.pw_name, "+") == 0) {
239 				if(!__ypdomain) {
240 					if(_yp_check(&__ypdomain) == 0) {
241 						continue;
242 					}
243 				}
244 				if(__ypcurrent) {
245 					free(__ypcurrent);
246 					__ypcurrent = NULL;
247 				}
248 				r = yp_match(__ypdomain, "passwd.byname",
249 					name, strlen(name),
250 					&__ypcurrent, &__ypcurrentlen);
251 				switch(r) {
252 				case 0:
253 					break;
254 				default:
255 					free(__ypcurrent);
256 					__ypcurrent = NULL;
257 					continue;
258 				}
259 				bcopy(__ypcurrent, line, __ypcurrentlen);
260 				line[__ypcurrentlen] = '\0';
261 				if(__ypparse(&_pw_passwd, line))
262 					continue;
263 			}
264 			if( strcmp(_pw_passwd.pw_name, name) == 0) {
265 				if (!_pw_stayopen) {
266 					(void)(_pw_db->close)(_pw_db);
267 					_pw_db = (DB *)NULL;
268 				}
269 				return &_pw_passwd;
270 			}
271 			continue;
272 		}
273 		if (!_pw_stayopen) {
274 			(void)(_pw_db->close)(_pw_db);
275 			_pw_db = (DB *)NULL;
276 		}
277 		return (struct passwd *)NULL;
278 	}
279 #endif /* YP */
280 
281 	bf[0] = _PW_KEYBYNAME;
282 	len = strlen(name);
283 	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
284 	key.data = (u_char *)bf;
285 	key.size = len + 1;
286 	rval = __hashpw(&key);
287 
288 	if (!_pw_stayopen) {
289 		(void)(_pw_db->close)(_pw_db);
290 		_pw_db = (DB *)NULL;
291 	}
292 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
293 }
294 
295 struct passwd *
296 #ifdef __STDC__
297 getpwuid(uid_t uid)
298 #else
299 getpwuid(uid)
300 	int uid;
301 #endif
302 {
303 	DBT key;
304 	char bf[sizeof(_pw_keynum) + 1];
305 	int keyuid, rval, len;
306 
307 	if (!_pw_db && !__initdb())
308 		return((struct passwd *)NULL);
309 
310 #ifdef YP
311 	bf[0] = _PW_KEYBYNAME;
312 	len = strlen("+");
313 	bcopy("+", bf + 1, MIN(len, UT_NAMESIZE));
314 	key.data = (u_char *)bf;
315 	key.size = len + 1;
316 
317 	/*
318 	 * If there is a user called "+", then YP is active. In that
319 	 * case we must sequence through the passwd file in sequence.
320 	 */
321 	if ( __hashpw(&key)) {
322 		char uidbuf[20];
323 		int r;
324 
325 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
326 			bf[0] = _PW_KEYBYNUM;
327 			bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
328 			key.data = (u_char *)bf;
329 			key.size = sizeof(_pw_keynum) + 1;
330 			if(__hashpw(&key) == 0)
331 				break;
332 			if(strcmp(_pw_passwd.pw_name, "+") == 0) {
333 				if(!__ypdomain) {
334 					if(_yp_check(&__ypdomain) == 0) {
335 						continue;
336 					}
337 				}
338 				if(__ypcurrent) {
339 					free(__ypcurrent);
340 					__ypcurrent = NULL;
341 				}
342 				sprintf(uidbuf, "%d", uid);
343 				r = yp_match(__ypdomain, "passwd.byuid",
344 					uidbuf, strlen(uidbuf),
345 					&__ypcurrent, &__ypcurrentlen);
346 				switch(r) {
347 				case 0:
348 					break;
349 				default:
350 					free(__ypcurrent);
351 					__ypcurrent = NULL;
352 					continue;
353 				}
354 				bcopy(__ypcurrent, line, __ypcurrentlen);
355 				line[__ypcurrentlen] = '\0';
356 				if(__ypparse(&_pw_passwd, line))
357 					continue;
358 			}
359 			if( _pw_passwd.pw_uid == uid) {
360 				if (!_pw_stayopen) {
361 					(void)(_pw_db->close)(_pw_db);
362 					_pw_db = (DB *)NULL;
363 				}
364 				return &_pw_passwd;
365 			}
366 			continue;
367 		}
368 		if (!_pw_stayopen) {
369 			(void)(_pw_db->close)(_pw_db);
370 			_pw_db = (DB *)NULL;
371 		}
372 		return (struct passwd *)NULL;
373 	}
374 #endif /* YP */
375 
376 	bf[0] = _PW_KEYBYUID;
377 	keyuid = uid;
378 	bcopy(&keyuid, bf + 1, sizeof(keyuid));
379 	key.data = (u_char *)bf;
380 	key.size = sizeof(keyuid) + 1;
381 	rval = __hashpw(&key);
382 
383 	if (!_pw_stayopen) {
384 		(void)(_pw_db->close)(_pw_db);
385 		_pw_db = (DB *)NULL;
386 	}
387 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
388 }
389 
390 int
391 setpassent(stayopen)
392 	int stayopen;
393 {
394 	_pw_keynum = 0;
395 	_pw_stayopen = stayopen;
396 #ifdef YP
397 	__ypmode = 0;
398 	if(__ypcurrent)
399 		free(__ypcurrent);
400 	__ypcurrent = NULL;
401 #endif
402 	return(1);
403 }
404 
405 void
406 setpwent()
407 {
408 	(void) setpassent(0);
409 }
410 
411 void
412 endpwent()
413 {
414 	_pw_keynum = 0;
415 	if (_pw_db) {
416 		(void)(_pw_db->close)(_pw_db);
417 		_pw_db = (DB *)NULL;
418 	}
419 #ifdef YP
420 	__ypmode = 0;
421 	if(__ypcurrent)
422 		free(__ypcurrent);
423 	__ypcurrent = NULL;
424 #endif
425 }
426 
427 static int
428 __initdb()
429 {
430 	static int warned;
431 	char *p;
432 
433 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
434 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
435 	if (_pw_db)
436 		return(1);
437 	if (!warned)
438 		syslog(LOG_ERR, "%s: %m", p);
439 	warned = 1;
440 	return(0);
441 }
442 
443 static int
444 __hashpw(key)
445 	DBT *key;
446 {
447 	register char *p, *t;
448 	static u_int max;
449 	static char *line;
450 	DBT data;
451 
452 	if ((_pw_db->get)(_pw_db, key, &data, 0))
453 		return(0);
454 	p = (char *)data.data;
455 	if (data.size > max && !(line = realloc(line, max += 1024)))
456 		return(0);
457 
458 	t = line;
459 #define	EXPAND(e)	e = t; while (*t++ = *p++);
460 	EXPAND(_pw_passwd.pw_name);
461 	EXPAND(_pw_passwd.pw_passwd);
462 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
463 	p += sizeof(int);
464 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
465 	p += sizeof(int);
466 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
467 	p += sizeof(time_t);
468 	EXPAND(_pw_passwd.pw_class);
469 	EXPAND(_pw_passwd.pw_gecos);
470 	EXPAND(_pw_passwd.pw_dir);
471 	EXPAND(_pw_passwd.pw_shell);
472 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
473 	p += sizeof(time_t);
474 	return(1);
475 }
476