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