getpwent.c revision 5714
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)
35static 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
50static struct passwd _pw_passwd;	/* password structure */
51static DB *_pw_db;			/* password database */
52static int _pw_keynum;			/* key counter */
53static int _pw_stayopen;		/* keep fd's open */
54#ifdef YP
55static struct passwd _pw_copy;
56static int _yp_enabled;			/* set true when yp enabled */
57static int _pw_stepping_yp;		/* set true when stepping thru map */
58#endif
59static int __hashpw(), __initdb();
60
61static int _getyppass(struct passwd *, const char *, const char *);
62static int _nextyppass(struct passwd *);
63
64struct passwd *
65getpwent()
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
81tryagain:
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
106struct passwd *
107getpwnam(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#endif
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
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
152struct passwd *
153#ifdef __STDC__
154getpwuid(uid_t uid)
155#else
156getpwuid(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
188int
189setpassent(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
200int
201setpwent()
202{
203	_pw_keynum = 0;
204#ifdef YP
205	_pw_stepping_yp = 0;
206#endif
207	_pw_stayopen = 0;
208	return(1);
209}
210
211void
212endpwent()
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
224static
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
257static
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
294static 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
342static char *_pw_yp_domain;
343
344static 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
371static 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 {
396tryagain:
397		lastkey = key;
398		rv = yp_next(_pw_yp_domain, "passwd.byname", key, keylen,
399			     &key, &keylen, &result, &resultlen);
400		free(lastkey);
401unpack:
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