1 /* $NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $ */
4 * Copyright (c) 1992 Keith Muller.
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Keith Muller of the University of California, San Diego.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * Copyright (c) 2002 The NetBSD Foundation, Inc.
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
43 * 1. Redistributions of source code must retain the above copyright
44 * notice, this list of conditions and the following disclaimer.
45 * 2. Redistributions in binary form must reproduce the above copyright
46 * notice, this list of conditions and the following disclaimer in the
47 * documentation and/or other materials provided with the distribution.
48 * 3. All advertising materials mentioning features or use of this software
49 * must display the following acknowledgement:
50 * This product includes software developed by the NetBSD
51 * Foundation, Inc. and its contributors.
52 * 4. Neither the name of The NetBSD Foundation nor the names of its
53 * contributors may be used to endorse or promote products derived
54 * from this software without specific prior written permission.
56 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
57 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
58 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
60 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
61 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
62 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
64 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
65 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
66 * POSSIBILITY OF SUCH DAMAGE.
69 #include <sys/cdefs.h>
70 __FBSDID("$FreeBSD$");
72 #include <sys/types.h>
73 #include <sys/param.h>
84 __weak_alias(user_from_uid,_user_from_uid)
85 __weak_alias(group_from_gid,_group_from_gid)
86 __weak_alias(pwcache_userdb,_pwcache_userdb)
87 __weak_alias(pwcache_groupdb,_pwcache_groupdb)
93 * routines that control user, group, uid and gid caches (for the archive
94 * member print routine).
96 * these routines cache BOTH hits and misses, a major performance improvement
100 * function pointers to various name lookup routines.
101 * these may be changed as necessary.
103 static int (*_pwcache_setgroupent)(int) = setgroupent;
104 static void (*_pwcache_endgrent)(void) = endgrent;
105 static struct group * (*_pwcache_getgrnam)(const char *) = getgrnam;
106 static struct group * (*_pwcache_getgrgid)(gid_t) = getgrgid;
107 static int (*_pwcache_setpassent)(int) = setpassent;
108 static void (*_pwcache_endpwent)(void) = endpwent;
109 static struct passwd * (*_pwcache_getpwnam)(const char *) = getpwnam;
110 static struct passwd * (*_pwcache_getpwuid)(uid_t) = getpwuid;
115 static int pwopn; /* is password file open */
116 static int gropn; /* is group file open */
117 static UIDC **uidtb; /* uid to name cache */
118 static GIDC **gidtb; /* gid to name cache */
119 static UIDC **usrtb; /* user name to uid cache */
120 static GIDC **grptb; /* group name to gid cache */
122 static int uidtb_fail; /* uidtb_start() failed ? */
123 static int gidtb_fail; /* gidtb_start() failed ? */
124 static int usrtb_fail; /* usrtb_start() failed ? */
125 static int grptb_fail; /* grptb_start() failed ? */
128 static u_int st_hash(const char *, size_t, int);
129 static int uidtb_start(void);
130 static int gidtb_start(void);
131 static int usrtb_start(void);
132 static int grptb_start(void);
136 st_hash(const char *name, size_t len, int tabsz)
142 key = (key << 8) | (key >> 24);
145 return (key % tabsz);
150 * creates an an empty uidtb
152 * 0 if ok, -1 otherwise
162 if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
171 * creates an an empty gidtb
173 * 0 if ok, -1 otherwise
183 if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
192 * creates an an empty usrtb
194 * 0 if ok, -1 otherwise
204 if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
213 * creates an an empty grptb
215 * 0 if ok, -1 otherwise
225 if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
234 * caches the name (if any) for the uid. If noname clear, we always
235 * return the stored name (if valid or invalid match).
236 * We use a simple hash table.
238 * Pointer to stored name (or a empty string)
241 user_from_uid(uid_t uid, int noname)
246 if ((uidtb == NULL) && (uidtb_start() < 0))
250 * see if we have this uid cached
252 pptr = uidtb + (uid % UID_SZ);
255 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
257 * have an entry for this uid
259 if (!noname || (ptr->valid == VALID))
265 * No entry for this uid, we will add it
268 if (_pwcache_setpassent != NULL)
269 (*_pwcache_setpassent)(1);
274 *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
276 if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) {
278 * no match for this uid in the local password file
279 * a string that is the uid in numeric format
284 (void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid);
285 ptr->valid = INVALID;
290 * there is an entry for this uid in the password file
293 return (pw->pw_name);
295 (void)strlcpy(ptr->name, pw->pw_name, UNMLEN);
303 * caches the name (if any) for the gid. If noname clear, we always
304 * return the stored name (if valid or invalid match).
305 * We use a simple hash table.
307 * Pointer to stored name (or a empty string)
310 group_from_gid(gid_t gid, int noname)
315 if ((gidtb == NULL) && (gidtb_start() < 0))
319 * see if we have this gid cached
321 pptr = gidtb + (gid % GID_SZ);
324 if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
326 * have an entry for this gid
328 if (!noname || (ptr->valid == VALID))
334 * No entry for this gid, we will add it
337 if (_pwcache_setgroupent != NULL)
338 (*_pwcache_setgroupent)(1);
343 *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
345 if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) {
347 * no match for this gid in the local group file, put in
348 * a string that is the gid in numberic format
353 (void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid);
354 ptr->valid = INVALID;
359 * there is an entry for this group in the group file
362 return (gr->gr_name);
364 (void)strlcpy(ptr->name, gr->gr_name, GNMLEN);
372 * caches the uid for a given user name. We use a simple hash table.
374 * the uid (if any) for a user name, or a -1 if no match can be found
377 uid_from_user(const char *name, uid_t *uid)
384 * return -1 for mangled names
386 if (name == NULL || ((namelen = strlen(name)) == 0))
388 if ((usrtb == NULL) && (usrtb_start() < 0))
392 * look up in hash table, if found and valid return the uid,
393 * if found and invalid, return a -1
395 pptr = usrtb + st_hash(name, namelen, UNM_SZ);
398 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
399 if (ptr->valid == INVALID)
406 if (_pwcache_setpassent != NULL)
407 (*_pwcache_setpassent)(1);
412 *pptr = ptr = (UIDC *)malloc(sizeof(UIDC));
415 * no match, look it up, if no match store it as an invalid entry,
416 * or store the matching uid
419 if ((pw = (*_pwcache_getpwnam)(name)) == NULL)
424 (void)strlcpy(ptr->name, name, UNMLEN);
425 if ((pw = (*_pwcache_getpwnam)(name)) == NULL) {
426 ptr->valid = INVALID;
430 *uid = ptr->uid = pw->pw_uid;
436 * caches the gid for a given group name. We use a simple hash table.
438 * the gid (if any) for a group name, or a -1 if no match can be found
441 gid_from_group(const char *name, gid_t *gid)
448 * return -1 for mangled names
450 if (name == NULL || ((namelen = strlen(name)) == 0))
452 if ((grptb == NULL) && (grptb_start() < 0))
456 * look up in hash table, if found and valid return the uid,
457 * if found and invalid, return a -1
459 pptr = grptb + st_hash(name, namelen, GID_SZ);
462 if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
463 if (ptr->valid == INVALID)
470 if (_pwcache_setgroupent != NULL)
471 (*_pwcache_setgroupent)(1);
476 *pptr = ptr = (GIDC *)malloc(sizeof(GIDC));
479 * no match, look it up, if no match store it as an invalid entry,
480 * or store the matching gid
483 if ((gr = (*_pwcache_getgrnam)(name)) == NULL)
489 (void)strlcpy(ptr->name, name, GNMLEN);
490 if ((gr = (*_pwcache_getgrnam)(name)) == NULL) {
491 ptr->valid = INVALID;
495 *gid = ptr->gid = gr->gr_gid;
499 #define FLUSHTB(arr, len, fail) \
502 for (i = 0; i < len; i++) \
503 if (arr[i] != NULL) \
508 } while (/* CONSTCOND */0);
512 int (*a_setpassent)(int),
513 void (*a_endpwent)(void),
514 struct passwd * (*a_getpwnam)(const char *),
515 struct passwd * (*a_getpwuid)(uid_t))
519 /* a_setpassent and a_endpwent may be NULL */
520 if (a_getpwnam == NULL || a_getpwuid == NULL)
523 if (_pwcache_endpwent != NULL)
524 (*_pwcache_endpwent)();
525 FLUSHTB(uidtb, UID_SZ, uidtb_fail);
526 FLUSHTB(usrtb, UNM_SZ, usrtb_fail);
528 _pwcache_setpassent = a_setpassent;
529 _pwcache_endpwent = a_endpwent;
530 _pwcache_getpwnam = a_getpwnam;
531 _pwcache_getpwuid = a_getpwuid;
538 int (*a_setgroupent)(int),
539 void (*a_endgrent)(void),
540 struct group * (*a_getgrnam)(const char *),
541 struct group * (*a_getgrgid)(gid_t))
545 /* a_setgroupent and a_endgrent may be NULL */
546 if (a_getgrnam == NULL || a_getgrgid == NULL)
549 if (_pwcache_endgrent != NULL)
550 (*_pwcache_endgrent)();
551 FLUSHTB(gidtb, GID_SZ, gidtb_fail);
552 FLUSHTB(grptb, GNM_SZ, grptb_fail);
554 _pwcache_setgroupent = a_setgroupent;
555 _pwcache_endgrent = a_endgrent;
556 _pwcache_getgrnam = a_getgrnam;
557 _pwcache_getgrgid = a_getgrgid;
566 test_getpwnam(const char *name)
568 static struct passwd foo;
570 memset(&foo, 0, sizeof(foo));
571 if (strcmp(name, "toor") == 0) {
575 return (getpwnam(name));
579 main(int argc, char *argv[])
584 printf("pass 1 (default userdb)\n");
585 for (i = 1; i < argc; i++) {
586 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
587 i, pwopn, usrtb_fail, usrtb);
588 r = uid_from_user(argv[i], &u);
590 printf(" uid_from_user %s: failed\n", argv[i]);
592 printf(" uid_from_user %s: %d\n", argv[i], u);
594 printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
595 pwopn, usrtb_fail, usrtb);
598 printf("pass 2 (replacement userdb)\n");
599 printf("pwcache_userdb returned %d\n",
600 pwcache_userdb(setpassent, test_getpwnam, getpwuid));
601 printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb);
603 for (i = 1; i < argc; i++) {
604 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
605 i, pwopn, usrtb_fail, usrtb);
607 r = uid_from_user(argv[i], &u);
609 printf(" uid_from_user %s: failed\n", argv[i]);
611 printf(" uid_from_user %s: %d\n", argv[i], u);
613 printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
614 pwopn, usrtb_fail, usrtb);
617 printf("pass 3 (null pointers)\n");
618 printf("pwcache_userdb returned %d\n",
619 pwcache_userdb(NULL, NULL, NULL));
623 #endif /* TEST_PWCACHE */