acl-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2] use thread-safe getpwnam_r and getgrnam_r


From: Pavel Simovec
Subject: [PATCH v2] use thread-safe getpwnam_r and getgrnam_r
Date: Thu, 12 Oct 2023 16:17:07 +0200

- Switch from `getpwnam` and `getgrnam` to `getpwnam_r` and `getgrnam_r`
for thread safety.
- Extract duplicated `get_id`, `get_uid`, and `get_gid` to common module
`libmisc/get.c` from `libacl/acl_from_text.c` and `tools/parse.c`.
- Update tests for buffer resizing due to these changes.

This ensures improved thread safety without changing the functional behavior.
---
 include/misc.h           |   5 ++
 libacl/acl_from_text.c   |  58 ------------------
 libmisc/Makemodule.am    |   1 +
 libmisc/uid_gid_lookup.c | 128 +++++++++++++++++++++++++++++++++++++++
 test/test_group.c        |  10 +++
 test/test_passwd.c       |  11 ++++
 tools/parse.c            |  64 --------------------
 7 files changed, 155 insertions(+), 122 deletions(-)
 create mode 100644 libmisc/uid_gid_lookup.c

diff --git a/include/misc.h b/include/misc.h
index 22ad915..6cb578a 100644
--- a/include/misc.h
+++ b/include/misc.h
@@ -19,6 +19,7 @@
 #define __MISC_H
 
 #include <stdio.h>
+#include <sys/types.h>
 
 /* Mark library internal functions as hidden */
 #if defined(HAVE_VISIBILITY_ATTRIBUTE)
@@ -34,6 +35,10 @@ hidden char *__acl_unquote(char *str);
 
 hidden char *__acl_next_line(FILE *file);
 
+hidden int get_id(const char *token, id_t *id_p);
+hidden int get_uid(const char *token, uid_t *uid_p);
+hidden int get_gid(const char *token, gid_t *gid_p);
+
 #ifdef ENABLE_NLS
 # include <libintl.h>
 # define _(x)                  gettext(x)
diff --git a/libacl/acl_from_text.c b/libacl/acl_from_text.c
index 2617cbb..e17bb0e 100644
--- a/libacl/acl_from_text.c
+++ b/libacl/acl_from_text.c
@@ -126,64 +126,6 @@ after_token:
 }
 
 
-static int
-get_id(const char *token, id_t *id_p)
-{
-       char *ep;
-       long l;
-       l = strtol(token, &ep, 0);
-       if (*ep != '\0')
-               return -1;
-       if (l < 0) {
-               /*
-                 Negative values are interpreted as 16-bit numbers,
-                 so that id -2 maps to 65534 (nobody/nogroup), etc.
-               */
-               l &= 0xFFFF;
-       }
-       *id_p = l;
-       return 0;
-}
-
-
-static int
-get_uid(const char *token, uid_t *uid_p)
-{
-       struct passwd *passwd;
-
-       if (get_id(token, uid_p) == 0)
-               return 0;
-       errno = 0;
-       passwd = getpwnam(token);
-       if (passwd) {
-               *uid_p = passwd->pw_uid;
-               return 0;
-       }
-       if (errno == 0)
-               errno = EINVAL;
-       return -1;
-}
-
-
-static int
-get_gid(const char *token, gid_t *gid_p)
-{
-       struct group *group;
-
-       if (get_id(token, (uid_t *)gid_p) == 0)
-               return 0;
-       errno = 0;
-       group = getgrnam(token);
-       if (group) {
-               *gid_p = group->gr_gid;
-               return 0;
-       }
-       if (errno == 0)
-               errno = EINVAL;
-       return -1;
-}
-
-
 /*
        Parses the next acl entry in text_p.
 
diff --git a/libmisc/Makemodule.am b/libmisc/Makemodule.am
index d784622..2bb7bf0 100644
--- a/libmisc/Makemodule.am
+++ b/libmisc/Makemodule.am
@@ -1,6 +1,7 @@
 noinst_LTLIBRARIES += libmisc.la
 
 libmisc_la_SOURCES = \
+       libmisc/uid_gid_lookup.c \
        libmisc/high_water_alloc.c \
        libmisc/next_line.c \
        libmisc/quote.c \
diff --git a/libmisc/uid_gid_lookup.c b/libmisc/uid_gid_lookup.c
new file mode 100644
index 0000000..ccebc99
--- /dev/null
+++ b/libmisc/uid_gid_lookup.c
@@ -0,0 +1,128 @@
+/*
+  File: uid_gid_lookup.c
+
+  Copyright (C) 2023 Andreas Gruenbacher <andreas.gruenbacher@gmail.com>
+
+  This program is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2.1 of the License, or (at
+  your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "config.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include "libacl.h"
+#include "misc.h"
+
+int
+get_id(const char *token, id_t *id_p)
+{
+       char *ep;
+       long l;
+       l = strtol(token, &ep, 0);
+       if (*ep != '\0')
+               return -1;
+       if (l < 0) {
+               /*
+                 Negative values are interpreted as 16-bit numbers,
+                 so that id -2 maps to 65534 (nobody/nogroup), etc.
+               */
+               l &= 0xFFFF;
+       }
+       *id_p = l;
+       return 0;
+}
+
+static char *
+grow_buffer(char **buffer, size_t *bufsize, int type)
+{
+       long size = *bufsize;
+       char *buf;
+
+       if (!size) {
+               size = sysconf(type);
+               if (size <= 0)
+                       size = 16384;
+       } else {
+               size *= 2;
+       }
+
+       buf = realloc(*buffer, size);
+       if (buf) {
+               *buffer = buf;
+               *bufsize = size;
+       }
+       return buf;
+}
+
+int
+get_uid(const char *token, uid_t *uid_p)
+{
+       struct passwd passwd, *result = NULL;
+       char *buffer = NULL;
+       size_t bufsize = 0;
+       int err;
+       if (get_id(token, uid_p) == 0)
+               return 0;
+
+       for(;;) {
+               if(!grow_buffer(&buffer, &bufsize, _SC_GETPW_R_SIZE_MAX))
+                       break;
+
+               err = getpwnam_r(token, &passwd, buffer, bufsize, &result);
+               if (result) {
+                       *uid_p = passwd.pw_uid;
+                       break;
+               }
+               if (err == ERANGE)
+                       continue;
+               errno = err ? err : EINVAL;
+       }
+       free(buffer);
+       return result ? 0 : -1;
+}
+
+
+int
+get_gid(const char *token, gid_t *gid_p)
+{
+       struct group group, *result = NULL;
+       char *buffer = NULL;
+       size_t bufsize = 0;
+       int err;
+       if (get_id(token, (uid_t *)gid_p) == 0)
+               return 0;
+
+       for(;;) {
+               if(!grow_buffer(&buffer, &bufsize, _SC_GETGR_R_SIZE_MAX))
+                       break;
+
+               err = getgrnam_r(token, &group, buffer, bufsize, &result);
+               if (result) {
+                       *gid_p = group.gr_gid;
+                       break;
+               }
+               if (err == ERANGE)
+                       continue;
+               errno = err ? err : EINVAL;
+               break;
+       }
+
+       free(buffer);
+       return result ? 0 : -1;
+}
+
diff --git a/test/test_group.c b/test/test_group.c
index 6ca761a..8c24a14 100644
--- a/test/test_group.c
+++ b/test/test_group.c
@@ -1,4 +1,5 @@
 #include "config.h"
