summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillem Jover <guillem@hadrons.org>2021-02-06 23:43:12 +0100
committerGuillem Jover <guillem@hadrons.org>2021-02-07 01:28:27 +0100
commit37a9b56c05339301510213c41fc507ea31cc2464 (patch)
treecbb067e81f4d3d1b6af63387ebbed6043746838e
parent45dd5229ea5f3c62877f5f66f80ab8e52d40a281 (diff)
Import pwcache module from OpenBSD
-rw-r--r--COPYING3
-rw-r--r--configure.ac2
-rw-r--r--include/Makefile.am2
-rw-r--r--include/bsd/grp.h51
-rw-r--r--include/bsd/pwd.h51
-rw-r--r--man/Makefile.am5
-rw-r--r--man/gid_from_group.3bsd1
-rw-r--r--man/group_from_gid.3bsd1
-rw-r--r--man/pwcache.3bsd143
-rw-r--r--man/uid_from_user.3bsd1
-rw-r--r--man/user_from_uid.3bsd1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/libbsd.map5
-rw-r--r--src/pwcache.c437
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am1
-rw-r--r--test/overlay.c3
-rw-r--r--test/pwcache.c49
18 files changed, 757 insertions, 1 deletions
diff --git a/COPYING b/COPYING
index d3899a9..34ec432 100644
--- a/COPYING
+++ b/COPYING
@@ -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;
+}