[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
- [PATCH v2] use thread-safe getpwnam_r and getgrnam_r,
Pavel Simovec <=