1 /* @(#)cache.c 8.1 (Berkeley) 5/31/93 */
2 /* $NetBSD: pwcache.c,v 1.31 2010/03/23 20:28:59 drochner Exp $ */
5 * Copyright (c) 1992 Keith Muller.
6 * Copyright (c) 1992, 1993
7 * The Regents of the University of California. All rights reserved.
9 * This code is derived from software contributed to Berkeley by
10 * Keith Muller of the University of California, San Diego.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * Copyright (c) 2002 The NetBSD Foundation, Inc.
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
63 #if HAVE_NBTOOL_CONFIG_H
64 #include "nbtool_config.h"
66 * XXX Undefine the renames of these functions so that we don't
67 * XXX rename the versions found in the host's <pwd.h> by mistake!
74 #include "namespace.h"
77 #include <sys/types.h>
78 #include <sys/param.h>
88 #include "un-namespace.h"
91 #if HAVE_NBTOOL_CONFIG_H
92 /* XXX Now, re-apply the renaming that we undid above. */
93 #define group_from_gid __nbcompat_group_from_gid
94 #define user_from_uid __nbcompat_user_from_uid
98 __weak_alias(user_from_uid
,_user_from_uid
)
99 __weak_alias(group_from_gid
,_group_from_gid
)
100 __weak_alias(pwcache_groupdb
,_pwcache_groupdb
)
103 #if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H
107 * routines that control user, group, uid and gid caches (for the archive
108 * member print routine).
110 * these routines cache BOTH hits and misses, a major performance improvement
114 * function pointers to various name lookup routines.
115 * these may be changed as necessary.
117 static int (*_pwcache_setgroupent
)(int) = setgroupent
;
118 static void (*_pwcache_endgrent
)(void) = endgrent
;
119 static struct group
* (*_pwcache_getgrnam
)(const char *) = getgrnam
;
120 static struct group
* (*_pwcache_getgrgid
)(gid_t
) = getgrgid
;
121 static int (*_pwcache_setpassent
)(int) = setpassent
;
122 static void (*_pwcache_endpwent
)(void) = endpwent
;
123 static struct passwd
* (*_pwcache_getpwnam
)(const char *) = getpwnam
;
124 static struct passwd
* (*_pwcache_getpwuid
)(uid_t
) = getpwuid
;
129 static int pwopn
; /* is password file open */
130 static int gropn
; /* is group file open */
131 static UIDC
**uidtb
; /* uid to name cache */
132 static GIDC
**gidtb
; /* gid to name cache */
133 static UIDC
**usrtb
; /* user name to uid cache */
134 static GIDC
**grptb
; /* group name to gid cache */
136 static int uidtb_fail
; /* uidtb_start() failed ? */
137 static int gidtb_fail
; /* gidtb_start() failed ? */
138 static int usrtb_fail
; /* usrtb_start() failed ? */
139 static int grptb_fail
; /* grptb_start() failed ? */
142 static u_int
st_hash(const char *, size_t, int);
143 static int uidtb_start(void);
144 static int gidtb_start(void);
145 static int usrtb_start(void);
146 static int grptb_start(void);
150 st_hash(const char *name
, size_t len
, int tabsz
)
154 _DIAGASSERT(name
!= NULL
);
158 key
= (key
<< 8) | (key
>> 24);
161 return (key
% tabsz
);
166 * creates an an empty uidtb
168 * 0 if ok, -1 otherwise
178 if ((uidtb
= (UIDC
**)calloc(UID_SZ
, sizeof(UIDC
*))) == NULL
) {
187 * creates an an empty gidtb
189 * 0 if ok, -1 otherwise
199 if ((gidtb
= (GIDC
**)calloc(GID_SZ
, sizeof(GIDC
*))) == NULL
) {
208 * creates an an empty usrtb
210 * 0 if ok, -1 otherwise
220 if ((usrtb
= (UIDC
**)calloc(UNM_SZ
, sizeof(UIDC
*))) == NULL
) {
229 * creates an an empty grptb
231 * 0 if ok, -1 otherwise
241 if ((grptb
= (GIDC
**)calloc(GNM_SZ
, sizeof(GIDC
*))) == NULL
) {
250 * caches the name (if any) for the uid. If noname clear, we always
251 * return the stored name (if valid or invalid match).
252 * We use a simple hash table.
254 * Pointer to stored name (or a empty string)
257 user_from_uid(uid_t uid
, int noname
)
262 if ((uidtb
== NULL
) && (uidtb_start() < 0))
266 * see if we have this uid cached
268 pptr
= uidtb
+ (uid
% UID_SZ
);
271 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && (ptr
->uid
== uid
)) {
273 * have an entry for this uid
275 if (!noname
|| (ptr
->valid
== VALID
))
281 * No entry for this uid, we will add it
284 if (_pwcache_setpassent
!= NULL
)
285 (*_pwcache_setpassent
)(1);
290 *pptr
= ptr
= (UIDC
*)malloc(sizeof(UIDC
));
292 if ((pw
= (*_pwcache_getpwuid
)(uid
)) == NULL
) {
294 * no match for this uid in the local password file
295 * a string that is the uid in numeric format
300 snprintf(ptr
->name
, UNMLEN
, "%lu", (long) uid
);
301 ptr
->valid
= INVALID
;
306 * there is an entry for this uid in the password file
309 return (pw
->pw_name
);
311 strlcpy(ptr
->name
, pw
->pw_name
, UNMLEN
);
319 * caches the name (if any) for the gid. If noname clear, we always
320 * return the stored name (if valid or invalid match).
321 * We use a simple hash table.
323 * Pointer to stored name (or a empty string)
326 group_from_gid(gid_t gid
, int noname
)
331 if ((gidtb
== NULL
) && (gidtb_start() < 0))
335 * see if we have this gid cached
337 pptr
= gidtb
+ (gid
% GID_SZ
);
340 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && (ptr
->gid
== gid
)) {
342 * have an entry for this gid
344 if (!noname
|| (ptr
->valid
== VALID
))
350 * No entry for this gid, we will add it
353 if (_pwcache_setgroupent
!= NULL
)
354 (*_pwcache_setgroupent
)(1);
359 *pptr
= ptr
= (GIDC
*)malloc(sizeof(GIDC
));
361 if ((gr
= (*_pwcache_getgrgid
)(gid
)) == NULL
) {
363 * no match for this gid in the local group file, put in
364 * a string that is the gid in numberic format
369 snprintf(ptr
->name
, GNMLEN
, "%lu", (long) gid
);
370 ptr
->valid
= INVALID
;
375 * there is an entry for this group in the group file
378 return (gr
->gr_name
);
380 strlcpy(ptr
->name
, gr
->gr_name
, GNMLEN
);
388 * caches the uid for a given user name. We use a simple hash table.
390 * the uid (if any) for a user name, or a -1 if no match can be found
393 uid_from_user(const char *name
, uid_t
*uid
)
400 * return -1 for mangled names
402 if (name
== NULL
|| ((namelen
= strlen(name
)) == 0))
404 if ((usrtb
== NULL
) && (usrtb_start() < 0))
408 * look up in hash table, if found and valid return the uid,
409 * if found and invalid, return a -1
411 pptr
= usrtb
+ st_hash(name
, namelen
, UNM_SZ
);
414 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && !strcmp(name
, ptr
->name
)) {
415 if (ptr
->valid
== INVALID
)
422 if (_pwcache_setpassent
!= NULL
)
423 (*_pwcache_setpassent
)(1);
428 *pptr
= ptr
= (UIDC
*)malloc(sizeof(UIDC
));
431 * no match, look it up, if no match store it as an invalid entry,
432 * or store the matching uid
435 if ((pw
= (*_pwcache_getpwnam
)(name
)) == NULL
)
440 strlcpy(ptr
->name
, name
, UNMLEN
);
441 if ((pw
= (*_pwcache_getpwnam
)(name
)) == NULL
) {
442 ptr
->valid
= INVALID
;
446 *uid
= ptr
->uid
= pw
->pw_uid
;
452 * caches the gid for a given group name. We use a simple hash table.
454 * the gid (if any) for a group name, or a -1 if no match can be found
457 gid_from_group(const char *name
, gid_t
*gid
)
464 * return -1 for mangled names
466 if (name
== NULL
|| ((namelen
= strlen(name
)) == 0))
468 if ((grptb
== NULL
) && (grptb_start() < 0))
472 * look up in hash table, if found and valid return the uid,
473 * if found and invalid, return a -1
475 pptr
= grptb
+ st_hash(name
, namelen
, GID_SZ
);
478 if ((ptr
!= NULL
) && (ptr
->valid
> 0) && !strcmp(name
, ptr
->name
)) {
479 if (ptr
->valid
== INVALID
)
486 if (_pwcache_setgroupent
!= NULL
)
487 (*_pwcache_setgroupent
)(1);
492 *pptr
= ptr
= (GIDC
*)malloc(sizeof(GIDC
));
495 * no match, look it up, if no match store it as an invalid entry,
496 * or store the matching gid
499 if ((gr
= (*_pwcache_getgrnam
)(name
)) == NULL
)
505 strlcpy(ptr
->name
, name
, GNMLEN
);
506 if ((gr
= (*_pwcache_getgrnam
)(name
)) == NULL
) {
507 ptr
->valid
= INVALID
;
511 *gid
= ptr
->gid
= gr
->gr_gid
;
515 #define FLUSHTB(arr, len, fail) \
518 for (i = 0; i < len; i++) \
519 if (arr[i] != NULL) \
524 } while (/* CONSTCOND */0);
528 int (*a_setpassent
)(int),
529 void (*a_endpwent
)(void),
530 struct passwd
* (*a_getpwnam
)(const char *),
531 struct passwd
* (*a_getpwuid
)(uid_t
))
535 /* a_setpassent and a_endpwent may be NULL */
536 if (a_getpwnam
== NULL
|| a_getpwuid
== NULL
)
539 if (_pwcache_endpwent
!= NULL
)
540 (*_pwcache_endpwent
)();
541 FLUSHTB(uidtb
, UID_SZ
, uidtb_fail
);
542 FLUSHTB(usrtb
, UNM_SZ
, usrtb_fail
);
544 _pwcache_setpassent
= a_setpassent
;
545 _pwcache_endpwent
= a_endpwent
;
546 _pwcache_getpwnam
= a_getpwnam
;
547 _pwcache_getpwuid
= a_getpwuid
;
554 int (*a_setgroupent
)(int),
555 void (*a_endgrent
)(void),
556 struct group
* (*a_getgrnam
)(const char *),
557 struct group
* (*a_getgrgid
)(gid_t
))
561 /* a_setgroupent and a_endgrent may be NULL */
562 if (a_getgrnam
== NULL
|| a_getgrgid
== NULL
)
565 if (_pwcache_endgrent
!= NULL
)
566 (*_pwcache_endgrent
)();
567 FLUSHTB(gidtb
, GID_SZ
, gidtb_fail
);
568 FLUSHTB(grptb
, GNM_SZ
, grptb_fail
);
570 _pwcache_setgroupent
= a_setgroupent
;
571 _pwcache_endgrent
= a_endgrent
;
572 _pwcache_getgrnam
= a_getgrnam
;
573 _pwcache_getgrgid
= a_getgrgid
;
582 test_getpwnam(const char *name
)
584 static struct passwd foo
;
586 memset(&foo
, 0, sizeof(foo
));
587 if (strcmp(name
, "toor") == 0) {
591 return (getpwnam(name
));
595 main(int argc
, char *argv
[])
600 printf("pass 1 (default userdb)\n");
601 for (i
= 1; i
< argc
; i
++) {
602 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
603 i
, pwopn
, usrtb_fail
, usrtb
);
604 r
= uid_from_user(argv
[i
], &u
);
606 printf(" uid_from_user %s: failed\n", argv
[i
]);
608 printf(" uid_from_user %s: %d\n", argv
[i
], u
);
610 printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n",
611 pwopn
, usrtb_fail
, usrtb
);
614 printf("pass 2 (replacement userdb)\n");
615 printf("pwcache_userdb returned %d\n",
616 pwcache_userdb(setpassent
, test_getpwnam
, getpwuid
));
617 printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn
, usrtb_fail
, usrtb
);
619 for (i
= 1; i
< argc
; i
++) {
620 printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n",
621 i
, pwopn
, usrtb_fail
, usrtb
);
623 r
= uid_from_user(argv
[i
], &u
);
625 printf(" uid_from_user %s: failed\n", argv
[i
]);
627 printf(" uid_from_user %s: %d\n", argv
[i
], u
);
629 printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n",
630 pwopn
, usrtb_fail
, usrtb
);
633 printf("pass 3 (null pointers)\n");
634 printf("pwcache_userdb returned %d\n",
635 pwcache_userdb(NULL
, NULL
, NULL
));
639 #endif /* TEST_PWCACHE */
640 #endif /* !HAVE_PWCACHE_USERDB */