]> git.ipfire.org Git - thirdparty/libbsd.git/commitdiff
Import pwcache module from OpenBSD
authorGuillem Jover <guillem@hadrons.org>
Sat, 6 Feb 2021 22:43:12 +0000 (23:43 +0100)
committerGuillem Jover <guillem@hadrons.org>
Sun, 7 Feb 2021 00:28:27 +0000 (01:28 +0100)
18 files changed:
COPYING
configure.ac
include/Makefile.am
include/bsd/grp.h [new file with mode: 0644]
include/bsd/pwd.h [new file with mode: 0644]
man/Makefile.am
man/gid_from_group.3bsd [new file with mode: 0644]
man/group_from_gid.3bsd [new file with mode: 0644]
man/pwcache.3bsd [new file with mode: 0644]
man/uid_from_user.3bsd [new file with mode: 0644]
man/user_from_uid.3bsd [new file with mode: 0644]
src/Makefile.am
src/libbsd.map
src/pwcache.c [new file with mode: 0644]
test/.gitignore
test/Makefile.am
test/overlay.c
test/pwcache.c [new file with mode: 0644]

diff --git a/COPYING b/COPYING
index d3899a9a7a42e13de7a2037cd62bf5ceb504ff9c..34ec43239c4bc7a16cde2f69259cdc93885d24bb 100644 (file)
--- 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
index e8d4c5f6929808b6e9481eebb794b5d48b1fa3fe..cf064bba28af0da8c1431ebeb92369d0c5b85cf1 100644 (file)
@@ -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
index 949ea80a12cba1a0a67cf76b1266a0fef0874d16..e6f66bdcff9bd68cff2ce50d2940796414c8895b 100644 (file)
@@ -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 (file)
index 0000000..b2705e5
--- /dev/null
@@ -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 (file)
index 0000000..798af4b
--- /dev/null
@@ -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
index 4c7ed0565a4935d1185e8532a894913ab8d12b28..25e9566f318dd85635e8fb671cff080eba0464e3 100644 (file)
@@ -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 (file)
index 0000000..6ddd88c
--- /dev/null
@@ -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 (file)
index 0000000..6ddd88c
--- /dev/null
@@ -0,0 +1 @@
+.so man3/pwcache.3bsd
diff --git a/man/pwcache.3bsd b/man/pwcache.3bsd
new file mode 100644 (file)
index 0000000..dac9bcd
--- /dev/null
@@ -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 (file)
index 0000000..6ddd88c
--- /dev/null
@@ -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 (file)
index 0000000..6ddd88c
--- /dev/null
@@ -0,0 +1 @@
+.so man3/pwcache.3bsd
index 75cdecd440d34e1454757f172c00f0239216219b..c13d385a07d23debd5c25842786cf1a678c2ff0e 100644 (file)
@@ -108,6 +108,7 @@ libbsd_la_SOURCES = \
        nlist.c \
        pidfile.c \
        progname.c \
+       pwcache.c \
        radixsort.c \
        readpassphrase.c \
        reallocarray.c \
index f499f8ee5f81be35f87a8995d176b51517bf2d60..34e709b23f6c12b8bc7a171e14abc448a01ad600 100644 (file)
@@ -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 (file)
index 0000000..d54daa0
--- /dev/null
@@ -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;
+}
index 47063b9b5e12131b470ba626ad48c0783d0e231b..2c3975184a79bab495b4b6eea2e24ddb5611c625 100644 (file)
@@ -15,6 +15,7 @@ overlay
 proctitle-init
 proctitle
 progname
+pwcache
 setmode
 strl
 strmode
index 452558dca8c552b472e1478e22528a375c181c51..90fe38430bbdb364f29c8610b8f8021908a51aae 100644 (file)
@@ -43,6 +43,7 @@ check_PROGRAMS = \
        nlist \
        proctitle-init \
        progname \
+       pwcache \
        setmode \
        strl \
        strmode \
index a17904ff4ac906d7a7656e5b6464b78ba683b474..0ec6d7c3bc73ccdd3ac909eafeaddd324a881861 100644 (file)
@@ -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 (file)
index 0000000..d68ea4c
--- /dev/null
@@ -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;
+}