diff --git a/contrib/libc-pwcache/pwcache.3 b/contrib/libc-pwcache/pwcache.3 new file mode 100644 index 000000000000..619c11743d69 --- /dev/null +++ b/contrib/libc-pwcache/pwcache.3 @@ -0,0 +1,223 @@ +.\" $NetBSD: pwcache.3,v 1.17 2008/05/02 18:11:04 martin Exp $ +.\" $FreeBSD$ +.\" +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" +.\" Copyright (c) 2002 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" +.\" @(#)pwcache.3 8.1 (Berkeley) 6/9/93 +.\" +.Dd October 19, 2012 +.Dt PWCACHE 3 +.Os +.Sh NAME +.Nm pwcache , +.Nm user_from_uid , +.Nm group_from_gid +.Nd cache password and group entries +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In pwd.h +.Ft const char * +.Fn user_from_uid "uid_t uid" "int nouser" +.Ft int +.Fn uid_from_user "const char *name" "uid_t *uid" +.Ft int +.Fn pwcache_userdb "int (*setpassent)(int)" "void (*endpwent)(void)" "struct passwd * (*getpwnam)(const char *)" "struct passwd * (*getpwuid)(uid_t)" +.In grp.h +.Ft const char * +.Fn group_from_gid "gid_t gid" "int nogroup" +.Ft int +.Fn gid_from_group "const char *name" "gid_t *gid" +.Ft int +.Fn pwcache_groupdb "int (*setgroupent)(int)" "void (*endgrent)(void)" "struct group * (*getgrnam)(const char *)" "struct group * (*getgrgid)(gid_t)" +.Sh DESCRIPTION +The +.Fn user_from_uid +function returns the user name associated with the argument +.Fa uid . +The user name is cached so that multiple calls with the same +.Fa uid +do not require additional calls to +.Xr getpwuid 3 . +If there is no user associated with the +.Fa uid , +a pointer is returned +to a string representation of the +.Fa uid , +unless the argument +.Fa nouser +is non-zero, in which case a +.Dv NULL +pointer is returned. +.Pp +The +.Fn group_from_gid +function returns the group name associated with the argument +.Fa gid . +The group name is cached so that multiple calls with the same +.Fa gid +do not require additional calls to +.Xr getgrgid 3 . +If there is no group associated with the +.Fa gid , +a pointer is returned +to a string representation of the +.Fa gid , +unless the argument +.Fa nogroup +is non-zero, in which case a +.Dv NULL +pointer is returned. +.Pp +The +.Fn uid_from_user +function returns the uid associated with the argument +.Fa name . +The uid is cached so that multiple calls with the same +.Fa name +do not require additional calls to +.Xr getpwnam 3 . +If there is no uid associated with the +.Fa name , +the +.Fn uid_from_user +function returns \-1; otherwise it stores the uid at the location pointed to by +.Fa uid +and returns 0. +.Pp +The +.Fn gid_from_group +function returns the gid associated with the argument +.Fa name . +The gid is cached so that multiple calls with the same +.Fa name +do not require additional calls to +.Xr getgrnam 3 . +If there is no gid associated with the +.Fa name , +the +.Fn gid_from_group +function returns \-1; otherwise it stores the gid at the location pointed to by +.Fa gid +and returns 0. +.Pp +The +.Fn pwcache_userdb +function changes the user database access routines which +.Fn user_from_uid +and +.Fn uid_from_user +call to search for users. +The caches are flushed and the existing +.Fn endpwent +method is called before switching to the new routines. +.Fa getpwnam +and +.Fa getpwuid +must be provided, and +.Fa setpassent +and +.Fa endpwent +may be +.Dv NULL +pointers. +.Pp +The +.Fn pwcache_groupdb +function changes the group database access routines which +.Fn group_from_gid +and +.Fn gid_from_group +call to search for groups. +The caches are flushed and the existing +.Fn endgrent +method is called before switching to the new routines. +.Fa getgrnam +and +.Fa getgrgid +must be provided, and +.Fa setgroupent +and +.Fa endgrent +may be +.Dv NULL +pointers. +.Sh SEE ALSO +.Xr getgrgid 3 , +.Xr getgrnam 3 , +.Xr getpwnam 3 , +.Xr getpwuid 3 +.Sh HISTORY +The +.Fn user_from_uid +and +.Fn group_from_gid +functions first appeared in +.Bx 4.4 . +.Pp +The +.Fn uid_from_user +and +.Fn gid_from_group +functions first appeared in +.Nx 1.4 . +.Pp +The +.Fn pwcache_userdb +and +.Fn pwcache_groupdb +functions first appeared in +.Nx 1.6 +and +.Fx 10.0 . diff --git a/contrib/libc-pwcache/pwcache.c b/contrib/libc-pwcache/pwcache.c new file mode 100644 index 000000000000..321e43900bd1 --- /dev/null +++ b/contrib/libc-pwcache/pwcache.c @@ -0,0 +1,646 @@ +/* $NetBSD: pwcache.c,v 1.31 2010/03/23 20:28:59 drochner Exp $ */ + +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +/* + * XXX Undefine the renames of these functions so that we don't + * XXX rename the versions found in the host's by mistake! + */ +#undef group_from_gid +#undef user_from_uid +#endif + +#include +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93"; +#else +__RCSID("$NetBSD: pwcache.c,v 1.31 2010/03/23 20:28:59 drochner Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ +__FBSDID("$FreeBSD$"); + +#include "namespace.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define _DIAGASSERT(x) assert((x)) + +#if HAVE_NBTOOL_CONFIG_H +/* XXX Now, re-apply the renaming that we undid above. */ +#define group_from_gid __nbcompat_group_from_gid +#define user_from_uid __nbcompat_user_from_uid +#endif + +#ifdef __weak_alias +__weak_alias(user_from_uid,_user_from_uid) +__weak_alias(group_from_gid,_group_from_gid) +__weak_alias(pwcache_groupdb,_pwcache_groupdb) +#endif + +#if !HAVE_PWCACHE_USERDB || HAVE_NBTOOL_CONFIG_H +#include "pwcache.h" + +/* + * routines that control user, group, uid and gid caches (for the archive + * member print routine). + * IMPORTANT: + * these routines cache BOTH hits and misses, a major performance improvement + */ + +/* + * function pointers to various name lookup routines. + * these may be changed as necessary. + */ +static int (*_pwcache_setgroupent)(int) = setgroupent; +static void (*_pwcache_endgrent)(void) = endgrent; +static struct group * (*_pwcache_getgrnam)(const char *) = getgrnam; +static struct group * (*_pwcache_getgrgid)(gid_t) = getgrgid; +static int (*_pwcache_setpassent)(int) = setpassent; +static void (*_pwcache_endpwent)(void) = endpwent; +static struct passwd * (*_pwcache_getpwnam)(const char *) = getpwnam; +static struct passwd * (*_pwcache_getpwuid)(uid_t) = getpwuid; + +/* + * internal state + */ +static int pwopn; /* is password file open */ +static int gropn; /* is group file open */ +static UIDC **uidtb; /* uid to name cache */ +static GIDC **gidtb; /* gid to name cache */ +static UIDC **usrtb; /* user name to uid cache */ +static GIDC **grptb; /* group name to gid cache */ + +static int uidtb_fail; /* uidtb_start() failed ? */ +static int gidtb_fail; /* gidtb_start() failed ? */ +static int usrtb_fail; /* usrtb_start() failed ? */ +static int grptb_fail; /* grptb_start() failed ? */ + + +static u_int st_hash(const char *, size_t, int); +static int uidtb_start(void); +static int gidtb_start(void); +static int usrtb_start(void); +static int grptb_start(void); + + +static u_int +st_hash(const char *name, size_t len, int tabsz) +{ + u_int key = 0; + + _DIAGASSERT(name != NULL); + + while (len--) { + key += *name++; + key = (key << 8) | (key >> 24); + } + + return (key % tabsz); +} + +/* + * uidtb_start + * creates an an empty uidtb + * Return: + * 0 if ok, -1 otherwise + */ +static int +uidtb_start(void) +{ + + if (uidtb != NULL) + return (0); + if (uidtb_fail) + return (-1); + if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) { + ++uidtb_fail; + return (-1); + } + return (0); +} + +/* + * gidtb_start + * creates an an empty gidtb + * Return: + * 0 if ok, -1 otherwise + */ +static int +gidtb_start(void) +{ + + if (gidtb != NULL) + return (0); + if (gidtb_fail) + return (-1); + if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) { + ++gidtb_fail; + return (-1); + } + return (0); +} + +/* + * usrtb_start + * creates an an empty usrtb + * Return: + * 0 if ok, -1 otherwise + */ +static int +usrtb_start(void) +{ + + if (usrtb != NULL) + return (0); + if (usrtb_fail) + return (-1); + if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { + ++usrtb_fail; + return (-1); + } + return (0); +} + +/* + * grptb_start + * creates an an empty grptb + * Return: + * 0 if ok, -1 otherwise + */ +static int +grptb_start(void) +{ + + if (grptb != NULL) + return (0); + if (grptb_fail) + return (-1); + if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { + ++grptb_fail; + return (-1); + } + return (0); +} + +/* + * user_from_uid() + * caches the name (if any) for the uid. If noname clear, we always + * return the stored name (if valid or invalid match). + * We use a simple hash table. + * Return + * Pointer to stored name (or a empty string) + */ +const char * +user_from_uid(uid_t uid, int noname) +{ + struct passwd *pw; + UIDC *ptr, **pptr; + + if ((uidtb == NULL) && (uidtb_start() < 0)) + return (NULL); + + /* + * see if we have this uid cached + */ + pptr = uidtb + (uid % UID_SZ); + ptr = *pptr; + + if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) { + /* + * have an entry for this uid + */ + if (!noname || (ptr->valid == VALID)) + return (ptr->name); + return (NULL); + } + + /* + * No entry for this uid, we will add it + */ + if (!pwopn) { + if (_pwcache_setpassent != NULL) + (*_pwcache_setpassent)(1); + ++pwopn; + } + + if (ptr == NULL) + *pptr = ptr = (UIDC *)malloc(sizeof(UIDC)); + + if ((pw = (*_pwcache_getpwuid)(uid)) == NULL) { + /* + * no match for this uid in the local password file + * a string that is the uid in numeric format + */ + if (ptr == NULL) + return (NULL); + ptr->uid = uid; + (void)snprintf(ptr->name, UNMLEN, "%lu", (long) uid); + ptr->valid = INVALID; + if (noname) + return (NULL); + } else { + /* + * there is an entry for this uid in the password file + */ + if (ptr == NULL) + return (pw->pw_name); + ptr->uid = uid; + (void)strlcpy(ptr->name, pw->pw_name, UNMLEN); + ptr->valid = VALID; + } + return (ptr->name); +} + +/* + * group_from_gid() + * caches the name (if any) for the gid. If noname clear, we always + * return the stored name (if valid or invalid match). + * We use a simple hash table. + * Return + * Pointer to stored name (or a empty string) + */ +const char * +group_from_gid(gid_t gid, int noname) +{ + struct group *gr; + GIDC *ptr, **pptr; + + if ((gidtb == NULL) && (gidtb_start() < 0)) + return (NULL); + + /* + * see if we have this gid cached + */ + pptr = gidtb + (gid % GID_SZ); + ptr = *pptr; + + if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) { + /* + * have an entry for this gid + */ + if (!noname || (ptr->valid == VALID)) + return (ptr->name); + return (NULL); + } + + /* + * No entry for this gid, we will add it + */ + if (!gropn) { + if (_pwcache_setgroupent != NULL) + (*_pwcache_setgroupent)(1); + ++gropn; + } + + if (ptr == NULL) + *pptr = ptr = (GIDC *)malloc(sizeof(GIDC)); + + if ((gr = (*_pwcache_getgrgid)(gid)) == NULL) { + /* + * no match for this gid in the local group file, put in + * a string that is the gid in numberic format + */ + if (ptr == NULL) + return (NULL); + ptr->gid = gid; + (void)snprintf(ptr->name, GNMLEN, "%lu", (long) gid); + ptr->valid = INVALID; + if (noname) + return (NULL); + } else { + /* + * there is an entry for this group in the group file + */ + if (ptr == NULL) + return (gr->gr_name); + ptr->gid = gid; + (void)strlcpy(ptr->name, gr->gr_name, GNMLEN); + ptr->valid = VALID; + } + return (ptr->name); +} + +/* + * uid_from_user() + * caches the uid for a given user name. We use a simple hash table. + * Return + * the uid (if any) for a user name, or a -1 if no match can be found + */ +int +uid_from_user(const char *name, uid_t *uid) +{ + struct passwd *pw; + UIDC *ptr, **pptr; + size_t namelen; + + /* + * return -1 for mangled names + */ + if (name == NULL || ((namelen = strlen(name)) == 0)) + return (-1); + if ((usrtb == NULL) && (usrtb_start() < 0)) + return (-1); + + /* + * look up in hash table, if found and valid return the uid, + * if found and invalid, return a -1 + */ + pptr = usrtb + st_hash(name, namelen, UNM_SZ); + ptr = *pptr; + + if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { + if (ptr->valid == INVALID) + return (-1); + *uid = ptr->uid; + return (0); + } + + if (!pwopn) { + if (_pwcache_setpassent != NULL) + (*_pwcache_setpassent)(1); + ++pwopn; + } + + if (ptr == NULL) + *pptr = ptr = (UIDC *)malloc(sizeof(UIDC)); + + /* + * no match, look it up, if no match store it as an invalid entry, + * or store the matching uid + */ + if (ptr == NULL) { + if ((pw = (*_pwcache_getpwnam)(name)) == NULL) + return (-1); + *uid = pw->pw_uid; + return (0); + } + (void)strlcpy(ptr->name, name, UNMLEN); + if ((pw = (*_pwcache_getpwnam)(name)) == NULL) { + ptr->valid = INVALID; + return (-1); + } + ptr->valid = VALID; + *uid = ptr->uid = pw->pw_uid; + return (0); +} + +/* + * gid_from_group() + * caches the gid for a given group name. We use a simple hash table. + * Return + * the gid (if any) for a group name, or a -1 if no match can be found + */ +int +gid_from_group(const char *name, gid_t *gid) +{ + struct group *gr; + GIDC *ptr, **pptr; + size_t namelen; + + /* + * return -1 for mangled names + */ + if (name == NULL || ((namelen = strlen(name)) == 0)) + return (-1); + if ((grptb == NULL) && (grptb_start() < 0)) + return (-1); + + /* + * look up in hash table, if found and valid return the uid, + * if found and invalid, return a -1 + */ + pptr = grptb + st_hash(name, namelen, GID_SZ); + ptr = *pptr; + + if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) { + if (ptr->valid == INVALID) + return (-1); + *gid = ptr->gid; + return (0); + } + + if (!gropn) { + if (_pwcache_setgroupent != NULL) + (*_pwcache_setgroupent)(1); + ++gropn; + } + + if (ptr == NULL) + *pptr = ptr = (GIDC *)malloc(sizeof(GIDC)); + + /* + * no match, look it up, if no match store it as an invalid entry, + * or store the matching gid + */ + if (ptr == NULL) { + if ((gr = (*_pwcache_getgrnam)(name)) == NULL) + return (-1); + *gid = gr->gr_gid; + return (0); + } + + (void)strlcpy(ptr->name, name, GNMLEN); + if ((gr = (*_pwcache_getgrnam)(name)) == NULL) { + ptr->valid = INVALID; + return (-1); + } + ptr->valid = VALID; + *gid = ptr->gid = gr->gr_gid; + return (0); +} + +#define FLUSHTB(arr, len, fail) \ + do { \ + if (arr != NULL) { \ + for (i = 0; i < len; i++) \ + if (arr[i] != NULL) \ + free(arr[i]); \ + arr = NULL; \ + } \ + fail = 0; \ + } while (/* CONSTCOND */0); + +int +pwcache_userdb( + int (*a_setpassent)(int), + void (*a_endpwent)(void), + struct passwd * (*a_getpwnam)(const char *), + struct passwd * (*a_getpwuid)(uid_t)) +{ + int i; + + /* a_setpassent and a_endpwent may be NULL */ + if (a_getpwnam == NULL || a_getpwuid == NULL) + return (-1); + + if (_pwcache_endpwent != NULL) + (*_pwcache_endpwent)(); + FLUSHTB(uidtb, UID_SZ, uidtb_fail); + FLUSHTB(usrtb, UNM_SZ, usrtb_fail); + pwopn = 0; + _pwcache_setpassent = a_setpassent; + _pwcache_endpwent = a_endpwent; + _pwcache_getpwnam = a_getpwnam; + _pwcache_getpwuid = a_getpwuid; + + return (0); +} + +int +pwcache_groupdb( + int (*a_setgroupent)(int), + void (*a_endgrent)(void), + struct group * (*a_getgrnam)(const char *), + struct group * (*a_getgrgid)(gid_t)) +{ + int i; + + /* a_setgroupent and a_endgrent may be NULL */ + if (a_getgrnam == NULL || a_getgrgid == NULL) + return (-1); + + if (_pwcache_endgrent != NULL) + (*_pwcache_endgrent)(); + FLUSHTB(gidtb, GID_SZ, gidtb_fail); + FLUSHTB(grptb, GNM_SZ, grptb_fail); + gropn = 0; + _pwcache_setgroupent = a_setgroupent; + _pwcache_endgrent = a_endgrent; + _pwcache_getgrnam = a_getgrnam; + _pwcache_getgrgid = a_getgrgid; + + return (0); +} + + +#ifdef TEST_PWCACHE + +struct passwd * +test_getpwnam(const char *name) +{ + static struct passwd foo; + + memset(&foo, 0, sizeof(foo)); + if (strcmp(name, "toor") == 0) { + foo.pw_uid = 666; + return &foo; + } + return (getpwnam(name)); +} + +int +main(int argc, char *argv[]) +{ + uid_t u; + int r, i; + + printf("pass 1 (default userdb)\n"); + for (i = 1; i < argc; i++) { + printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n", + i, pwopn, usrtb_fail, usrtb); + r = uid_from_user(argv[i], &u); + if (r == -1) + printf(" uid_from_user %s: failed\n", argv[i]); + else + printf(" uid_from_user %s: %d\n", argv[i], u); + } + printf("pass 1 finish: pwopn %d usrtb_fail %d usrtb %p\n", + pwopn, usrtb_fail, usrtb); + + puts(""); + printf("pass 2 (replacement userdb)\n"); + printf("pwcache_userdb returned %d\n", + pwcache_userdb(setpassent, test_getpwnam, getpwuid)); + printf("pwopn %d usrtb_fail %d usrtb %p\n", pwopn, usrtb_fail, usrtb); + + for (i = 1; i < argc; i++) { + printf("i: %d, pwopn %d usrtb_fail %d usrtb %p\n", + i, pwopn, usrtb_fail, usrtb); + u = -1; + r = uid_from_user(argv[i], &u); + if (r == -1) + printf(" uid_from_user %s: failed\n", argv[i]); + else + printf(" uid_from_user %s: %d\n", argv[i], u); + } + printf("pass 2 finish: pwopn %d usrtb_fail %d usrtb %p\n", + pwopn, usrtb_fail, usrtb); + + puts(""); + printf("pass 3 (null pointers)\n"); + printf("pwcache_userdb returned %d\n", + pwcache_userdb(NULL, NULL, NULL)); + + return (0); +} +#endif /* TEST_PWCACHE */ +#endif /* !HAVE_PWCACHE_USERDB */ diff --git a/contrib/libc-pwcache/pwcache.h b/contrib/libc-pwcache/pwcache.h new file mode 100644 index 000000000000..6e7de3464a45 --- /dev/null +++ b/contrib/libc-pwcache/pwcache.h @@ -0,0 +1,73 @@ +/* $NetBSD: pwcache.h,v 1.5 2003/11/10 08:51:51 wiz Exp $ */ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)cache.h 8.1 (Berkeley) 5/31/93 + */ + +/* + * Constants and data structures used to implement group and password file + * caches. Traditional passwd/group cache routines perform quite poorly with + * archives. The chances of hitting a valid lookup with an archive is quite a + * bit worse than with files already resident on the file system. These misses + * create a MAJOR performance cost. To address this problem, these routines + * cache both hits and misses. + * + * NOTE: name lengths must be as large as those stored in ANY PROTOCOL and + * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME + */ +#define UNMLEN 32 /* >= user name found in any protocol */ +#define GNMLEN 32 /* >= group name found in any protocol */ +#define UID_SZ 317 /* size of uid to user_name cache */ +#define UNM_SZ 317 /* size of user_name to uid cache */ +#define GID_SZ 251 /* size of gid to group_name cache */ +#define GNM_SZ 251 /* size of group_name to gid cache */ +#define VALID 1 /* entry and name are valid */ +#define INVALID 2 /* entry valid, name NOT valid */ + +/* + * Node structures used in the user, group, uid, and gid caches. + */ + +typedef struct uidc { + int valid; /* is this a valid or a miss entry */ + char name[UNMLEN]; /* uid name */ + uid_t uid; /* cached uid */ +} UIDC; + +typedef struct gidc { + int valid; /* is this a valid or a miss entry */ + char name[GNMLEN]; /* gid name */ + gid_t gid; /* cached gid */ +} GIDC; diff --git a/include/grp.h b/include/grp.h index 2b9f73f763cc..e7f65ecad636 100644 --- a/include/grp.h +++ b/include/grp.h @@ -69,6 +69,10 @@ struct group *getgrgid(gid_t); struct group *getgrnam(const char *); #if __BSD_VISIBLE const char *group_from_gid(gid_t, int); +int gid_from_group(const char *, gid_t *); +int pwcache_groupdb(int (*)(int), void (*)(void), + struct group * (*)(const char *), + struct group * (*)(gid_t)); #endif #if __BSD_VISIBLE || __XSI_VISIBLE /* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */ diff --git a/include/pwd.h b/include/pwd.h index 0a6dba1d7b90..2099e33891a4 100644 --- a/include/pwd.h +++ b/include/pwd.h @@ -165,6 +165,10 @@ int getpwuid_r(uid_t, struct passwd *, char *, size_t, int getpwent_r(struct passwd *, char *, size_t, struct passwd **); int setpassent(int); const char *user_from_uid(uid_t, int); +int uid_from_user(const char *, uid_t *); +int pwcache_userdb(int (*)(int), void (*)(void), + struct passwd * (*)(const char *), + struct passwd * (*)(uid_t)); #endif __END_DECLS diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 134ba34b51d5..2481f28abf1a 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -24,7 +24,7 @@ SRCS+= __getosreldate.c __xuname.c \ lockf.c lrand48.c mrand48.c nftw.c nice.c \ nlist.c nrand48.c opendir.c \ pause.c pmadvise.c popen.c posix_spawn.c \ - psignal.c pututxline.c pw_scan.c pwcache.c \ + psignal.c pututxline.c pw_scan.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ scandir.c seed48.c seekdir.c semctl.c \ setdomainname.c sethostname.c setjmperr.c setmode.c \ @@ -36,6 +36,9 @@ SRCS+= __getosreldate.c __xuname.c \ usleep.c utime.c utxdb.c valloc.c vis.c wait.c wait3.c waitpid.c \ wordexp.c +.PATH: ${.CURDIR}/../../contrib/libc-pwcache +SRCS+= pwcache.c pwcache.h + MISRCS+=modf.c CANCELPOINTS_SRCS=sem.c sem_new.c diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 50a1d88fc1c4..b4f88aed65c0 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -387,6 +387,10 @@ FBSD_1.3 { fdlopen; __FreeBSD_libc_enter_restricted_mode; getcontextx; + gid_from_group; + pwcache_userdb; + pwcache_groupdb; + uid_from_user; }; FBSDprivate_1.0 { diff --git a/lib/libc/gen/pwcache.3 b/lib/libc/gen/pwcache.3 deleted file mode 100644 index 39100822d8c0..000000000000 --- a/lib/libc/gen/pwcache.3 +++ /dev/null @@ -1,93 +0,0 @@ -.\" Copyright (c) 1989, 1991, 1993 -.\" The Regents of the University of California. All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 4. Neither the name of the University nor the names of its contributors -.\" may be used to endorse or promote products derived from this software -.\" without specific prior written permission. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -.\" SUCH DAMAGE. -.\" -.\" @(#)pwcache.3 8.1 (Berkeley) 6/9/93 -.\" $FreeBSD$ -.\" -.Dd March 22, 2002 -.Dt PWCACHE 3 -.Os -.Sh NAME -.Nm pwcache -.Nd cache password and group entries -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In pwd.h -.Ft const char * -.Fn user_from_uid "uid_t uid" "int nouser" -.In grp.h -.Ft const char * -.Fn group_from_gid "gid_t gid" "int nogroup" -.Sh DESCRIPTION -The -.Fn user_from_uid -function returns the user name associated with the argument -.Fa uid . -The user name is cached so that multiple calls with the same -.Fa uid -do not require additional calls to -.Xr getpwuid 3 . -If there is no user associated with the -.Fa uid , -a pointer is returned -to a string representation of the -.Fa uid , -unless the argument -.Fa nouser -is non-zero, in which case a -.Dv NULL -pointer is returned. -.Pp -The -.Fn group_from_gid -function returns the group name associated with the argument -.Fa gid . -The group name is cached so that multiple calls with the same -.Fa gid -do not require additional calls to -.Xr getgrgid 3 . -If there is no group associated with the -.Fa gid , -a pointer is returned -to a string representation of the -.Fa gid , -unless the argument -.Fa nogroup -is non-zero, in which case a -.Dv NULL -pointer is returned. -.Sh SEE ALSO -.Xr getgrgid 3 , -.Xr getpwuid 3 -.Sh HISTORY -The -.Fn user_from_uid -and -.Fn group_from_gid -functions first appeared in -.Bx 4.4 . diff --git a/lib/libc/gen/pwcache.c b/lib/libc/gen/pwcache.c deleted file mode 100644 index a8a73f16cd85..000000000000 --- a/lib/libc/gen/pwcache.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)pwcache.c 8.1 (Berkeley) 6/4/93"; -#endif /* LIBC_SCCS and not lint */ -#include -__FBSDID("$FreeBSD$"); - -#include -#include - -#include -#include -#include -#include - -#define NCACHE 64 /* power of 2 */ -#define MASK (NCACHE - 1) /* bits to store with */ - -const char * -user_from_uid(uid_t uid, int nouser) -{ - static struct ncache { - uid_t uid; - int found; - char name[MAXLOGNAME]; - } c_uid[NCACHE]; - static int pwopen; - struct passwd *pw; - struct ncache *cp; - - cp = c_uid + (uid & MASK); - if (cp->uid != uid || !*cp->name) { - if (pwopen == 0) { - setpassent(1); - pwopen = 1; - } - pw = getpwuid(uid); - cp->uid = uid; - if (pw != NULL) { - cp->found = 1; - (void)strncpy(cp->name, pw->pw_name, MAXLOGNAME - 1); - cp->name[MAXLOGNAME - 1] = '\0'; - } else { - cp->found = 0; - (void)snprintf(cp->name, MAXLOGNAME - 1, "%u", uid); - if (nouser) - return (NULL); - } - } - return ((nouser && !cp->found) ? NULL : cp->name); -} - -const char * -group_from_gid(gid_t gid, int nogroup) -{ - static struct ncache { - gid_t gid; - int found; - char name[MAXLOGNAME]; - } c_gid[NCACHE]; - static int gropen; - struct group *gr; - struct ncache *cp; - - cp = c_gid + (gid & MASK); - if (cp->gid != gid || !*cp->name) { - if (gropen == 0) { - setgroupent(1); - gropen = 1; - } - gr = getgrgid(gid); - cp->gid = gid; - if (gr != NULL) { - cp->found = 1; - (void)strncpy(cp->name, gr->gr_name, MAXLOGNAME - 1); - cp->name[MAXLOGNAME - 1] = '\0'; - } else { - cp->found = 0; - (void)snprintf(cp->name, MAXLOGNAME - 1, "%u", gid); - if (nogroup) - return (NULL); - } - } - return ((nogroup && !cp->found) ? NULL : cp->name); -}