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