Home | History | Annotate | Line # | Download | only in gen
pwcache.c revision 1.24
      1 /*	$NetBSD: pwcache.c,v 1.24 2003/08/07 16:42:55 agc Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Keith Muller of the University of California, San Diego.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 /*-
     36  * Copyright (c) 1992 Keith Muller.
     37  *
     38  * This code is derived from software contributed to Berkeley by
     39  * Keith Muller of the University of California, San Diego.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. All advertising materials mentioning features or use of this software
     50  *    must display the following acknowledgement:
     51  *	This product includes software developed by the University of
     52  *	California, Berkeley and its contributors.
     53  * 4. Neither the name of the University nor the names of its contributors
     54  *    may be used to endorse or promote products derived from this software
     55  *    without specific prior written permission.
     56  *
     57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     67  * SUCH DAMAGE.
     68  */
     69 
     70 /*-
     71  * Copyright (c) 2002 The NetBSD Foundation, Inc.
     72  * All rights reserved.
     73  *
     74  * Redistribution and use in source and binary forms, with or without
     75  * modification, are permitted provided that the following conditions
     76  * are met:
     77  * 1. Redistributions of source code must retain the above copyright
     78  *    notice, this list of conditions and the following disclaimer.
     79  * 2. Redistributions in binary form must reproduce the above copyright
     80  *    notice, this list of conditions and the following disclaimer in the
     81  *    documentation and/or other materials provided with the distribution.
     82  * 3. All advertising materials mentioning features or use of this software
     83  *    must display the following acknowledgement:
     84  *        This product includes software developed by the NetBSD
     85  *        Foundation, Inc. and its contributors.
     86  * 4. Neither the name of The NetBSD Foundation nor the names of its
     87  *    contributors may be used to endorse or promote products derived
     88  *    from this software without specific prior written permission.
     89  *
     90  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     91  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     92  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     93  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     94  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     95  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     96  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     97  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     98  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     99  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    100  * POSSIBILITY OF SUCH DAMAGE.
    101  */
    102 
    103 #include <sys/cdefs.h>
    104 #if defined(LIBC_SCCS) && !defined(lint)
    105 #if 0
    106 static char sccsid[] = "@(#)cache.c	8.1 (Berkeley) 5/31/93";
    107 #else
    108 __RCSID("$NetBSD: pwcache.c,v 1.24 2003/08/07 16:42:55 agc Exp $");
    109 #endif
    110 #endif /* LIBC_SCCS and not lint */
    111 
    112 #include "namespace.h"
    113 
    114 #include <sys/types.h>
    115 #include <sys/param.h>
    116 
    117 #include <assert.h>
    118 #include <grp.h>
    119 #include <pwd.h>
    120 #include <stdio.h>
    121 #include <stdlib.h>
    122 #include <string.h>
    123 #include <unistd.h>
    124 
    125 #ifdef __weak_alias
    126 __weak_alias(user_from_uid,_user_from_uid)
    127 __weak_alias(group_from_gid,_group_from_gid)
    128 __weak_alias(pwcache_userdb,_pwcache_userdb)
    129 __weak_alias(pwcache_groupdb,_pwcache_groupdb)
    130 #endif
    131 
    132 #if !HAVE_PWCACHE_USERDB
    133 #include "pwcache.h"
    134 
    135 /*
    136  * routines that control user, group, uid and gid caches (for the archive
    137  * member print routine).
    138  * IMPORTANT:
    139  * these routines cache BOTH hits and misses, a major performance improvement
    140  */
    141 
    142 /*
    143  * function pointers to various name lookup routines.
    144  * these may be changed as necessary.
    145  */
    146 static	int		(*_pwcache_setgroupent)(int)		= setgroupent;
    147 static	void		(*_pwcache_endgrent)(void)		= endgrent;
    148 static	struct group *	(*_pwcache_getgrnam)(const char *)	= getgrnam;
    149 static	struct group *	(*_pwcache_getgrgid)(gid_t)		= getgrgid;
    150 static	int		(*_pwcache_setpassent)(int)		= setpassent;
    151 static	void		(*_pwcache_endpwent)(void)		= endpwent;
    152 static	struct passwd *	(*_pwcache_getpwnam)(const char *)	= getpwnam;
    153 static	struct passwd *	(*_pwcache_getpwuid)(uid_t)		= getpwuid;
    154 
    155 /*
    156  * internal state
    157  */
    158 static	int	pwopn;		/* is password file open */
    159 static	int	gropn;		/* is group file open */
    160 static	UIDC	**uidtb;	/* uid to name cache */
    161 static	GIDC	**gidtb;	/* gid to name cache */
    162 static	UIDC	**usrtb;	/* user name to uid cache */
    163 static	GIDC	**grptb;	/* group name to gid cache */
    164 
    165 static	int	uidtb_fail;	/* uidtb_start() failed ? */
    166 static	int	gidtb_fail;	/* gidtb_start() failed ? */
    167 static	int	usrtb_fail;	/* usrtb_start() failed ? */
    168 static	int	grptb_fail;	/* grptb_start() failed ? */
    169 
    170 
    171 static	u_int	st_hash(const char *, size_t, int);
    172 static	int	uidtb_start(void);
    173 static	int	gidtb_start(void);
    174 static	int	usrtb_start(void);
    175 static	int	grptb_start(void);
    176 
    177 
    178 static u_int
    179 st_hash(const char *name, size_t len, int tabsz)
    180 {
    181 	u_int key = 0;
    182 
    183 	_DIAGASSERT(name != NULL);
    184 
    185 	while (len--) {
    186 		key += *name++;
    187 		key = (key << 8) | (key >> 24);
    188 	}
    189 
    190 	return (key % tabsz);
    191 }
    192 
    193 /*
    194  * uidtb_start
    195  *	creates an an empty uidtb
    196  * Return:
    197  *	0 if ok, -1 otherwise
    198  */
    199 static int
    200 uidtb_start(void)
    201 {
    202 
    203 	if (uidtb != NULL)
    204 		return (0);
    205 	if (uidtb_fail)
    206 		return (-1);
    207 	if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
    208 		++uidtb_fail;
    209 		return (-1);
    210 	}
    211 	return (0);
    212 }
    213 
    214 /*
    215  * gidtb_start
    216  *	creates an an empty gidtb
    217  * Return:
    218  *	0 if ok, -1 otherwise
    219  */
    220 static int
    221 gidtb_start(void)
    222 {
    223 
    224 	if (gidtb != NULL)
    225 		return (0);
    226 	if (gidtb_fail)
    227 		return (-1);
    228 	if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
    229 		++gidtb_fail;
    230 		return (-1);
    231 	}
    232 	return (0);
    233 }
    234 
    235 /*
    236  * usrtb_start
    237  *	creates an an empty usrtb
    238  * Return:
    239  *	0 if ok, -1 otherwise
    240  */
    241 static int
    242 usrtb_start(void)
    243 {
    244 
    245 	if (usrtb != NULL)
    246 		return (0);
    247 	if (usrtb_fail)
    248 		return (-1);
    249 	if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
    250 		++usrtb_fail;
    251 		return (-1);
    252 	}
    253 	return (0);
    254 }
    255 
    256 /*
    257  * grptb_start
    258  *	creates an an empty grptb
    259  * Return:
    260  *	0 if ok, -1 otherwise
    261  */
    262 static int
    263 grptb_start(void)
    264 {
    265 
    266 	if (grptb != NULL)
    267 		return (0);
    268 	if (grptb_fail)
    269 		return (-1);
    270 	if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
    271 		++grptb_fail;
    272 		return (-1);
    273 	}
    274 	return (0);
    275 }
    276 
    277 #if !HAVE_USER_FROM_UID
    278 /*
    279  * user_from_uid()
    280  *	caches the name (if any) for the uid. If noname clear, we always
    281  *	return the the stored name (if valid or invalid match).
    282  *	We use a simple hash table.
    283  * Return
    284  *	Pointer to stored name (or a empty string)
    285  */
    286 
    287 const char *
    288 user_from_uid(uid_t uid, int noname)
    289 {
    290 	struct passwd *pw;
    291 	UIDC *ptr, **pptr;
    292 
    293 	if ((uidtb == NULL) && (uidtb_start() < 0))
    294 		return (NULL);
    295 
    296 	/*
    297 	 * see if we have this uid cached
    298 	 */
    299 	pptr = uidtb + (uid % UID_SZ);
    300 	ptr = *pptr;
    301 
    302 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
    303 		/*
    304 		 * have an entry for this uid
    305 		 */
    306 		if (!noname || (ptr->valid == VALID))
    307 			return (ptr->name);
    308 		return (NULL);
    309 	}
    310 
    311 	/*
    312 	 * No entry for this uid, we will add it
    313 	 */
    314 	if (!pwopn) {
    315 		if (_pwcache_setpassent != NULL)
    316 			(*_pwcache_setpassent)(1);
    317 		++pwopn;
    318 	}
    319 
    320 	if (ptr == NULL)
    321 		*pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
    322 
    323 	if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) {
    324 		/*
    325 		 * no match for this uid in the local password file
    326 		 * a string that is the uid in numeric format
    327 		 */
    328 		if (ptr == NULL)
    329 			return (NULL);
    330 		ptr->uid = uid;
    331 		(void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid);
    332 		ptr->valid = INVALID;
    333 		if (noname)
    334 			return (NULL);
    335 	} else {
    336 		/*
    337 		 * there is an entry for this uid in the password file
    338 		 */
    339 		if (ptr == NULL)
    340 			return (pw->pw_name);
    341 		ptr->uid = uid;
    342 		(void)strlcpy(ptr->name, pw->pw_name, UNMLEN);
    343 		ptr->valid = VALID;
    344 	}
    345 	return (ptr->name);
    346 }
    347 
    348 /*
    349  * group_from_gid()
    350  *	caches the name (if any) for the gid. If noname clear, we always
    351  *	return the the stored name (if valid or invalid match).
    352  *	We use a simple hash table.
    353  * Return
    354  *	Pointer to stored name (or a empty string)
    355  */
    356 
    357 const char *
    358 group_from_gid(gid_t gid, int noname)
    359 {
    360 	struct group *gr;
    361 	GIDC *ptr, **pptr;
    362 
    363 	if ((gidtb == NULL) && (gidtb_start() < 0))
    364 		return (NULL);
    365 
    366 	/*
    367 	 * see if we have this gid cached
    368 	 */
    369 	pptr = gidtb + (gid % GID_SZ);
    370 	ptr = *pptr;
    371 
    372 	if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
    373 		/*
    374 		 * have an entry for this gid
    375 		 */
    376 		if (!noname || (ptr->valid == VALID))
    377 			return (ptr->name);
    378 		return (NULL);
    379 	}
    380 
    381 	/*
    382 	 * No entry for this gid, we will add it
    383 	 */
    384 	if (!gropn) {
    385 		if (_pwcache_setgroupent != NULL)
    386 			(*_pwcache_setgroupent)(1);
    387 		++gropn;
    388 	}
    389 
    390 	if (ptr == NULL)
    391 		*pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
    392 
    393 	if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) {
    394 		/*
    395 		 * no match for this gid in the local group file, put in
    396 		 * a string that is the gid in numberic format
    397 		 */
    398 		if (ptr == NULL)
    399 			return (NULL);
    400 		ptr->gid = gid;
    401 		(void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid);
    402 		ptr->valid = INVALID;
    403 		if (noname)
    404 			return (NULL);
    405 	} else {
    406 		/*
    407 		 * there is an entry for this group in the group file
    408 		 */
    409 		if (ptr == NULL)
    410 			return (gr->gr_name);
    411 		ptr->gid = gid;
    412 		(void)strlcpy(ptr->name, gr->gr_name, GNMLEN);
    413 		ptr->valid = VALID;
    414 	}
    415 	return (ptr->name);
    416 }
    417 #endif /* HAVE_USER_FROM_UID */
    418 
    419 /*
    420  * uid_from_user()
    421  *	caches the uid for a given user name. We use a simple hash table.
    422  * Return
    423  *	the uid (if any) for a user name, or a -1 if no match can be found
    424  */
    425 
    426 int
    427 uid_from_user(const char *name, uid_t *uid)
    428 {
    429 	struct passwd *pw;
    430 	UIDC *ptr, **pptr;
    431 	size_t namelen;
    432 
    433 	/*
    434 	 * return -1 for mangled names
    435 	 */
    436 	if (name == NULL || ((namelen = strlen(name)) == 0))
    437 		return (-1);
    438 	if ((usrtb == NULL) && (usrtb_start() < 0))
    439 		return (-1);
    440 
    441 	/*
    442 	 * look up in hash table, if found and valid return the uid,
    443 	 * if found and invalid, return a -1
    444 	 */
    445 	pptr = usrtb + st_hash(name, namelen, UNM_SZ);
    446 	ptr = *pptr;
    447 
    448 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
    449 		if (ptr->valid == INVALID)
    450 			return (-1);
    451 		*uid = ptr->uid;
    452 		return (0);
    453 	}
    454 
    455 	if (!pwopn) {
    456 		if (_pwcache_setpassent != NULL)
    457 			(*_pwcache_setpassent)(1);
    458 		++pwopn;
    459 	}
    460 
    461 	if (ptr == NULL)
    462 		*pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
    463 
    464 	/*
    465 	 * no match, look it up, if no match store it as an invalid entry,
    466 	 * or store the matching uid
    467 	 */
    468 	if (ptr == NULL) {
    469 		if ((pw = (*_pwcache_getpwnam)(name)) == NULL)
    470 			return (-1);
    471 		*uid = pw->pw_uid;
    472 		return (0);
    473 	}
    474 	(void)strlcpy(ptr->name, name, UNMLEN);
    475 	if ((pw = (*_pwcache_getpwnam)(name)) == NULL) {
    476 		ptr->valid = INVALID;
    477 		return (-1);
    478 	}
    479 	ptr->valid = VALID;
    480 	*uid = ptr->uid = pw->pw_uid;
    481 	return (0);
    482 }
    483 
    484 /*
    485  * gid_from_group()
    486  *	caches the gid for a given group name. We use a simple hash table.
    487  * Return
    488  *	the gid (if any) for a group name, or a -1 if no match can be found
    489  */
    490 
    491 int
    492 gid_from_group(const char *name, gid_t *gid)
    493 {
    494 	struct group *gr;
    495 	GIDC *ptr, **pptr;
    496 	size_t namelen;
    497 
    498 	/*
    499 	 * return -1 for mangled names
    500 	 */
    501 	if (name == NULL || ((namelen = strlen(name)) == 0))
    502 		return (-1);
    503 	if ((grptb == NULL) && (grptb_start() < 0))
    504 		return (-1);
    505 
    506 	/*
    507 	 * look up in hash table, if found and valid return the uid,
    508 	 * if found and invalid, return a -1
    509 	 */
    510 	pptr = grptb + st_hash(name, namelen, GID_SZ);
    511 	ptr = *pptr;
    512 
    513 	if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
    514 		if (ptr->valid == INVALID)
    515 			return (-1);
    516 		*gid = ptr->gid;
    517 		return (0);
    518 	}
    519 
    520 	if (!gropn) {
    521 		if (_pwcache_setgroupent != NULL)
    522 			(*_pwcache_setgroupent)(1);
    523 		++gropn;
    524 	}
    525 
    526 	if (ptr == NULL)
    527 		*pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
    528 
    529 	/*
    530 	 * no match, look it up, if no match store it as an invalid entry,
    531 	 * or store the matching gid
    532 	 */
    533 	if (ptr == NULL) {
    534 		if ((gr = (*_pwcache_getgrnam)(name)) == NULL)
    535 			return (-1);
    536 		*gid = gr->gr_gid;
    537 		return (0);
    538 	}
    539 
    540 	(void)strlcpy(ptr->name, name, GNMLEN);
    541 	if ((gr = (*_pwcache_getgrnam)(name)) == NULL) {
    542 		ptr->valid = INVALID;
    543 		return (-1);
    544 	}
    545 	ptr->valid = VALID;
    546 	*gid = ptr->gid = gr->gr_gid;
    547 	return (0);
    548 }
    549 
    550 #define FLUSHTB(arr, len, fail)				\
    551 	do {						\
    552 		if (arr != NULL) {			\
    553 			for (i = 0; i < len; i++)	\
    554 				if (arr[i] != NULL)	\
    555 					free(arr[i]);	\
    556 			arr = NULL;			\
    557 		}					\
    558 		fail = 0;				\
    559 	} while (/* CONSTCOND */0);
    560 
    561 int
    562 pwcache_userdb(
    563 	int		(*a_setpassent)(int),
    564 	void		(*a_endpwent)(void),
    565 	struct passwd *	(*a_getpwnam)(const char *),
    566 	struct passwd *	(*a_getpwuid)(uid_t))
    567 {
    568 	int i;
    569 
    570 		/* a_setpassent and a_endpwent may be NULL */
    571 	if (a_getpwnam == NULL || a_getpwuid == NULL)
    572 		return (-1);
    573 
    574 	if (_pwcache_endpwent != NULL)
    575 		(*_pwcache_endpwent)();
    576 	FLUSHTB(uidtb, UID_SZ, uidtb_fail);
    577 	FLUSHTB(usrtb, UNM_SZ, usrtb_fail);
    578 	pwopn = 0;
    579 	_pwcache_setpassent = a_setpassent;
    580 	_pwcache_endpwent = a_endpwent;
    581 	_pwcache_getpwnam = a_getpwnam;
    582 	_pwcache_getpwuid = a_getpwuid;
    583 
    584 	return (0);
    585 }
    586 
    587 int
    588 pwcache_groupdb(
    589 	int		(*a_setgroupent)(int),
    590 	void		(*a_endgrent)(void),
    591 	struct group *	(*a_getgrnam)(const char *),
    592 	struct group *	(*a_getgrgid)(gid_t))
    593 {
    594 	int i;
    595 
    596 		/* a_setgroupent and a_endgrent may be NULL */
    597 	if (a_getgrnam == NULL || a_getgrgid == NULL)
    598 		return (-1);
    599 
    600 	if (_pwcache_endgrent != NULL)
    601 		(*_pwcache_endgrent)();
    602 	FLUSHTB(gidtb, GID_SZ, gidtb_fail);
    603 	FLUSHTB(grptb, GNM_SZ, grptb_fail);
    604 	gropn = 0;
    605 	_pwcache_setgroupent = a_setgroupent;
    606 	_pwcache_endgrent = a_endgrent;
    607 	_pwcache_getgrnam = a_getgrnam;
    608 	_pwcache_getgrgid = a_getgrgid;
    609 
    610 	return (0);
    611 }
    612 
    613 
    614 #ifdef TEST_PWCACHE
    615 
    616 struct passwd *
    617 test_getpwnam(const char *name)
    618 {
    619 	static struct passwd foo;
    620 
    621 	memset(&foo, 0, sizeof(foo));
    622 	if (strcmp(name, "toor") == 0) {
    623 		foo.pw_uid = 666;
    624 		return &foo;
    625 	}
    626 	return (getpwnam(name));
    627 }
    628 
    629 int
    630 main(int argc, char *argv[])
    631 {
    632 	uid_t	u;
    633 	int	r, i;
    634 
    635 	printf("pass 1 (default userdb)\n");
    636 	for (i = 1; i < argc; i++) {
    637 		printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
    638 		    i, pwopn, usrtb_fail, usrtb);
    639 		r = uid_from_user(argv[i], &u);
    640 		if (r == -1)
    641 			printf("  uid_from_user %s: failed\n", argv[i]);
    642 		else
    643 			printf("  uid_from_user %s: %d\n", argv[i], u);
    644 	}
    645 	printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
    646 		    pwopn, usrtb_fail, usrtb);
    647 
    648 	puts("");
    649 	printf("pass 2 (replacement userdb)\n");
    650 	printf("pwcache_userdb returned %d\n",
    651 	    pwcache_userdb(setpassent, test_getpwnam, getpwuid));
    652 	printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb);
    653 
    654 	for (i = 1; i < argc; i++) {
    655 		printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
    656 		    i, pwopn, usrtb_fail, usrtb);
    657 		u = -1;
    658 		r = uid_from_user(argv[i], &u);
    659 		if (r == -1)
    660 			printf("  uid_from_user %s: failed\n", argv[i]);
    661 		else
    662 			printf("  uid_from_user %s: %d\n", argv[i], u);
    663 	}
    664 	printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
    665 		    pwopn, usrtb_fail, usrtb);
    666 
    667 	puts("");
    668 	printf("pass 3 (null pointers)\n");
    669 	printf("pwcache_userdb returned %d\n",
    670 	    pwcache_userdb(NULL, NULL, NULL));
    671 
    672 	return (0);
    673 }
    674 #endif	/* TEST_PWCACHE */
    675 #endif	/* !HAVE_PWCACHE_USERDB */
    676