xref: /freebsd/lib/libc/gen/getpwent.c (revision a316b26e50bbed7cf655fbba726ab87d8ab7599d)
1 /*
2  * Copyright (c) 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. 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 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)getpwent.c	8.1 (Berkeley) 6/4/93";
36 #endif /* LIBC_SCCS and not lint */
37 
38 #include <sys/param.h>
39 #include <fcntl.h>
40 #include <db.h>
41 #include <syslog.h>
42 #include <pwd.h>
43 #include <utmp.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <limits.h>
49 
50 static struct passwd _pw_passwd;	/* password structure */
51 static DB *_pw_db;			/* password database */
52 static int _pw_keynum;			/* key counter */
53 static int _pw_stayopen;		/* keep fd's open */
54 #ifdef YP
55 static struct passwd _pw_copy;
56 static int _yp_enabled;			/* set true when yp enabled */
57 static int _pw_stepping_yp;		/* set true when stepping thru map */
58 #endif
59 static int __hashpw(), __initdb();
60 
61 static int _getyppass(struct passwd *, const char *, const char *);
62 static int _nextyppass(struct passwd *);
63 
64 struct passwd *
65 getpwent()
66 {
67 	DBT key;
68 	char bf[sizeof(_pw_keynum) + 1];
69 	int rv;
70 
71 	if (!_pw_db && !__initdb())
72 		return((struct passwd *)NULL);
73 
74 #ifdef YP
75 	if(_pw_stepping_yp) {
76 		_pw_passwd = _pw_copy;
77 		return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0);
78 	}
79 #endif
80 
81 tryagain:
82 	++_pw_keynum;
83 	bf[0] = _PW_KEYBYNUM;
84 	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
85 	key.data = (u_char *)bf;
86 	key.size = sizeof(_pw_keynum) + 1;
87 	rv = __hashpw(&key);
88 	if(!rv) return (struct passwd *)NULL;
89 #ifdef YP
90 	if(_pw_passwd.pw_name[0] == '+' && _pw_passwd.pw_name[1]) {
91 		_getyppass(&_pw_passwd, &_pw_passwd.pw_name[1],
92 			   "passwd.byname");
93 	} else if(_pw_passwd.pw_name[0] == '+') {
94 		_pw_copy = _pw_passwd;
95 		return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0);
96 	}
97 #else
98 	/* Ignore YP password file entries when YP is disabled. */
99 	if(_pw_passwd.pw_name[0] == '+') {
100 		goto tryagain;
101 	}
102 #endif
103 	return(&_pw_passwd);
104 }
105 
106 struct passwd *
107 getpwnam(name)
108 	const char *name;
109 {
110 	DBT key;
111 	int len, rval;
112 	char bf[UT_NAMESIZE + 2];
113 
114 	if (!_pw_db && !__initdb())
115 		return((struct passwd *)NULL);
116 
117 	bf[0] = _PW_KEYBYNAME;
118 	len = strlen(name);
119 	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
120 	key.data = (u_char *)bf;
121 	key.size = len + 1;
122 	rval = __hashpw(&key);
123 
124 #ifdef YP
125 	if (!rval && _yp_enabled) {
126 		bf[1] = '+';
127 		bcopy(name, bf + 2, MIN(len, UT_NAMESIZE - 1));
128 		key.data = (u_char *)bf;
129 		key.size = len + 2;
130 		rval = __hashpw(&key);
131 		if (!rval && _yp_enabled < 0) {
132 			key.size = 2;
133 			rval = __hashpw(&key);
134 		}
135 		if(rval)
136 			rval = _getyppass(&_pw_passwd, name, "passwd.byname");
137 	}
138 #else
139 	/*
140 	 * Prevent login attempts when YP is not enabled but YP entries
141 	 * are in /etc/master.passwd.
142 	 */
143 	if (rval && _pw_passwd.pw_name[0] == '+') rval = 0;
144 #endif
145 	if (!_pw_stayopen) {
146 		(void)(_pw_db->close)(_pw_db);
147 		_pw_db = (DB *)NULL;
148 	}
149 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
150 }
151 
152 struct passwd *
153 #ifdef __STDC__
154 getpwuid(uid_t uid)
155 #else
156 getpwuid(uid)
157 	int uid;
158 #endif
159 {
160 	DBT key;
161 	int keyuid, rval;
162 	char bf[sizeof(keyuid) + 1];
163 
164 	if (!_pw_db && !__initdb())
165 		return((struct passwd *)NULL);
166 
167 	bf[0] = _PW_KEYBYUID;
168 	keyuid = uid;
169 	bcopy(&keyuid, bf + 1, sizeof(keyuid));
170 	key.data = (u_char *)bf;
171 	key.size = sizeof(keyuid) + 1;
172 	rval = __hashpw(&key);
173 
174 #ifdef YP
175 	if (!rval && _yp_enabled) {
176 		char ypbuf[16];	/* big enough for 32-bit uids and then some */
177 		snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
178 		rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
179 	}
180 #endif
181 	if (!_pw_stayopen) {
182 		(void)(_pw_db->close)(_pw_db);
183 		_pw_db = (DB *)NULL;
184 	}
185 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
186 }
187 
188 int
189 setpassent(stayopen)
190 	int stayopen;
191 {
192 	_pw_keynum = 0;
193 #ifdef YP
194 	_pw_stepping_yp = 0;
195 #endif
196 	_pw_stayopen = stayopen;
197 	return(1);
198 }
199 
200 int
201 setpwent()
202 {
203 	_pw_keynum = 0;
204 #ifdef YP
205 	_pw_stepping_yp = 0;
206 #endif
207 	_pw_stayopen = 0;
208 	return(1);
209 }
210 
211 void
212 endpwent()
213 {
214 	_pw_keynum = 0;
215 #ifdef YP
216 	_pw_stepping_yp = 0;
217 #endif
218 	if (_pw_db) {
219 		(void)(_pw_db->close)(_pw_db);
220 		_pw_db = (DB *)NULL;
221 	}
222 }
223 
224 static
225 __initdb()
226 {
227 	static int warned;
228 	char *p;
229 
230 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
231 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
232 	if (_pw_db) {
233 #ifdef YP
234 		DBT key, data;
235 		char buf[] = { _PW_KEYYPENABLED };
236 		key.data = buf;
237 		key.size = 1;
238 		if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
239 			_yp_enabled = 0;
240 		} else {
241 			/* Distinguish between old and new versions of
242 			   pwd_mkdb. */
243 			if(data.size != 1) {
244 				_yp_enabled = -1;
245 			} else {
246 				_yp_enabled = (int)*((char *)data.data) - 2;
247 			}
248 		}
249 #endif
250 		return(1);
251 	}
252 	if (!warned)
253 		syslog(LOG_ERR, "%s: %m", p);
254 	return(0);
255 }
256 
257 static
258 __hashpw(key)
259 	DBT *key;
260 {
261 	register char *p, *t;
262 	static u_int max;
263 	static char *line;
264 	DBT data;
265 
266 	if ((_pw_db->get)(_pw_db, key, &data, 0))
267 		return(0);
268 	p = (char *)data.data;
269 	if (data.size > max && !(line = realloc(line, max += 1024)))
270 		return(0);
271 
272 	t = line;
273 #define	EXPAND(e)	e = t; while (*t++ = *p++);
274 	EXPAND(_pw_passwd.pw_name);
275 	EXPAND(_pw_passwd.pw_passwd);
276 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
277 	p += sizeof(int);
278 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
279 	p += sizeof(int);
280 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
281 	p += sizeof(time_t);
282 	EXPAND(_pw_passwd.pw_class);
283 	EXPAND(_pw_passwd.pw_gecos);
284 	EXPAND(_pw_passwd.pw_dir);
285 	EXPAND(_pw_passwd.pw_shell);
286 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
287 	p += sizeof(time_t);
288 	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
289 	p += sizeof _pw_passwd.pw_fields;
290 	return(1);
291 }
292 
293 #ifdef YP
294 static void
295 _pw_breakout_yp(struct passwd *pw, char *result)
296 {
297 	char *s;
298 
299 	s = strsep(&result, ":"); /* name */
300 	if(!(pw->pw_fields & _PWF_NAME) || (pw->pw_name[0] == '+')) {
301 		pw->pw_name = s;
302 		pw->pw_fields |= _PWF_NAME;
303 	}
304 
305 	s = strsep(&result, ":"); /* password */
306 	if(!(pw->pw_fields & _PWF_PASSWD)) {
307 		pw->pw_passwd = s;
308 		pw->pw_fields |= _PWF_PASSWD;
309 	}
310 
311 	s = strsep(&result, ":"); /* uid */
312 	if(!(pw->pw_fields & _PWF_UID)) {
313 		pw->pw_uid = atoi(s);
314 		pw->pw_fields |= _PWF_UID;
315 	}
316 
317 	s = strsep(&result, ":"); /* gid */
318 	if(!(pw->pw_fields & _PWF_GID))  {
319 		pw->pw_gid = atoi(s);
320 		pw->pw_fields |= _PWF_GID;
321 	}
322 
323 	s = strsep(&result, ":"); /* gecos */
324 	if(!(pw->pw_fields & _PWF_GECOS)) {
325 		pw->pw_gecos = s;
326 		pw->pw_fields |= _PWF_GECOS;
327 	}
328 
329 	s = strsep(&result, ":"); /* dir */
330 	if(!(pw->pw_fields & _PWF_DIR)) {
331 		pw->pw_dir = s;
332 		pw->pw_fields |= _PWF_DIR;
333 	}
334 
335 	s = strsep(&result, ":"); /* shell */
336 	if(!(pw->pw_fields & _PWF_SHELL)) {
337 		pw->pw_shell = s;
338 		pw->pw_fields |= _PWF_SHELL;
339 	}
340 }
341 
342 static char *_pw_yp_domain;
343 
344 static int
345 _getyppass(struct passwd *pw, const char *name, const char *map)
346 {
347 	char *result, *s;
348 	static char resultbuf[1024];
349 	int resultlen;
350 
351 	if(!_pw_yp_domain) {
352 		if(yp_get_default_domain(&_pw_yp_domain))
353 		  return 0;
354 	}
355 
356 	if(yp_match(_pw_yp_domain, map, name, strlen(name),
357 		    &result, &resultlen))
358 		return 0;
359 
360 	s = strchr(result, '\n');
361 	if(s) *s = '\0';
362 
363 	if(resultlen >= sizeof resultbuf) return 0;
364 	strcpy(resultbuf, result);
365 	result = resultbuf;
366 	_pw_breakout_yp(pw, resultbuf);
367 
368 	return 1;
369 }
370 
371 static int
372 _nextyppass(struct passwd *pw)
373 {
374 	static char *key;
375 	static int keylen;
376 	char *lastkey, *result;
377 	static char resultbuf[1024];
378 	int resultlen;
379 	int rv;
380 
381 	if(!_pw_yp_domain) {
382 		if(yp_get_default_domain(&_pw_yp_domain))
383 		  return 0;
384 	}
385 
386 	if(!_pw_stepping_yp) {
387 		if(key) free(key);
388 		rv = yp_first(_pw_yp_domain, "passwd.byname",
389 			      &key, &keylen, &result, &resultlen);
390 		if(rv) {
391 			return 0;
392 		}
393 		_pw_stepping_yp = 1;
394 		goto unpack;
395 	} else {
396 tryagain:
397 		lastkey = key;
398 		rv = yp_next(_pw_yp_domain, "passwd.byname", key, keylen,
399 			     &key, &keylen, &result, &resultlen);
400 		free(lastkey);
401 unpack:
402 		if(rv) {
403 			_pw_stepping_yp = 0;
404 			return 0;
405 		}
406 
407 		if(resultlen > sizeof(resultbuf)) {
408 			free(result);
409 			goto tryagain;
410 		}
411 
412 		strcpy(resultbuf, result);
413 		free(result);
414 		if(result = strchr(resultbuf, '\n')) *result = '\0';
415 		_pw_breakout_yp(pw, resultbuf);
416 	}
417 	return 1;
418 }
419 
420 #endif /* YP */
421