getpwent.c revision 2917
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));
128		key.data = (u_char *)bf;
129		key.size = len + 2;
130		rval = __hashpw(&key);
131		if (!rval) {
132			key.size = 2;
133			rval = __hashpw(&key);
134		}
135		rval = _getyppass(&_pw_passwd, name, "passwd.byname");
136	}
137#else
138	/*
139	 * Prevent login attempts when YP is not enabled but YP entries
140	 * are in /etc/master.passwd.
141	 */
142	if (rval && _pw_passwd.pw_name[0] == '+') rval = 0;
143#endif
144	if (!_pw_stayopen) {
145		(void)(_pw_db->close)(_pw_db);
146		_pw_db = (DB *)NULL;
147	}
148	return(rval ? &_pw_passwd : (struct passwd *)NULL);
149}
150
151struct passwd *
152#ifdef __STDC__
153getpwuid(uid_t uid)
154#else
155getpwuid(uid)
156	int uid;
157#endif
158{
159	DBT key;
160	int keyuid, rval;
161	char bf[sizeof(keyuid) + 1];
162
163	if (!_pw_db && !__initdb())
164		return((struct passwd *)NULL);
165
166	bf[0] = _PW_KEYBYUID;
167	keyuid = uid;
168	bcopy(&keyuid, bf + 1, sizeof(keyuid));
169	key.data = (u_char *)bf;
170	key.size = sizeof(keyuid) + 1;
171	rval = __hashpw(&key);
172
173#ifdef YP
174	if (!rval && _yp_enabled) {
175		char ypbuf[16];	/* big enough for 32-bit uids and then some */
176		snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
177		rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
178	}
179#endif
180	if (!_pw_stayopen) {
181		(void)(_pw_db->close)(_pw_db);
182		_pw_db = (DB *)NULL;
183	}
184	return(rval ? &_pw_passwd : (struct passwd *)NULL);
185}
186
187int
188setpassent(stayopen)
189	int stayopen;
190{
191	_pw_keynum = 0;
192#ifdef YP
193	_pw_stepping_yp = 0;
194#endif
195	_pw_stayopen = stayopen;
196	return(1);
197}
198
199int
200setpwent()
201{
202	_pw_keynum = 0;
203#ifdef YP
204	_pw_stepping_yp = 0;
205#endif
206	_pw_stayopen = 0;
207	return(1);
208}
209
210void
211endpwent()
212{
213	_pw_keynum = 0;
214#ifdef YP
215	_pw_stepping_yp = 0;
216#endif
217	if (_pw_db) {
218		(void)(_pw_db->close)(_pw_db);
219		_pw_db = (DB *)NULL;
220	}
221}
222
223static
224__initdb()
225{
226	static int warned;
227	char *p;
228
229	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
230	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
231	if (_pw_db) {
232#ifdef YP
233		DBT key, data;
234		char buf[] = { _PW_KEYYPENABLED };
235		key.data = buf;
236		key.size = 1;
237		if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
238			_yp_enabled = 0;
239		} else {
240			_yp_enabled = 1;
241		}
242#endif
243		return(1);
244	}
245	if (!warned)
246		syslog(LOG_ERR, "%s: %m", p);
247	return(0);
248}
249
250static
251__hashpw(key)
252	DBT *key;
253{
254	register char *p, *t;
255	static u_int max;
256	static char *line;
257	DBT data;
258
259	if ((_pw_db->get)(_pw_db, key, &data, 0))
260		return(0);
261	p = (char *)data.data;
262	if (data.size > max && !(line = realloc(line, max += 1024)))
263		return(0);
264
265	t = line;
266#define	EXPAND(e)	e = t; while (*t++ = *p++);
267	EXPAND(_pw_passwd.pw_name);
268	EXPAND(_pw_passwd.pw_passwd);
269	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
270	p += sizeof(int);
271	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
272	p += sizeof(int);
273	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
274	p += sizeof(time_t);
275	EXPAND(_pw_passwd.pw_class);
276	EXPAND(_pw_passwd.pw_gecos);
277	EXPAND(_pw_passwd.pw_dir);
278	EXPAND(_pw_passwd.pw_shell);
279	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
280	p += sizeof(time_t);
281	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
282	p += sizeof _pw_passwd.pw_fields;
283	return(1);
284}
285
286#ifdef YP
287static void
288_pw_breakout_yp(struct passwd *pw, char *result)
289{
290	char *s;
291
292	s = strsep(&result, ":"); /* name */
293	if(!(pw->pw_fields & _PWF_NAME) || (pw->pw_name[0] == '+')) {
294		pw->pw_name = s;
295		pw->pw_fields |= _PWF_NAME;
296	}
297
298	s = strsep(&result, ":"); /* password */
299	if(!(pw->pw_fields & _PWF_PASSWD)) {
300		pw->pw_passwd = s;
301		pw->pw_fields |= _PWF_PASSWD;
302	}
303
304	s = strsep(&result, ":"); /* uid */
305	if(!(pw->pw_fields & _PWF_UID)) {
306		pw->pw_uid = atoi(s);
307		pw->pw_fields |= _PWF_UID;
308	}
309
310	s = strsep(&result, ":"); /* gid */
311	if(!(pw->pw_fields & _PWF_GID))  {
312		pw->pw_gid = atoi(s);
313		pw->pw_fields |= _PWF_GID;
314	}
315
316	s = strsep(&result, ":"); /* gecos */
317	if(!(pw->pw_fields & _PWF_GECOS)) {
318		pw->pw_gecos = s;
319		pw->pw_fields |= _PWF_GECOS;
320	}
321
322	s = strsep(&result, ":"); /* dir */
323	if(!(pw->pw_fields & _PWF_DIR)) {
324		pw->pw_dir = s;
325		pw->pw_fields |= _PWF_DIR;
326	}
327
328	s = strsep(&result, ":"); /* shell */
329	if(!(pw->pw_fields & _PWF_SHELL)) {
330		pw->pw_shell = s;
331		pw->pw_fields |= _PWF_SHELL;
332	}
333}
334
335static char *_pw_yp_domain;
336
337static int
338_getyppass(struct passwd *pw, const char *name, const char *map)
339{
340	char *result, *s;
341	static char resultbuf[1024];
342	int resultlen;
343
344	if(!_pw_yp_domain) {
345		if(yp_get_default_domain(&_pw_yp_domain))
346		  return 0;
347	}
348
349	if(yp_match(_pw_yp_domain, map, name, strlen(name),
350		    &result, &resultlen))
351		return 0;
352
353	s = strchr(result, '\n');
354	if(s) *s = '\0';
355
356	if(resultlen >= sizeof resultbuf) return -1;
357	strcpy(resultbuf, result);
358	result = resultbuf;
359	_pw_breakout_yp(pw, resultbuf);
360
361	return 1;
362}
363
364static int
365_nextyppass(struct passwd *pw)
366{
367	static char *key;
368	static int keylen;
369	char *lastkey, *result;
370	static char resultbuf[1024];
371	int resultlen;
372	int rv;
373
374	if(!_pw_yp_domain) {
375		if(yp_get_default_domain(&_pw_yp_domain))
376		  return 0;
377	}
378
379	if(!_pw_stepping_yp) {
380		if(key) free(key);
381		rv = yp_first(_pw_yp_domain, "passwd.byname",
382			      &key, &keylen, &result, &resultlen);
383		if(rv) {
384			return 0;
385		}
386		_pw_stepping_yp = 1;
387		goto unpack;
388	} else {
389tryagain:
390		lastkey = key;
391		rv = yp_next(_pw_yp_domain, "passwd.byname", key, keylen,
392			     &key, &keylen, &result, &resultlen);
393		free(lastkey);
394unpack:
395		if(rv) {
396			_pw_stepping_yp = 0;
397			return 0;
398		}
399
400		if(resultlen > sizeof(resultbuf)) {
401			free(result);
402			goto tryagain;
403		}
404
405		strcpy(resultbuf, result);
406		free(result);
407		if(result = strchr(resultbuf, '\n')) *result = '\0';
408		_pw_breakout_yp(pw, resultbuf);
409	}
410	return 1;
411}
412
413#endif /* YP */
414