+#include <assert.h>
 #include <sys/types.h>
 #include <stdio.h>
 #include <string.h>
@@ -10,6 +11,7 @@
 
 #define TEST_GROUP "test/test.group"
 static char grfile[] = BASEDIR "/" TEST_GROUP;
+static int lastbufsize = -1;
 
 
 #define ALIGN_MASK(x, mask)    (((x) + (mask)) & ~(mask))
@@ -116,6 +118,14 @@ EXPORT
 int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen,
               struct group **result)
 {
+       assert(lastbufsize < 0 || buflen == lastbufsize * 2);
+       lastbufsize=buflen;
+       size_t REQBUFSIZE = 170000;
+       if (buflen < REQBUFSIZE){
+               *result=NULL;
+               return ERANGE;
+       }
+       lastbufsize=-1;
        return test_getgr_match(grp, buf, buflen, result, match_name, name);
 }
 
diff --git a/test/test_passwd.c b/test/test_passwd.c
index 9a6dad5..ef5ebb1 100644
--- a/test/test_passwd.c
+++ b/test/test_passwd.c
@@ -1,4 +1,5 @@
 #include "config.h"
+#include <assert.h>
 #include <sys/types.h>
 #include <stdio.h>
 #include <string.h>
@@ -11,6 +12,8 @@
 #define TEST_PASSWD "test/test.passwd"
 static char pwfile[] = BASEDIR "/" TEST_PASSWD;
 
+static int lastbufsize =- 1;
+
 #define ALIGN_MASK(x, mask)    (((x) + (mask)) & ~(mask))
 #define ALIGN(x, a)            ALIGN_MASK(x, (typeof(x))(a) - 1)
 
@@ -110,6 +113,14 @@ EXPORT
 int getpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen,
               struct passwd **result)
 {
+       assert(lastbufsize < 0 || buflen == lastbufsize * 2);
+       lastbufsize = buflen;
+       size_t REQBUFSIZE = 170000;
+       if (buflen < REQBUFSIZE){
+               *result=NULL;
+               return ERANGE;
+       }
+       lastbufsize =- 1;
        return test_getpw_match(pwd, buf, buflen, result, match_name, name);
 }
 
diff --git a/tools/parse.c b/tools/parse.c
index 78ae49a..9c41fe7 100644
--- a/tools/parse.c
+++ b/tools/parse.c
@@ -111,70 +111,6 @@ after_token:
 }
 
 
-static int
-get_id(
-       const char *token,
-       id_t *id_p)
-{
-       char *ep;
-       long l;
-       l = strtol(token, &ep, 0);
-       if (*ep != '\0')
-               return -1;
-       if (l < 0) {
-               /*
-                 Negative values are interpreted as 16-bit numbers,
-                 so that id -2 maps to 65534 (nobody/nogroup), etc.
-               */
-               l &= 0xFFFF;
-       }
-       *id_p = l;
-       return 0;
-}
-
-
-static int
-get_uid(
-       const char *token,
-       uid_t *uid_p)
-{
-       struct passwd *passwd;
-
-       if (get_id(token, (id_t *)uid_p) == 0)
-               goto accept;
-       passwd = getpwnam(token);
-       if (passwd) {
-               *uid_p = passwd->pw_uid;
-               goto accept;
-       }
-       return -1;
-
-accept:
-       return 0;
-}
-
-
-static int
-get_gid(
-       const char *token,
-       gid_t *gid_p)
-{
-       struct group *group;
-
-       if (get_id(token, (id_t *)gid_p) == 0)
-               goto accept;
-       group = getgrnam(token);
-       if (group) {
-               *gid_p = group->gr_gid;
-               goto accept;
-       }
-       return -1;
-
-accept:
-       return 0;
-}
-
-
 /*
        Parses the next acl entry in text_p.
 
-- 
2.42.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]