Home | History | Annotate | Line # | Download | only in gen
getpwent.c revision 1.33
      1 /*	$NetBSD: getpwent.c,v 1.33 1999/01/16 14:42:54 lukem Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  * Portions Copyright (c) 1994, 1995, Jason Downs.  All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 #if defined(LIBC_SCCS) && !defined(lint)
     39 #if 0
     40 static char sccsid[] = "@(#)getpwent.c	8.2 (Berkeley) 4/27/95";
     41 #else
     42 __RCSID("$NetBSD: getpwent.c,v 1.33 1999/01/16 14:42:54 lukem Exp $");
     43 #endif
     44 #endif /* LIBC_SCCS and not lint */
     45 
     46 #include "namespace.h"
     47 #include <sys/param.h>
     48 #include <fcntl.h>
     49 #include <db.h>
     50 #include <syslog.h>
     51 #include <pwd.h>
     52 #include <utmp.h>
     53 #include <errno.h>
     54 #include <unistd.h>
     55 #include <stdlib.h>
     56 #include <string.h>
     57 #include <limits.h>
     58 #include <netgroup.h>
     59 #include <nsswitch.h>
     60 #ifdef HESIOD
     61 #include <hesiod.h>
     62 #endif
     63 #ifdef YP
     64 #include <machine/param.h>
     65 #include <stdio.h>
     66 #include <rpc/rpc.h>
     67 #include <rpcsvc/yp_prot.h>
     68 #include <rpcsvc/ypclnt.h>
     69 #endif
     70 
     71 #include "pw_private.h"
     72 
     73 #ifdef __weak_alias
     74 __weak_alias(endpwent,_endpwent);
     75 __weak_alias(getpwent,_getpwent);
     76 __weak_alias(getpwnam,_getpwnam);
     77 __weak_alias(getpwuid,_getpwuid);
     78 __weak_alias(setpassent,_setpassent);
     79 __weak_alias(setpwent,_setpwent);
     80 #endif
     81 
     82 
     83 /*
     84  * The lookup techniques and data extraction code here must be kept
     85  * in sync with that in `pwd_mkdb'.
     86  */
     87 
     88 static struct passwd _pw_passwd;	/* password structure */
     89 static DB *_pw_db;			/* password database */
     90 static int _pw_keynum;			/* key counter */
     91 static int _pw_stayopen;		/* keep fd's open */
     92 static int _pw_flags;			/* password flags */
     93 static int _pw_none;			/* true if getpwent got EOF */
     94 
     95 static int __hashpw __P((DBT *));
     96 static int __initdb __P((void));
     97 
     98 const char __yp_token[] = "__YP!";	/* Let pwd_mkdb pull this in. */
     99 
    100 #ifdef YP
    101 static char     *__ypcurrent, *__ypdomain;
    102 static int      __ypcurrentlen;
    103 #endif
    104 
    105 #ifdef HESIOD
    106 static int	_pw_hesnum;
    107 #endif
    108 
    109 #if defined(YP) || defined(HESIOD)
    110 enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP };
    111 static enum _pwmode __pwmode;
    112 
    113 enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER };
    114 
    115 static struct passwd	*__pwproto = (struct passwd *)NULL;
    116 static int		 __pwproto_flags;
    117 static char		 line[1024];
    118 static long		 prbuf[1024 / sizeof(long)];
    119 static DB		*__pwexclude = (DB *)NULL;
    120 
    121 static int	__pwexclude_add __P((const char *));
    122 static int	__pwexclude_is __P((const char *));
    123 static void	__pwproto_set __P((void));
    124 static int	__ypmaptype __P((void));
    125 static int	__pwparse __P((struct passwd *, char *));
    126 
    127 	/* macros for deciding which YP maps to use. */
    128 #define PASSWD_BYNAME	(__ypmaptype() == YPMAP_MASTER \
    129 			    ? "master.passwd.byname" : "passwd.byname")
    130 #define PASSWD_BYUID	(__ypmaptype() == YPMAP_MASTER \
    131 			    ? "master.passwd.byuid" : "passwd.byuid")
    132 
    133 /*
    134  * add a name to the compat mode exclude list
    135  */
    136 static int
    137 __pwexclude_add(name)
    138 	const char *name;
    139 {
    140 	DBT key;
    141 	DBT data;
    142 
    143 	/* initialize the exclusion table if needed. */
    144 	if(__pwexclude == (DB *)NULL) {
    145 		__pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
    146 		if(__pwexclude == (DB *)NULL)
    147 			return 1;
    148 	}
    149 
    150 	/* set up the key */
    151 	key.size = strlen(name);
    152 	/* LINTED key does not get modified */
    153 	key.data = (char *)name;
    154 
    155 	/* data is nothing. */
    156 	data.data = NULL;
    157 	data.size = 0;
    158 
    159 	/* store it */
    160 	if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1)
    161 		return 1;
    162 
    163 	return 0;
    164 }
    165 
    166 /*
    167  * test if a name is on the compat mode exclude list
    168  */
    169 static int
    170 __pwexclude_is(name)
    171 	const char *name;
    172 {
    173 	DBT key;
    174 	DBT data;
    175 
    176 	if(__pwexclude == (DB *)NULL)
    177 		return 0;	/* nothing excluded */
    178 
    179 	/* set up the key */
    180 	key.size = strlen(name);
    181 	/* LINTED key does not get modified */
    182 	key.data = (char *)name;
    183 
    184 	if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0)
    185 		return 1;	/* excluded */
    186 
    187 	return 0;
    188 }
    189 
    190 /*
    191  * setup the compat mode prototype template
    192  */
    193 static void
    194 __pwproto_set()
    195 {
    196 	char *ptr;
    197 	struct passwd *pw = &_pw_passwd;
    198 
    199 	/* make this the new prototype */
    200 	ptr = (char *)(void *)prbuf;
    201 
    202 	/* first allocate the struct. */
    203 	__pwproto = (struct passwd *)ptr;
    204 	ptr += sizeof(struct passwd);
    205 
    206 	/* name */
    207 	if(pw->pw_name && (pw->pw_name)[0]) {
    208 		ptr = (char *)ALIGN(ptr);
    209 		memmove(ptr, pw->pw_name, strlen(pw->pw_name) + 1);
    210 		__pwproto->pw_name = ptr;
    211 		ptr += (strlen(pw->pw_name) + 1);
    212 	} else
    213 		__pwproto->pw_name = (char *)NULL;
    214 
    215 	/* password */
    216 	if(pw->pw_passwd && (pw->pw_passwd)[0]) {
    217 		ptr = (char *)ALIGN(ptr);
    218 		memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1);
    219 		__pwproto->pw_passwd = ptr;
    220 		ptr += (strlen(pw->pw_passwd) + 1);
    221 	} else
    222 		__pwproto->pw_passwd = (char *)NULL;
    223 
    224 	/* uid */
    225 	__pwproto->pw_uid = pw->pw_uid;
    226 
    227 	/* gid */
    228 	__pwproto->pw_gid = pw->pw_gid;
    229 
    230 	/* change (ignored anyway) */
    231 	__pwproto->pw_change = pw->pw_change;
    232 
    233 	/* class (ignored anyway) */
    234 	__pwproto->pw_class = "";
    235 
    236 	/* gecos */
    237 	if(pw->pw_gecos && (pw->pw_gecos)[0]) {
    238 		ptr = (char *)ALIGN(ptr);
    239 		memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1);
    240 		__pwproto->pw_gecos = ptr;
    241 		ptr += (strlen(pw->pw_gecos) + 1);
    242 	} else
    243 		__pwproto->pw_gecos = (char *)NULL;
    244 
    245 	/* dir */
    246 	if(pw->pw_dir && (pw->pw_dir)[0]) {
    247 		ptr = (char *)ALIGN(ptr);
    248 		memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1);
    249 		__pwproto->pw_dir = ptr;
    250 		ptr += (strlen(pw->pw_dir) + 1);
    251 	} else
    252 		__pwproto->pw_dir = (char *)NULL;
    253 
    254 	/* shell */
    255 	if(pw->pw_shell && (pw->pw_shell)[0]) {
    256 		ptr = (char *)ALIGN(ptr);
    257 		memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1);
    258 		__pwproto->pw_shell = ptr;
    259 		ptr += (strlen(pw->pw_shell) + 1);
    260 	} else
    261 		__pwproto->pw_shell = (char *)NULL;
    262 
    263 	/* expire (ignored anyway) */
    264 	__pwproto->pw_expire = pw->pw_expire;
    265 
    266 	/* flags */
    267 	__pwproto_flags = _pw_flags;
    268 }
    269 
    270 static int
    271 __ypmaptype()
    272 {
    273 	static int maptype = -1;
    274 	int order, r;
    275 
    276 	if (maptype != -1)
    277 		return (maptype);
    278 
    279 	maptype = YPMAP_NONE;
    280 	if (geteuid() != 0)
    281 		return (maptype);
    282 
    283 	if (!__ypdomain) {
    284 		if( _yp_check(&__ypdomain) == 0)
    285 			return (maptype);
    286 	}
    287 
    288 	r = yp_order(__ypdomain, "master.passwd.byname", &order);
    289 	if (r == 0) {
    290 		maptype = YPMAP_MASTER;
    291 		return (maptype);
    292 	}
    293 
    294 	/*
    295 	 * NIS+ in YP compat mode doesn't support
    296 	 * YPPROC_ORDER -- no point in continuing.
    297 	 */
    298 	if (r == YPERR_YPERR)
    299 		return (maptype);
    300 
    301 	/* master.passwd doesn't exist -- try passwd.adjunct */
    302 	if (r == YPERR_MAP) {
    303 		r = yp_order(__ypdomain, "passwd.adjunct.byname", &order);
    304 		if (r == 0)
    305 			maptype = YPMAP_ADJUNCT;
    306 		return (maptype);
    307 	}
    308 
    309 	return (maptype);
    310 }
    311 
    312 /*
    313  * parse an old-style passwd file line (from NIS or HESIOD)
    314  */
    315 static int
    316 __pwparse(pw, s)
    317 	struct passwd *pw;
    318 	char *s;
    319 {
    320 	static char adjunctpw[YPMAXRECORD + 2];
    321 	int flags, maptype;
    322 
    323 	maptype = __ypmaptype();
    324 	flags = _PASSWORD_NOWARN;
    325 	if (maptype != YPMAP_MASTER)
    326 		flags |= _PASSWORD_OLDFMT;
    327 	if (! __pw_scan(s, pw, &flags))
    328 		return 1;
    329 
    330 	/* now let the prototype override, if set. */
    331 	if(__pwproto != (struct passwd *)NULL) {
    332 #ifdef PW_OVERRIDE_PASSWD
    333 		if(__pwproto->pw_passwd != (char *)NULL)
    334 			pw->pw_passwd = __pwproto->pw_passwd;
    335 #endif
    336 		if(!(__pwproto_flags & _PASSWORD_NOUID))
    337 			pw->pw_uid = __pwproto->pw_uid;
    338 		if(!(__pwproto_flags & _PASSWORD_NOGID))
    339 			pw->pw_gid = __pwproto->pw_gid;
    340 		if(__pwproto->pw_gecos != (char *)NULL)
    341 			pw->pw_gecos = __pwproto->pw_gecos;
    342 		if(__pwproto->pw_dir != (char *)NULL)
    343 			pw->pw_dir = __pwproto->pw_dir;
    344 		if(__pwproto->pw_shell != (char *)NULL)
    345 			pw->pw_shell = __pwproto->pw_shell;
    346 	}
    347 	if ((maptype == YPMAP_ADJUNCT) &&
    348 	    (strstr(pw->pw_passwd, "##") != NULL)) {
    349 		char *data, *bp;
    350 		int datalen;
    351 
    352 		if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name,
    353 		    (int)strlen(pw->pw_name), &data, &datalen) == 0) {
    354 			if (datalen > sizeof(adjunctpw) - 1)
    355 				datalen = sizeof(adjunctpw) - 1;
    356 			strncpy(adjunctpw, data, datalen);
    357 
    358 				/* skip name to get password */
    359 			if ((bp = strsep(&data, ":")) != NULL &&
    360 			    (bp = strsep(&data, ":")) != NULL)
    361 				pw->pw_passwd = bp;
    362 		}
    363 	}
    364 	return 0;
    365 }
    366 #endif /* YP || HESIOD */
    367 
    368 /*
    369  * local files implementation of getpw*()
    370  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    371  */
    372 static int	_local_getpw __P((void *, void *, va_list));
    373 
    374 static int
    375 _local_getpw(rv, cb_data, ap)
    376 	void	*rv;
    377 	void	*cb_data;
    378 	va_list	 ap;
    379 {
    380 	DBT		 key;
    381 	char		 bf[MAX(UT_NAMESIZE, sizeof(_pw_keynum)) + 1];
    382 	uid_t		 uid;
    383 	int		 search, len, rval;
    384 	const char	*name;
    385 
    386 	if (!_pw_db && !__initdb())
    387 		return NS_UNAVAIL;
    388 
    389 	search = va_arg(ap, int);
    390 	bf[0] = search;
    391 	switch (search) {
    392 	case _PW_KEYBYNUM:
    393 		++_pw_keynum;
    394 		memmove(bf + 1, (char *)&_pw_keynum, sizeof(_pw_keynum));
    395 		key.size = sizeof(_pw_keynum) + 1;
    396 		break;
    397 	case _PW_KEYBYNAME:
    398 		name = va_arg(ap, const char *);
    399 		len = strlen(name);
    400 		memmove(bf + 1, name, MIN(len, UT_NAMESIZE));
    401 		key.size = len + 1;
    402 		break;
    403 	case _PW_KEYBYUID:
    404 		uid = va_arg(ap, uid_t);
    405 		memmove(bf + 1, (char *)&uid, sizeof(len));
    406 		key.size = sizeof(uid) + 1;
    407 		break;
    408 	default:
    409 		abort();
    410 	}
    411 
    412 	key.data = (u_char *)bf;
    413 	rval = __hashpw(&key);
    414 	if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM) {
    415 		_pw_none = 1;
    416 		rval = NS_SUCCESS;
    417 	}
    418 
    419 	if (!_pw_stayopen && (search != _PW_KEYBYNUM)) {
    420 		(void)(_pw_db->close)(_pw_db);
    421 		_pw_db = (DB *)NULL;
    422 	}
    423 	return (rval);
    424 }
    425 
    426 #ifdef HESIOD
    427 /*
    428  * hesiod implementation of getpw*()
    429  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    430  */
    431 static int	_dns_getpw __P((void *, void *, va_list));
    432 
    433 static int
    434 _dns_getpw(rv, cb_data, ap)
    435 	void	*rv;
    436 	void	*cb_data;
    437 	va_list	 ap;
    438 {
    439 	const char	 *name;
    440 	uid_t		  uid;
    441 	int		  search;
    442 	char		**hp;
    443 
    444 
    445 	search = va_arg(ap, int);
    446 	switch (search) {
    447 	case _PW_KEYBYNUM:
    448 		snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum);
    449 		_pw_hesnum++;
    450 		break;
    451 	case _PW_KEYBYNAME:
    452 		name = va_arg(ap, const char *);
    453 		strncpy(line, name, sizeof(line));
    454 		break;
    455 	case _PW_KEYBYUID:
    456 		uid = va_arg(ap, uid_t);
    457 		snprintf(line, sizeof(line), "%u", (unsigned int)uid);
    458 		break;
    459 	default:
    460 		abort();
    461 	}
    462 	line[sizeof(line) - 1] = '\0';
    463 
    464 	hp = hes_resolve(line, "passwd");
    465 	if (hp == NULL) {
    466 		switch (hes_error()) {
    467 		case HES_ER_NOTFOUND:
    468 			if (search == _PW_KEYBYNUM) {
    469 				_pw_hesnum = 0;
    470 				_pw_none = 1;
    471 				return NS_SUCCESS;
    472 			}
    473 			return NS_NOTFOUND;
    474 		case HES_ER_OK:
    475 			abort();
    476 		default:
    477 			return NS_UNAVAIL;
    478 		}
    479 	}
    480 
    481 	strncpy(line, hp[0], sizeof(line));	/* only check first elem */
    482 	line[sizeof(line) - 1] = '\0';
    483 	hes_free(hp);
    484 	if (__pwparse(&_pw_passwd, line))
    485 		return NS_UNAVAIL;
    486 	return NS_SUCCESS;
    487 }
    488 #endif
    489 
    490 #ifdef YP
    491 /*
    492  * nis implementation of getpw*()
    493  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    494  */
    495 static int	_nis_getpw __P((void *, void *, va_list));
    496 
    497 static int
    498 _nis_getpw(rv, cb_data, ap)
    499 	void	*rv;
    500 	void	*cb_data;
    501 	va_list	 ap;
    502 {
    503 	const char	*name;
    504 	uid_t		 uid;
    505 	int		 search;
    506 	char		*key, *data;
    507 	char		*map = PASSWD_BYNAME;
    508 	int		 keylen, datalen, r;
    509 
    510 	if(__ypdomain == NULL) {
    511 		if(_yp_check(&__ypdomain) == 0)
    512 			return NS_UNAVAIL;
    513 	}
    514 
    515 	search = va_arg(ap, int);
    516 	switch (search) {
    517 	case _PW_KEYBYNUM:
    518 		break;
    519 	case _PW_KEYBYNAME:
    520 		name = va_arg(ap, const char *);
    521 		strncpy(line, name, sizeof(line));
    522 		break;
    523 	case _PW_KEYBYUID:
    524 		uid = va_arg(ap, uid_t);
    525 		snprintf(line, sizeof(line), "%u", (unsigned int)uid);
    526 		map = PASSWD_BYUID;
    527 		break;
    528 	default:
    529 		abort();
    530 	}
    531 	line[sizeof(line) - 1] = '\0';
    532 	if (search != _PW_KEYBYNUM) {
    533 		data = NULL;
    534 		r = yp_match(__ypdomain, map, line, (int)strlen(line),
    535 				&data, &datalen);
    536 		switch (r) {
    537 		case 0:
    538 			break;
    539 		case YPERR_KEY:
    540 			r =  NS_NOTFOUND;
    541 			break;
    542 		default:
    543 			r = NS_UNAVAIL;
    544 			break;
    545 		}
    546 		if (r != 0) {
    547 			if (data)
    548 				free(data);
    549 			return r;
    550 		}
    551 		data[datalen] = '\0';		/* clear trailing \n */
    552 		strncpy(line, data, sizeof(line));
    553 		line[sizeof(line) - 1] = '\0';
    554 		free(data);
    555 		if (__pwparse(&_pw_passwd, line))
    556 			return NS_UNAVAIL;
    557 		return NS_SUCCESS;
    558 	}
    559 
    560 	for (;;) {
    561 		data = key = NULL;
    562 		if (__ypcurrent) {
    563 			r = yp_next(__ypdomain, map,
    564 					__ypcurrent, __ypcurrentlen,
    565 					&key, &keylen, &data, &datalen);
    566 			free(__ypcurrent);
    567 			switch (r) {
    568 			case 0:
    569 				__ypcurrent = key;
    570 				__ypcurrentlen = keylen;
    571 				break;
    572 			case YPERR_NOMORE:
    573 				__ypcurrent = NULL;
    574 				_pw_none = 1;
    575 				if (key)
    576 					free(key);
    577 				return NS_SUCCESS;
    578 			default:
    579 				r = NS_UNAVAIL;
    580 				break;
    581 			}
    582 		} else {
    583 			r = 0;
    584 			if (yp_first(__ypdomain, map, &__ypcurrent,
    585 					&__ypcurrentlen, &data, &datalen))
    586 				r = NS_UNAVAIL;
    587 		}
    588 		if (r != 0) {
    589 			if (key)
    590 				free(key);
    591 			if (data)
    592 				free(data);
    593 			return r;
    594 		}
    595 		data[datalen] = '\0';		/* clear trailing \n */
    596 		strncpy(line, data, sizeof(line));
    597 		line[sizeof(line) - 1] = '\0';
    598 				free(data);
    599 		if (! __pwparse(&_pw_passwd, line))
    600 			return NS_SUCCESS;
    601 	}
    602 	/* NOTREACHED */
    603 } /* _nis_getpw */
    604 #endif
    605 
    606 #if defined(YP) || defined(HESIOD)
    607 /*
    608  * See if the compat token is in the database.  Only works if pwd_mkdb knows
    609  * about the token.
    610  */
    611 static int	__has_compatpw __P((void));
    612 
    613 static int
    614 __has_compatpw()
    615 {
    616 	DBT key, data;
    617 	DBT pkey, pdata;
    618 	int len;
    619 	char bf[UT_NAMESIZE];
    620 
    621 	key.data = (u_char *)__yp_token;
    622 	key.size = strlen(__yp_token);
    623 
    624 	/* Pre-token database support. */
    625 	bf[0] = _PW_KEYBYNAME;
    626 	len = strlen("+");
    627 	memmove(bf + 1, "+", MIN(len, UT_NAMESIZE));
    628 	pkey.data = (u_char *)bf;
    629 	pkey.size = len + 1;
    630 
    631 	if ((_pw_db->get)(_pw_db, &key, &data, 0)
    632 	    && (_pw_db->get)(_pw_db, &pkey, &pdata, 0))
    633 		return 0;		/* No compat token */
    634 	return 1;
    635 }
    636 
    637 /*
    638  * log an error if "files" or "compat" is specified in passwd_compat database
    639  */
    640 static int	_bad_getpw __P((void *, void *, va_list));
    641 
    642 static int
    643 _bad_getpw(rv, cb_data, ap)
    644 	void	*rv;
    645 	void	*cb_data;
    646 	va_list	 ap;
    647 {
    648 	static int warned;
    649 	if (!warned) {
    650 		syslog(LOG_ERR,
    651 			"nsswitch.conf passwd_compat database can't use '%s'",
    652 			(char *)cb_data);
    653 	}
    654 	warned = 1;
    655 	return NS_UNAVAIL;
    656 }
    657 
    658 /*
    659  * when a name lookup in compat mode is required (e.g., '+name', or a name in
    660  * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database.
    661  * only Hesiod and NIS is supported - it doesn't make sense to lookup
    662  * compat names from 'files' or 'compat'.
    663  */
    664 static int	__getpwcompat __P((int, uid_t, const char *));
    665 
    666 static int
    667 __getpwcompat(type, uid, name)
    668 	int		 type;
    669 	uid_t		 uid;
    670 	const char	*name;
    671 {
    672 	static ns_dtab	dtab[] = {
    673 		NS_FILES_CB(_bad_getpw, NULL),
    674 		NS_DNS_CB(_dns_getpw, NULL),
    675 		NS_NIS_CB(_nis_getpw, NULL),
    676 		NS_COMPAT_CB(_bad_getpw, NULL),
    677 		{ NULL, NULL, NULL }
    678 	};
    679 
    680 	switch (type) {
    681 	case _PW_KEYBYNUM:
    682 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type);
    683 	case _PW_KEYBYNAME:
    684 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, name);
    685 	case _PW_KEYBYUID:
    686 		return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, type, uid);
    687 	default:
    688 		abort();
    689 	}
    690 }
    691 
    692 /*
    693  * compat implementation of getpwent()
    694  * varargs (ignored):
    695  *	type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    696  */
    697 static int	_compat_getpwent __P((void *, void *, va_list));
    698 
    699 static int
    700 _compat_getpwent(rv, cb_data, ap)
    701 	void	*rv;
    702 	void	*cb_data;
    703 	va_list	 ap;
    704 {
    705 	DBT		 key;
    706 	char		 bf[sizeof(_pw_keynum) + 1];
    707 	static char	*name = NULL;
    708 	const char	*user, *host, *dom;
    709 	int		 has_compatpw;
    710 
    711 	if (!_pw_db && !__initdb())
    712 		return NS_UNAVAIL;
    713 
    714 	has_compatpw = __has_compatpw();
    715 
    716 again:
    717 	if (has_compatpw && (__pwmode != PWMODE_NONE)) {
    718 		int r;
    719 
    720 		switch (__pwmode) {
    721 		case PWMODE_FULL:
    722 			r = __getpwcompat(_PW_KEYBYNUM, 0, NULL);
    723 			if (r == NS_SUCCESS)
    724 				return r;
    725 			__pwmode = PWMODE_NONE;
    726 			break;
    727 
    728 		case PWMODE_NETGRP:
    729 			r = getnetgrent(&host, &user, &dom);
    730 			if (r == 0) {	/* end of group */
    731 				endnetgrent();
    732 				__pwmode = PWMODE_NONE;
    733 				break;
    734 			}
    735 			if (!user || !*user)
    736 				break;
    737 			r = __getpwcompat(_PW_KEYBYNAME, 0, user);
    738 			if (r == NS_SUCCESS)
    739 				return r;
    740 			break;
    741 
    742 		case PWMODE_USER:
    743 			if (name == NULL) {
    744 				__pwmode = PWMODE_NONE;
    745 				break;
    746 			}
    747 			r = __getpwcompat(_PW_KEYBYNAME, 0, name);
    748 			free(name);
    749 			name = NULL;
    750 			if (r == NS_SUCCESS)
    751 				return r;
    752 			break;
    753 
    754 		case PWMODE_NONE:
    755 			abort();
    756 		}
    757 		goto again;
    758 	}
    759 
    760 	++_pw_keynum;
    761 	bf[0] = _PW_KEYBYNUM;
    762 	memmove(bf + 1, (char *)&_pw_keynum, sizeof(_pw_keynum));
    763 	key.data = (u_char *)bf;
    764 	key.size = sizeof(_pw_keynum) + 1;
    765 	if(__hashpw(&key) == NS_SUCCESS) {
    766 		/* if we don't have YP at all, don't bother. */
    767 		if (has_compatpw) {
    768 			if(_pw_passwd.pw_name[0] == '+') {
    769 				/* set the mode */
    770 				switch(_pw_passwd.pw_name[1]) {
    771 				case '\0':
    772 					__pwmode = PWMODE_FULL;
    773 					break;
    774 				case '@':
    775 					__pwmode = PWMODE_NETGRP;
    776 					setnetgrent(_pw_passwd.pw_name + 2);
    777 					break;
    778 				default:
    779 					__pwmode = PWMODE_USER;
    780 					name = strdup(_pw_passwd.pw_name + 1);
    781 					break;
    782 				}
    783 
    784 				/* save the prototype */
    785 				__pwproto_set();
    786 				goto again;
    787 			} else if(_pw_passwd.pw_name[0] == '-') {
    788 				/* an attempted exclusion */
    789 				switch(_pw_passwd.pw_name[1]) {
    790 				case '\0':
    791 					break;
    792 				case '@':
    793 					setnetgrent(_pw_passwd.pw_name + 2);
    794 					while(getnetgrent(&host, &user, &dom)) {
    795 						if(user && *user)
    796 							__pwexclude_add(user);
    797 					}
    798 					endnetgrent();
    799 					break;
    800 				default:
    801 					__pwexclude_add(_pw_passwd.pw_name + 1);
    802 					break;
    803 				}
    804 				goto again;
    805 			}
    806 		}
    807 		return NS_SUCCESS;
    808 	}
    809 	return NS_NOTFOUND;
    810 }
    811 
    812 /*
    813  * compat implementation of getpwnam() and getpwuid()
    814  * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ]
    815  */
    816 static int	_compat_getpw __P((void *, void *, va_list));
    817 
    818 static int
    819 _compat_getpw(rv, cb_data, ap)
    820 	void	*rv;
    821 	void	*cb_data;
    822 	va_list	 ap;
    823 {
    824 	DBT		key;
    825 	int		len, search, rval;
    826 	uid_t		uid;
    827 	char		bf[MAXLOGNAME + 1];
    828 	const char	*name;
    829 
    830 	search = va_arg(ap, int);
    831 	uid = 0;
    832 	name = NULL;
    833 	rval = NS_NOTFOUND;
    834 
    835 	if (!_pw_db && !__initdb())
    836 		return NS_UNAVAIL;
    837 
    838 	switch (search) {
    839 	case _PW_KEYBYNAME:
    840 		name = va_arg(ap, const char *);
    841 		break;
    842 	case _PW_KEYBYUID:
    843 		uid = va_arg(ap, uid_t);
    844 		break;
    845 	default:
    846 		abort();
    847 	}
    848 
    849 	/*
    850 	 * If YP is active, we must sequence through the passwd file
    851 	 * in sequence.
    852 	 */
    853 	if (__has_compatpw()) {
    854 		int r;
    855 		int s = -1;
    856 		const char *host, *user, *dom;
    857 
    858 		for(_pw_keynum=1; _pw_keynum; _pw_keynum++) {
    859 			bf[0] = _PW_KEYBYNUM;
    860 			memmove(bf + 1, (char *)&_pw_keynum,
    861 			    sizeof(_pw_keynum));
    862 			key.data = (u_char *)bf;
    863 			key.size = sizeof(_pw_keynum) + 1;
    864 			if(__hashpw(&key) != NS_SUCCESS)
    865 				break;
    866 			switch(_pw_passwd.pw_name[0]) {
    867 			case '+':
    868 				/* save the prototype */
    869 				__pwproto_set();
    870 
    871 				switch(_pw_passwd.pw_name[1]) {
    872 				case '\0':
    873 					r = __getpwcompat(search, uid, name);
    874 					if (r != NS_SUCCESS)
    875 						continue;
    876 					break;
    877 				case '@':
    878 pwnam_netgrp:
    879 					if(__ypcurrent) {
    880 						free(__ypcurrent);
    881 						__ypcurrent = NULL;
    882 					}
    883 					if(s == -1)	/* first time */
    884 						setnetgrent(_pw_passwd.pw_name + 2);
    885 					s = getnetgrent(&host, &user, &dom);
    886 					if(s == 0) {	/* end of group */
    887 						endnetgrent();
    888 						s = -1;
    889 						continue;
    890 					}
    891 					if (!user || !*user)
    892 						goto pwnam_netgrp;
    893 
    894 					r = __getpwcompat(_PW_KEYBYNAME,
    895 					    0, user);
    896 
    897 					if (r == NS_UNAVAIL)
    898 						return r;
    899 					if (r == NS_NOTFOUND) {
    900 						/*
    901 						 * just because this user is bad
    902 						 * it doesn't mean they all are.
    903 						 */
    904 						goto pwnam_netgrp;
    905 					}
    906 					break;
    907 				default:
    908 					user = _pw_passwd.pw_name + 1;
    909 					r = __getpwcompat(_PW_KEYBYNAME,
    910 					    0, user);
    911 
    912 					if (r == NS_UNAVAIL)
    913 						return r;
    914 					if (r == NS_NOTFOUND)
    915 						continue;
    916 					break;
    917 				}
    918 				if(__pwexclude_is(_pw_passwd.pw_name)) {
    919 					if(s == 1)	/* inside netgrp */
    920 						goto pwnam_netgrp;
    921 					continue;
    922 				}
    923 				break;
    924 			case '-':
    925 				/* attempted exclusion */
    926 				switch(_pw_passwd.pw_name[1]) {
    927 				case '\0':
    928 					break;
    929 				case '@':
    930 					setnetgrent(_pw_passwd.pw_name + 2);
    931 					while(getnetgrent(&host, &user, &dom)) {
    932 						if(user && *user)
    933 							__pwexclude_add(user);
    934 					}
    935 					endnetgrent();
    936 					break;
    937 				default:
    938 					__pwexclude_add(_pw_passwd.pw_name + 1);
    939 					break;
    940 				}
    941 				break;
    942 			}
    943 			if ((search == _PW_KEYBYNAME &&
    944 				    strcmp(_pw_passwd.pw_name, name) == 0)
    945 			 || (search == _PW_KEYBYUID &&
    946 				    _pw_passwd.pw_uid == uid)) {
    947 				rval = NS_SUCCESS;
    948 				break;
    949 			}
    950 			if(s == 1)	/* inside netgrp */
    951 				goto pwnam_netgrp;
    952 			continue;
    953 		}
    954 		__pwproto = (struct passwd *)NULL;
    955 	} else {
    956 		bf[0] = _PW_KEYBYNAME;
    957 		len = strlen(name);
    958 		memmove(bf + 1, name, MIN(len, UT_NAMESIZE));
    959 		key.data = (u_char *)bf;
    960 		key.size = len + 1;
    961 		rval = __hashpw(&key);
    962 	}
    963 
    964 	if (!_pw_stayopen) {
    965 		(void)(_pw_db->close)(_pw_db);
    966 		_pw_db = (DB *)NULL;
    967 	}
    968 	if(__pwexclude != (DB *)NULL) {
    969 		(void)(__pwexclude->close)(__pwexclude);
    970 			__pwexclude = (DB *)NULL;
    971 	}
    972 	return rval;
    973 }
    974 #endif /* YP || HESIOD */
    975 
    976 struct passwd *
    977 getpwent()
    978 {
    979 	int		r;
    980 	static ns_dtab	dtab[] = {
    981 		NS_FILES_CB(_local_getpw, NULL),
    982 		NS_DNS_CB(_dns_getpw, NULL),
    983 		NS_NIS_CB(_nis_getpw, NULL),
    984 		NS_COMPAT_CB(_compat_getpwent, NULL),
    985 		{ NULL, NULL, NULL }
    986 	};
    987 
    988 	_pw_none = 0;
    989 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNUM);
    990 	if (_pw_none || r != NS_SUCCESS)
    991 		return (struct passwd *)NULL;
    992 	return &_pw_passwd;
    993 }
    994 
    995 struct passwd *
    996 getpwnam(name)
    997 	const char *name;
    998 {
    999 	int		r;
   1000 	static ns_dtab	dtab[] = {
   1001 		NS_FILES_CB(_local_getpw, NULL),
   1002 		NS_DNS_CB(_dns_getpw, NULL),
   1003 		NS_NIS_CB(_nis_getpw, NULL),
   1004 		NS_COMPAT_CB(_compat_getpw, NULL),
   1005 		{ NULL, NULL, NULL }
   1006 	};
   1007 
   1008 	if (name == NULL || name[0] == '\0')
   1009 		return (struct passwd *)NULL;
   1010 
   1011 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYNAME, name);
   1012 	return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
   1013 }
   1014 
   1015 struct passwd *
   1016 getpwuid(uid)
   1017 	uid_t uid;
   1018 {
   1019 	int		r;
   1020 	static ns_dtab	dtab[] = {
   1021 		NS_FILES_CB(_local_getpw, NULL),
   1022 		NS_DNS_CB(_dns_getpw, NULL),
   1023 		NS_NIS_CB(_nis_getpw, NULL),
   1024 		NS_COMPAT_CB(_compat_getpw, NULL),
   1025 		{ NULL, NULL, NULL }
   1026 	};
   1027 
   1028 	r = nsdispatch(NULL, dtab, NSDB_PASSWD, _PW_KEYBYUID, uid);
   1029 	return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL);
   1030 }
   1031 
   1032 int
   1033 setpassent(stayopen)
   1034 	int stayopen;
   1035 {
   1036 	_pw_keynum = 0;
   1037 	_pw_stayopen = stayopen;
   1038 #ifdef YP
   1039 	__pwmode = PWMODE_NONE;
   1040 	if(__ypcurrent)
   1041 		free(__ypcurrent);
   1042 	__ypcurrent = NULL;
   1043 #endif
   1044 #ifdef HESIOD
   1045 	_pw_hesnum = 0;
   1046 #endif
   1047 #if defined(YP) || defined(HESIOD)
   1048 	if(__pwexclude != (DB *)NULL) {
   1049 		(void)(__pwexclude->close)(__pwexclude);
   1050 		__pwexclude = (DB *)NULL;
   1051 	}
   1052 	__pwproto = (struct passwd *)NULL;
   1053 #endif
   1054 	return 1;
   1055 }
   1056 
   1057 void
   1058 setpwent()
   1059 {
   1060 	(void) setpassent(0);
   1061 }
   1062 
   1063 void
   1064 endpwent()
   1065 {
   1066 	_pw_keynum = 0;
   1067 	if (_pw_db) {
   1068 		(void)(_pw_db->close)(_pw_db);
   1069 		_pw_db = (DB *)NULL;
   1070 	}
   1071 #if defined(YP) || defined(HESIOD)
   1072 	__pwmode = PWMODE_NONE;
   1073 #endif
   1074 #ifdef YP
   1075 	if(__ypcurrent)
   1076 		free(__ypcurrent);
   1077 	__ypcurrent = NULL;
   1078 #endif
   1079 #ifdef HESIOD
   1080 	_pw_hesnum = 0;
   1081 #endif
   1082 #if defined(YP) || defined(HESIOD)
   1083 	if(__pwexclude != (DB *)NULL) {
   1084 		(void)(__pwexclude->close)(__pwexclude);
   1085 		__pwexclude = (DB *)NULL;
   1086 	}
   1087 	__pwproto = (struct passwd *)NULL;
   1088 #endif
   1089 }
   1090 
   1091 static int
   1092 __initdb()
   1093 {
   1094 	static int warned;
   1095 	char *p;
   1096 
   1097 #if defined(YP) || defined(HESIOD)
   1098 	__pwmode = PWMODE_NONE;
   1099 #endif
   1100 	if (geteuid() == 0) {
   1101 		_pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL);
   1102 		if (_pw_db)
   1103 			return(1);
   1104 	}
   1105 	_pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL);
   1106 	if (_pw_db)
   1107 		return 1;
   1108 	if (!warned)
   1109 		syslog(LOG_ERR, "%s: %m", p);
   1110 	warned = 1;
   1111 	return 0;
   1112 }
   1113 
   1114 static int
   1115 __hashpw(key)
   1116 	DBT *key;
   1117 {
   1118 	char *p, *t;
   1119 	static u_int max;
   1120 	static char *buf;
   1121 	DBT data;
   1122 
   1123 	switch ((_pw_db->get)(_pw_db, key, &data, 0)) {
   1124 	case 0:
   1125 		break;			/* found */
   1126 	case 1:
   1127 		return NS_NOTFOUND;
   1128 	case -1:
   1129 		return NS_UNAVAIL;	/* error in db routines */
   1130 	default:
   1131 		abort();
   1132 	}
   1133 
   1134 	p = (char *)data.data;
   1135 	if (data.size > max && !(buf = realloc(buf, (max += 1024))))
   1136 		return NS_UNAVAIL;
   1137 
   1138 	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
   1139 	t = buf;
   1140 #define	EXPAND(e)	e = t; while ((*t++ = *p++));
   1141 #define	SCALAR(v)	memmove(&(v), p, sizeof v); p += sizeof v
   1142 	EXPAND(_pw_passwd.pw_name);
   1143 	EXPAND(_pw_passwd.pw_passwd);
   1144 	SCALAR(_pw_passwd.pw_uid);
   1145 	SCALAR(_pw_passwd.pw_gid);
   1146 	SCALAR(_pw_passwd.pw_change);
   1147 	EXPAND(_pw_passwd.pw_class);
   1148 	EXPAND(_pw_passwd.pw_gecos);
   1149 	EXPAND(_pw_passwd.pw_dir);
   1150 	EXPAND(_pw_passwd.pw_shell);
   1151 	SCALAR(_pw_passwd.pw_expire);
   1152 
   1153 	/* See if there's any data left.  If so, read in flags. */
   1154 	if (data.size > (p - (char *)data.data)) {
   1155 		SCALAR(_pw_flags);
   1156 	} else
   1157 		_pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID;	/* default */
   1158 
   1159 	return NS_SUCCESS;
   1160 }
   1161