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