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