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.
49 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
50 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
59 * POSSIBILITY OF SUCH DAMAGE.
62 #if HAVE_NBTOOL_CONFIG_H
63 #include "nbtool_config.h"
65 * XXX Undefine the renames of these functions so that we don't
66 * XXX rename the versions found in the host's <pwd.h> by mistake!
72 #include <sys/cdefs.h>
73 #if defined(LIBC_SCCS) && !defined(lint)
75 static char sccsid
[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
77 __RCSID("$NetBSD: pwcache.c,v 1.29 2004/06/20 22:20:14 jmc Exp $");
79 #endif /* LIBC_SCCS and not lint */
81 #include "namespace.h"
83 #include <sys/types.h>
84 #include <sys/param.h>
94 #if HAVE_NBTOOL_CONFIG_H
95 /* XXX Now, re-apply the renaming that we undid above. */
96 #define group_from_gid __nbcompat_group_from_gid
97 #define user_from_uid __nbcompat_user_from_uid
101 __weak_alias(user_from_uid
,_user_from_uid
)
102 __weak_alias(group_from_gid
,_group_from_gid
)
103 __weak_alias(pwcache_userdb
,_pwcache_userdb
)
104 __weak_alias(pwcache_groupdb
,_pwcache_groupdb
)
107 #if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H
111 * routines that control user, group, uid and gid caches (for the archive
112 * member print routine).
114 * these routines cache BOTH hits and misses, a major performance improvement
118 * function pointers to various name lookup routines.
119 * these may be changed as necessary.
121 static int (*_pwcache_setgroupent
)(int) = setgroupent
;
122 static void (*_pwcache_endgrent
)(void) = endgrent
;
123 static struct group
* (*_pwcache_getgrnam
)(const char *) = getgrnam
;
124 static struct group
* (*_pwcache_getgrgid
)(gid_t
) = getgrgid
;
125 static int (*_pwcache_setpassent
)(int) = setpassent
;
126 static void (*_pwcache_endpwent
)(void) = endpwent
;
127 static struct passwd
* (*_pwcache_getpwnam
)(const char *) = getpwnam
;
128 static struct passwd
* (*_pwcache_getpwuid
)(uid_t
) = getpwuid
;
133 static int pwopn
; /* is password file open */
134 static int gropn
; /* is group file open */
135 static UIDC
**uidtb
; /* uid to name cache */
136 static GIDC
**gidtb
; /* gid to name cache */
137 static UIDC
**usrtb
; /* user name to uid cache */
138 static GIDC
**grptb
; /* group name to gid cache */
140 static int uidtb_fail
; /* uidtb_start() failed ? */
141 static int gidtb_fail
; /* gidtb_start() failed ? */
142 static int usrtb_fail
; /* usrtb_start() failed ? */
143 static int grptb_fail
; /* grptb_start() failed ? */
146 static u_int
st_hash(const char *, size_t, int);
147 static int uidtb_start(void);
148 static int gidtb_start(void);
149 static int usrtb_start(void);
150 static int grptb_start(void);
154 st_hash(const char *name
, size_t len
, int tabsz
)
158 _DIAGASSERT(name
!= NULL
);
162 key
= (key
<< 8) | (key
>> 24);
165 return (key
% tabsz
);
170 * creates an an empty uidtb
172 * 0 if ok, -1 otherwise
182 if ((uidtb
= (UIDC
**)calloc(UID_SZ
, sizeof(UIDC
*))) == NULL
) {
191 * creates an an empty gidtb
193 * 0 if ok, -1 otherwise
203 if ((gidtb
= (GIDC
**)calloc(GID_SZ
, sizeof(GIDC
*))) == NULL
) {
212 * creates an an empty usrtb
214 * 0 if ok, -1 otherwise
224 if ((usrtb
= (UIDC
**)calloc(UNM_SZ
, sizeof(UIDC
*))) == NULL
) {
233 * creates an an empty grptb
235 * 0 if ok, -1 otherwise
245 if ((grptb
= (GIDC
**)calloc(GNM_SZ
, sizeof(GIDC
*))) == NULL
) {
254 * caches the name (if any) for the uid. If noname clear, we always
255 * return the stored name (if valid or invalid match).
256 * We use a simple hash table.
258 * Pointer to stored name (or a empty string)
261 user_from_uid(uid_t uid
, int noname
)
266 if ((uidtb
== NULL
) && (uidtb_start() < 0))
270 * see if we have this uid cached
272 pptr
= uidtb
+ (uid
% UID_SZ
);
275 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && (ptr
->uid
== uid
)) {
277 * have an entry for this uid
279 if (!noname
|| (ptr
->valid
== VALID
))
285 * No entry for this uid, we will add it
288 if (_pwcache_setpassent
!= NULL
)
289 (*_pwcache_setpassent
)(1);
294 *pptr
= ptr
= (UIDC
*)malloc(sizeof(UIDC
));
296 if ((pw
= (*_pwcache_getpwuid
)(uid
)) == NULL
) {
298 * no match for this uid in the local password file
299 * a string that is the uid in numeric format
304 (void)snprintf(ptr
->name
, UNMLEN
, "%lu", (long) uid
);
305 ptr
->valid
= INVALID
;
310 * there is an entry for this uid in the password file
313 return (pw
->pw_name
);
315 (void)strlcpy(ptr
->name
, pw
->pw_name
, UNMLEN
);
323 * caches the name (if any) for the gid. If noname clear, we always
324 * return the stored name (if valid or invalid match).
325 * We use a simple hash table.
327 * Pointer to stored name (or a empty string)
330 group_from_gid(gid_t gid
, int noname
)
335 if ((gidtb
== NULL
) && (gidtb_start() < 0))
339 * see if we have this gid cached
341 pptr
= gidtb
+ (gid
% GID_SZ
);
344 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && (ptr
->gid
== gid
)) {
346 * have an entry for this gid
348 if (!noname
|| (ptr
->valid
== VALID
))
354 * No entry for this gid, we will add it
357 if (_pwcache_setgroupent
!= NULL
)
358 (*_pwcache_setgroupent
)(1);
363 *pptr
= ptr
= (GIDC
*)malloc(sizeof(GIDC
));
365 if ((gr
= (*_pwcache_getgrgid
)(gid
)) == NULL
) {
367 * no match for this gid in the local group file, put in
368 * a string that is the gid in numberic format
373 (void)snprintf(ptr
->name
, GNMLEN
, "%lu", (long) gid
);
374 ptr
->valid
= INVALID
;
379 * there is an entry for this group in the group file
382 return (gr
->gr_name
);
384 (void)strlcpy(ptr
->name
, gr
->gr_name
, GNMLEN
);
392 * caches the uid for a given user name. We use a simple hash table.
394 * the uid (if any) for a user name, or a -1 if no match can be found
397 uid_from_user(const char *name
, uid_t
*uid
)
404 * return -1 for mangled names
406 if (name
== NULL
|| ((namelen
= strlen(name
)) == 0))
408 if ((usrtb
== NULL
) && (usrtb_start() < 0))
412 * look up in hash table, if found and valid return the uid,
413 * if found and invalid, return a -1
415 pptr
= usrtb
+ st_hash(name
, namelen
, UNM_SZ
);
418 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && !strcmp(name
, ptr
->name
)) {
419 if (ptr
->valid
== INVALID
)
426 if (_pwcache_setpassent
!= NULL
)
427 (*_pwcache_setpassent
)(1);
432 *pptr
= ptr
= (UIDC
*)malloc(sizeof(UIDC
));
435 * no match, look it up, if no match store it as an invalid entry,
436 * or store the matching uid
439 if ((pw
= (*_pwcache_getpwnam
)(name
)) == NULL
)
444 (void)strlcpy(ptr
->name
, name
, UNMLEN
);
445 if ((pw
= (*_pwcache_getpwnam
)(name
)) == NULL
) {
446 ptr
->valid
= INVALID
;
450 *uid
= ptr
->uid
= pw
->pw_uid
;
456 * caches the gid for a given group name. We use a simple hash table.
458 * the gid (if any) for a group name, or a -1 if no match can be found
461 gid_from_group(const char *name
, gid_t
*gid
)
468 * return -1 for mangled names
470 if (name
== NULL
|| ((namelen
= strlen(name
)) == 0))
472 if ((grptb
== NULL
) && (grptb_start() < 0))
476 * look up in hash table, if found and valid return the uid,
477 * if found and invalid, return a -1
479 pptr
= grptb
+ st_hash(name
, namelen
, GID_SZ
);
482 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && !strcmp(name
, ptr
->name
)) {
483 if (ptr
->valid
== INVALID
)
490 if (_pwcache_setgroupent
!= NULL
)
491 (*_pwcache_setgroupent
)(1);
496 *pptr
= ptr
= (GIDC
*)malloc(sizeof(GIDC
));
499 * no match, look it up, if no match store it as an invalid entry,
500 * or store the matching gid
503 if ((gr
= (*_pwcache_getgrnam
)(name
)) == NULL
)
509 (void)strlcpy(ptr
->name
, name
, GNMLEN
);
510 if ((gr
= (*_pwcache_getgrnam
)(name
)) == NULL
) {
511 ptr
->valid
= INVALID
;
515 *gid
= ptr
->gid
= gr
->gr_gid
;
519 #define FLUSHTB(arr, len, fail) \
522 for (i = 0; i < len; i++) \
523 if (arr[i] != NULL) \
528 } while (/* CONSTCOND */0);
532 int (*a_setpassent
)(int),
533 void (*a_endpwent
)(void),
534 struct passwd
* (*a_getpwnam
)(const char *),
535 struct passwd
* (*a_getpwuid
)(uid_t
))
539 /* a_setpassent and a_endpwent may be NULL */
540 if (a_getpwnam
== NULL
|| a_getpwuid
== NULL
)
543 if (_pwcache_endpwent
!= NULL
)
544 (*_pwcache_endpwent
)();
545 FLUSHTB(uidtb
, UID_SZ
, uidtb_fail
);
546 FLUSHTB(usrtb
, UNM_SZ
, usrtb_fail
);
548 _pwcache_setpassent
= a_setpassent
;
549 _pwcache_endpwent
= a_endpwent
;
550 _pwcache_getpwnam
= a_getpwnam
;
551 _pwcache_getpwuid
= a_getpwuid
;
558 int (*a_setgroupent
)(int),
559 void (*a_endgrent
)(void),
560 struct group
* (*a_getgrnam
)(const char *),
561 struct group
* (*a_getgrgid
)(gid_t
))
565 /* a_setgroupent and a_endgrent may be NULL */
566 if (a_getgrnam
== NULL
|| a_getgrgid
== NULL
)
569 if (_pwcache_endgrent
!= NULL
)
570 (*_pwcache_endgrent
)();
571 FLUSHTB(gidtb
, GID_SZ
, gidtb_fail
);
572 FLUSHTB(grptb
, GNM_SZ
, grptb_fail
);
574 _pwcache_setgroupent
= a_setgroupent
;
575 _pwcache_endgrent
= a_endgrent
;
576 _pwcache_getgrnam
= a_getgrnam
;
577 _pwcache_getgrgid
= a_getgrgid
;
586 test_getpwnam(const char *name
)
588 static struct passwd foo
;
590 memset(&foo
, 0, sizeof(foo
));
591 if (strcmp(name
, "toor") == 0) {
595 return (getpwnam(name
));
599 main(int argc
, char *argv
[])
604 printf("pass 1 (default userdb)\n");
605 for (i
= 1; i
< argc
; i
++) {
606 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
607 i
, pwopn
, usrtb_fail
, usrtb
);
608 r
= uid_from_user(argv
[i
], &u
);
610 printf(" uid_from_user %s: failed\n", argv
[i
]);
612 printf(" uid_from_user %s: %d\n", argv
[i
], u
);
614 printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
615 pwopn
, usrtb_fail
, usrtb
);
618 printf("pass 2 (replacement userdb)\n");
619 printf("pwcache_userdb returned %d\n",
620 pwcache_userdb(setpassent
, test_getpwnam
, getpwuid
));
621 printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn
, usrtb_fail
, usrtb
);
623 for (i
= 1; i
< argc
; i
++) {
624 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
625 i
, pwopn
, usrtb_fail
, usrtb
);
627 r
= uid_from_user(argv
[i
], &u
);
629 printf(" uid_from_user %s: failed\n", argv
[i
]);
631 printf(" uid_from_user %s: %d\n", argv
[i
], u
);
633 printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
634 pwopn
, usrtb_fail
, usrtb
);
637 printf("pass 3 (null pointers)\n");
638 printf("pwcache_userdb returned %d\n",
639 pwcache_userdb(NULL
, NULL
, NULL
));
643 #endif /* TEST_PWCACHE */
644 #endif /* !HAVE_PWCACHE_USERDB */