diff options
author | Guillem Jover <guillem@hadrons.org> | 2021-02-06 23:43:12 +0100 |
---|---|---|
committer | Guillem Jover <guillem@hadrons.org> | 2021-02-07 01:28:27 +0100 |
commit | 37a9b56c05339301510213c41fc507ea31cc2464 (patch) | |
tree | cbb067e81f4d3d1b6af63387ebbed6043746838e | |
parent | 45dd5229ea5f3c62877f5f66f80ab8e52d40a281 (diff) |
Import pwcache module from OpenBSD
-rw-r--r-- | COPYING | 3 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | include/Makefile.am | 2 | ||||
-rw-r--r-- | include/bsd/grp.h | 51 | ||||
-rw-r--r-- | include/bsd/pwd.h | 51 | ||||
-rw-r--r-- | man/Makefile.am | 5 | ||||
-rw-r--r-- | man/gid_from_group.3bsd | 1 | ||||
-rw-r--r-- | man/group_from_gid.3bsd | 1 | ||||
-rw-r--r-- | man/pwcache.3bsd | 143 | ||||
-rw-r--r-- | man/uid_from_user.3bsd | 1 | ||||
-rw-r--r-- | man/user_from_uid.3bsd | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/libbsd.map | 5 | ||||
-rw-r--r-- | src/pwcache.c | 437 | ||||
-rw-r--r-- | test/.gitignore | 1 | ||||
-rw-r--r-- | test/Makefile.am | 1 | ||||
-rw-r--r-- | test/overlay.c | 3 | ||||
-rw-r--r-- | test/pwcache.c | 49 |
18 files changed, 757 insertions, 1 deletions
@@ -105,6 +105,7 @@ Files: man/getbsize.3bsd man/heapsort.3bsd man/nlist.3bsd + man/pwcache.3bsd man/queue.3bsd man/radixsort.3bsd man/reallocarray.3bsd @@ -121,6 +122,7 @@ Files: src/heapsort.c src/merge.c src/nlist.c + src/pwcache.c src/radixsort.c src/setmode.c src/strmode.c @@ -131,6 +133,7 @@ Files: Copyright: Copyright © 1980, 1982, 1986, 1989-1994 The Regents of the University of California. All rights reserved. + Copyright © 1992 Keith Muller. Copyright © 2001 Mike Barcroft <mike@FreeBSD.org> . Some code is derived from software contributed to Berkeley by diff --git a/configure.ac b/configure.ac index e8d4c5f..cf064bb 100644 --- a/configure.ac +++ b/configure.ac @@ -87,7 +87,7 @@ AS_CASE([$host_os], AM_CONDITIONAL([OS_WINDOWS], [test "x$is_windows" = "xyes"]) # Checks for header files. -AC_CHECK_HEADERS([sys/ndir.h sys/dir.h ndir.h dirent.h grp.h]) +AC_CHECK_HEADERS([sys/ndir.h sys/dir.h ndir.h dirent.h pwd.h grp.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE diff --git a/include/Makefile.am b/include/Makefile.am index 949ea80..e6f66bd 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -14,10 +14,12 @@ nobase_include_HEADERS = \ bsd/bsd.h \ bsd/err.h \ bsd/getopt.h \ + bsd/grp.h \ bsd/inttypes.h \ bsd/libutil.h \ bsd/md5.h \ bsd/nlist.h \ + bsd/pwd.h \ bsd/readpassphrase.h \ bsd/stdio.h \ bsd/stdlib.h \ diff --git a/include/bsd/grp.h b/include/bsd/grp.h new file mode 100644 index 0000000..b2705e5 --- /dev/null +++ b/include/bsd/grp.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2021 Guillem Jover <guillem@hadrons.org> + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#ifdef LIBBSD_OVERLAY +#include <sys/cdefs.h> +#if __has_include_next(<grp.h>) +#include_next <grp.h> +#endif +#else +#include <bsd/sys/cdefs.h> +#if __has_include(<grp.h>) +#include <grp.h> +#endif +#endif + +#ifndef LIBBSD_GRP_H +#define LIBBSD_GRP_H + +#define _GR_BUF_LEN (1024 + 200 * sizeof(char *)) + +__BEGIN_DECLS +int +gid_from_group(const char *, gid_t *); +const char * +group_from_gid(gid_t, int); +__END_DECLS + +#endif diff --git a/include/bsd/pwd.h b/include/bsd/pwd.h new file mode 100644 index 0000000..798af4b --- /dev/null +++ b/include/bsd/pwd.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2021 Guillem Jover <guillem@hadrons.org> + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#ifdef LIBBSD_OVERLAY +#include <sys/cdefs.h> +#if __has_include_next(<pwd.h>) +#include_next <pwd.h> +#endif +#else +#include <bsd/sys/cdefs.h> +#if __has_include(<pwd.h>) +#include <pwd.h> +#endif +#endif + +#ifndef LIBBSD_PWD_H +#define LIBBSD_PWD_H + +#define _PW_BUF_LEN 1024 /* length of getpw*_r buffer */ + +__BEGIN_DECLS +int +uid_from_user(const char *, uid_t *); +const char * +user_from_uid(uid_t, int); +__END_DECLS + +#endif diff --git a/man/Makefile.am b/man/Makefile.am index 4c7ed05..25e9566 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -174,6 +174,8 @@ dist_man_MANS = \ getmode.3bsd \ getpeereid.3bsd \ getprogname.3bsd \ + gid_from_group.3bsd \ + group_from_gid.3bsd \ heapsort.3bsd \ humanize_number.3bsd \ le16dec.3bsd \ @@ -191,6 +193,7 @@ dist_man_MANS = \ pidfile_open.3bsd \ pidfile_remove.3bsd \ pidfile_write.3bsd \ + pwcache.3bsd \ queue.3bsd \ radixsort.3bsd \ readpassphrase.3bsd \ @@ -233,7 +236,9 @@ dist_man_MANS = \ timespecsub.3bsd \ timeval.3bsd \ tree.3bsd \ + uid_from_user.3bsd \ unvis.3bsd \ + user_from_uid.3bsd \ vis.3bsd \ wcslcat.3bsd \ wcslcpy.3bsd \ diff --git a/man/gid_from_group.3bsd b/man/gid_from_group.3bsd new file mode 100644 index 0000000..6ddd88c --- /dev/null +++ b/man/gid_from_group.3bsd @@ -0,0 +1 @@ +.so man3/pwcache.3bsd diff --git a/man/group_from_gid.3bsd b/man/group_from_gid.3bsd new file mode 100644 index 0000000..6ddd88c --- /dev/null +++ b/man/group_from_gid.3bsd @@ -0,0 +1 @@ +.so man3/pwcache.3bsd diff --git a/man/pwcache.3bsd b/man/pwcache.3bsd new file mode 100644 index 0000000..dac9bcd --- /dev/null +++ b/man/pwcache.3bsd @@ -0,0 +1,143 @@ +.\" $OpenBSD: pwcache.3,v 1.15 2018/09/13 16:50:54 jmc Exp $ +.\" +.\" 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. +.\" +.Dd $Mdocdate: September 13 2018 $ +.Dt USER_FROM_UID 3 +.Os +.Sh NAME +.Nm user_from_uid , +.Nm uid_from_user , +.Nm group_from_gid , +.Nm gid_from_group +.Nd cache password and group entries +.Sh LIBRARY +.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd) +.ds doc-str-Lb-libbsd \*[str-Lb-libbsd] +.Lb libbsd +.Sh SYNOPSIS +.In pwd.h +(See +.Xr libbsd 7 +for include usage.) +.Ft int +.Fn uid_from_user "const char *name" "uid_t *uid" +.Ft const char * +.Fn user_from_uid "uid_t uid" "int nouser" +.In grp.h +.Ft int +.Fn gid_from_group "const char *name" "gid_t *gid" +.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 null pointer is returned. +.Pp +The +.Fn uid_from_user +function returns the user ID associated with the argument +.Fa name . +The user ID is cached so that multiple calls with the same +.Fa name +do not require additional calls to +.Xr getpwnam 3 . +If there is no user ID associated with the +.Fa name , +the +.Fn uid_from_user +function returns -1; +otherwise it stores the user ID at the location pointed to by +.Fa uid +and returns 0. +.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 null pointer is returned. +.Pp +The +.Fn gid_from_group +function returns the group ID associated with the argument +.Fa name . +The group ID is cached so that multiple calls with the same +.Fa name +do not require additional calls to +.Xr getgrnam 3 . +If there is no group ID associated with the +.Fa name , +the +.Fn gid_from_group +function returns -1; +otherwise it stores the group ID at the location pointed to by +.Fa gid +and returns 0. +.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 . +.Pp +The +.Fn uid_from_user +and +.Fn gid_from_group +functions were ported from +.Nx +and first appeared in +.Ox 6.4 . diff --git a/man/uid_from_user.3bsd b/man/uid_from_user.3bsd new file mode 100644 index 0000000..6ddd88c --- /dev/null +++ b/man/uid_from_user.3bsd @@ -0,0 +1 @@ +.so man3/pwcache.3bsd diff --git a/man/user_from_uid.3bsd b/man/user_from_uid.3bsd new file mode 100644 index 0000000..6ddd88c --- /dev/null +++ b/man/user_from_uid.3bsd @@ -0,0 +1 @@ +.so man3/pwcache.3bsd diff --git a/src/Makefile.am b/src/Makefile.am index 75cdecd..c13d385 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -108,6 +108,7 @@ libbsd_la_SOURCES = \ nlist.c \ pidfile.c \ progname.c \ + pwcache.c \ radixsort.c \ readpassphrase.c \ reallocarray.c \ diff --git a/src/libbsd.map b/src/libbsd.map index f499f8e..34e709b 100644 --- a/src/libbsd.map +++ b/src/libbsd.map @@ -187,4 +187,9 @@ LIBBSD_0.11.0 { recallocarray; freezero; + + gid_from_group; + group_from_gid; + uid_from_user; + user_from_uid; } LIBBSD_0.10.0; diff --git a/src/pwcache.c b/src/pwcache.c new file mode 100644 index 0000000..d54daa0 --- /dev/null +++ b/src/pwcache.c @@ -0,0 +1,437 @@ +/* $OpenBSD: pwcache.c,v 1.15 2018/09/22 02:47:23 millert 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. + */ + +#include <sys/types.h> + +#include <assert.h> +#include <grp.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +/* + * Constants and data structures used to implement group and password file + * caches. Name lengths have been chosen to be as large as those supported + * by the passwd and group files as well as the standard archive formats. + * 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; + +/* + * Routines that control user, group, uid and gid 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 adress this problem, these routines + * cache both hits and misses. + */ + +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 u_int +st_hash(const char *name, size_t len, int tabsz) +{ + u_int key = 0; + + assert(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) +{ + static int fail = 0; + + if (uidtb != NULL) + return 0; + if (fail) + return -1; + if ((uidtb = calloc(UID_SZ, sizeof(UIDC *))) == NULL) { + ++fail; + return -1; + } + return 0; +} + +/* + * gidtb_start + * creates an an empty gidtb + * Return: + * 0 if ok, -1 otherwise + */ +static int +gidtb_start(void) +{ + static int fail = 0; + + if (gidtb != NULL) + return 0; + if (fail) + return -1; + if ((gidtb = calloc(GID_SZ, sizeof(GIDC *))) == NULL) { + ++fail; + return -1; + } + return 0; +} + +/* + * usrtb_start + * creates an an empty usrtb + * Return: + * 0 if ok, -1 otherwise + */ +static int +usrtb_start(void) +{ + static int fail = 0; + + if (usrtb != NULL) + return 0; + if (fail) + return -1; + if ((usrtb = calloc(UNM_SZ, sizeof(UIDC *))) == NULL) { + ++fail; + return -1; + } + return 0; +} + +/* + * grptb_start + * creates an an empty grptb + * Return: + * 0 if ok, -1 otherwise + */ +static int +grptb_start(void) +{ + static int fail = 0; + + if (grptb != NULL) + return 0; + if (fail) + return -1; + if ((grptb = calloc(GNM_SZ, sizeof(GIDC *))) == NULL) { + ++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 pwstore, *pw = NULL; + char pwbuf[_PW_BUF_LEN]; + UIDC **pptr, *ptr = NULL; + + if ((uidtb != NULL) || (uidtb_start() == 0)) { + /* + * 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; + } + + if (ptr == NULL) + *pptr = ptr = malloc(sizeof(UIDC)); + } + + getpwuid_r(uid, &pwstore, pwbuf, sizeof(pwbuf), &pw); + if (pw == 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, "%u", 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, sizeof(ptr->name)); + 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 grstore, *gr = NULL; + char grbuf[_GR_BUF_LEN]; + GIDC **pptr, *ptr = NULL; + + if ((gidtb != NULL) || (gidtb_start() == 0)) { + /* + * 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; + } + + if (ptr == NULL) + *pptr = ptr = malloc(sizeof(GIDC)); + } + + getgrgid_r(gid, &grstore, grbuf, sizeof(grbuf), &gr); + if (gr == NULL) { + /* + * no match for this gid in the local group file, put in + * a string that is the gid in numeric format + */ + if (ptr == NULL) + return NULL; + ptr->gid = gid; + (void)snprintf(ptr->name, GNMLEN, "%u", 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, sizeof(ptr->name)); + ptr->valid = VALID; + } + return ptr->name; +} + +/* + * uid_from_user() + * caches the uid for a given user name. We use a simple hash table. + * Return: + * 0 if the user name is found (filling in uid), -1 otherwise + */ +int +uid_from_user(const char *name, uid_t *uid) +{ + struct passwd pwstore, *pw = NULL; + char pwbuf[_PW_BUF_LEN]; + UIDC **pptr, *ptr = NULL; + size_t namelen; + + /* + * return -1 for mangled names + */ + if (name == NULL || ((namelen = strlen(name)) == 0)) + return -1; + + if ((usrtb != NULL) || (usrtb_start() == 0)) { + /* + * 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) == 0) { + if (ptr->valid == INVALID) + return -1; + *uid = ptr->uid; + return 0; + } + + if (ptr == NULL) + *pptr = ptr = malloc(sizeof(UIDC)); + } + + /* + * no match, look it up, if no match store it as an invalid entry, + * or store the matching uid + */ + getpwnam_r(name, &pwstore, pwbuf, sizeof(pwbuf), &pw); + if (ptr == NULL) { + if (pw == NULL) + return -1; + *uid = pw->pw_uid; + return 0; + } + (void)strlcpy(ptr->name, name, sizeof(ptr->name)); + if (pw == 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: + * 0 if the group name is found (filling in gid), -1 otherwise + */ +int +gid_from_group(const char *name, gid_t *gid) +{ + struct group grstore, *gr = NULL; + char grbuf[_GR_BUF_LEN]; + GIDC **pptr, *ptr = NULL; + size_t namelen; + + /* + * return -1 for mangled names + */ + if (name == NULL || ((namelen = strlen(name)) == 0)) + return -1; + + if ((grptb != NULL) || (grptb_start() == 0)) { + /* + * 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) == 0) { + if (ptr->valid == INVALID) + return -1; + *gid = ptr->gid; + return 0; + } + + if (ptr == NULL) + *pptr = ptr = malloc(sizeof(GIDC)); + } + + /* + * no match, look it up, if no match store it as an invalid entry, + * or store the matching gid + */ + getgrnam_r(name, &grstore, grbuf, sizeof(grbuf), &gr); + if (ptr == NULL) { + if (gr == NULL) + return -1; + *gid = gr->gr_gid; + return 0; + } + + (void)strlcpy(ptr->name, name, sizeof(ptr->name)); + if (gr == NULL) { + ptr->valid = INVALID; + return -1; + } + ptr->valid = VALID; + *gid = ptr->gid = gr->gr_gid; + return 0; +} diff --git a/test/.gitignore b/test/.gitignore index 47063b9..2c39751 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -15,6 +15,7 @@ overlay proctitle-init proctitle progname +pwcache setmode strl strmode diff --git a/test/Makefile.am b/test/Makefile.am index 452558d..90fe384 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -43,6 +43,7 @@ check_PROGRAMS = \ nlist \ proctitle-init \ progname \ + pwcache \ setmode \ strl \ strmode \ diff --git a/test/overlay.c b/test/overlay.c index a17904f..0ec6d7c 100644 --- a/test/overlay.c +++ b/test/overlay.c @@ -28,6 +28,9 @@ * other headers through magic macros, to check that the overlay is working * properly. */ #include <errno.h> +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif #ifdef HAVE_GRP_H #include <grp.h> #endif diff --git a/test/pwcache.c b/test/pwcache.c new file mode 100644 index 0000000..d68ea4c --- /dev/null +++ b/test/pwcache.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2021 Guillem Jover <guillem@hadrons.org> + * + * 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. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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. + */ + +#include <assert.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> + +int +main(int argc, char **argv) +{ + uid_t uid; + gid_t gid; + + assert(uid_from_user("root", &uid) == 0); + assert(uid == 0); + + assert(strcmp(user_from_uid(0, 0), "root") == 0); + + assert(gid_from_group("root", &gid) == 0); + assert(gid == 0); + + assert(strcmp(group_from_gid(0, 0), "root") == 0); + + return 0; +} |