]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib: (pwdutils.c) new library routines to get a group/passwd struct by name or GID/UID
authorChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Wed, 26 Nov 2025 02:36:23 +0000 (21:36 -0500)
committerChristian Goeschel Ndjomouo <cgoesc2@wgu.edu>
Mon, 1 Dec 2025 07:58:13 +0000 (02:58 -0500)
In some tools users can specify groups/users by their name but not
the GID or UID. To enable this in a trivial manner util-linux tools
can now call the ul_getgrp_str(), ul_getuserpw_str(), xgetgroup()
and xgetuserpw() routines to achieve this.

Signed-off-by: Christian Goeschel Ndjomouo <cgoesc2@wgu.edu>
include/pwdutils.h
lib/Makemodule.am
lib/pwdutils.c

index 1d44242746eeac472426528e5acc80044c1d242b..321b2ac59665a559b68b1f374cc3b127e8e9a2b7 100644 (file)
@@ -9,10 +9,12 @@
 #include <pwd.h>
 #include <grp.h>
 
-extern struct passwd *xgetpwnam(const char *username, char **pwdbuf);
-extern struct group *xgetgrnam(const char *groupname, char **grpbuf);
 extern struct passwd *xgetpwuid(uid_t uid, char **pwdbuf);
+extern struct passwd *xgetuserpw(const char *str, char **pwdbuf);
+extern struct group *xgetgroup(const char *str, char **pwdbuf);
 extern char *xgetlogin(void);
+extern struct group *ul_getgrp_str(const char *str);
+extern struct passwd *ul_getuserpw_str(const char *str);
 
 #endif /* UTIL_LINUX_PWDUTILS_H */
 
index a9da577348baf8bb31bb81444cdf07b63123bd9e..e824593d6ccbbcd1c077a1f23f2a5a474207b3a1 100644 (file)
@@ -231,6 +231,7 @@ test_timeutils_LDADD = $(LDADD) libcommon.la
 
 test_pwdutils_SOURCES = lib/pwdutils.c
 test_pwdutils_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM
+test_pwdutils_LDADD = $(LDADD) libcommon.la
 
 test_remove_env_SOURCES = lib/env.c
 test_remove_env_CFLAGS = $(AM_CFLAGS) -DTEST_PROGRAM_ENV
index 1c1f13e9293384f7da6c92fb5095af66886c3d44..35f1f7866ccd26189e7f4d6d481783f0ad68e739 100644 (file)
@@ -1,31 +1,28 @@
 /*
- * No copyright is claimed.  This code is in the public domain; do with
+ * No copyright is claimed. This code is in the public domain; do with
  * it what you wish.
  */
 #include <stdlib.h>
 #include <assert.h>
+#include <unistd.h>
 
 #include "c.h"
 #include "pwdutils.h"
 #include "xalloc.h"
+#include "strutils.h"
 
-/* Returns allocated passwd and allocated pwdbuf to store passwd strings
- * fields. In case of error returns NULL and set errno, for unknown user set
- * errno to EINVAL
- */
-struct passwd *xgetpwnam(const char *username, char **pwdbuf)
+struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
 {
        struct passwd *pwd = NULL, *res = NULL;
        int rc;
 
        assert(pwdbuf);
-       assert(username);
 
        *pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
        pwd = xcalloc(1, sizeof(struct passwd));
 
        errno = 0;
-       rc = getpwnam_r(username, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+       rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
        if (rc != 0) {
                errno = rc;
                goto failed;
@@ -41,23 +38,39 @@ failed:
        return NULL;
 }
 
-/* Returns allocated group and allocated grpbuf to store group strings
- * fields. In case of error returns NULL and set errno, for unknown group set
- * errno to EINVAL
+/* Returns allocated passwd and allocated pwdbuf for the username or UID passed
+ * as @str. In case of error returns NULL and set errno, for unknown user it
+ * sets errno to EINVAL.
  */
-struct group *xgetgrnam(const char *groupname, char **grpbuf)
+struct passwd *xgetuserpw(const char *str ,char **pwdbuf)
 {
-       struct group *grp = NULL, *res = NULL;
+       struct passwd *pwd = NULL, *res = NULL;
        int rc;
+       uint64_t uid;
 
-       assert(grpbuf);
-       assert(groupname);
+       assert(pwdbuf);
+       assert(str);
 
-       *grpbuf = xmalloc(UL_GETPW_BUFSIZ);
-       grp = xcalloc(1, sizeof(struct group));
+       *pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
+       pwd = xcalloc(1, sizeof(struct passwd));
+
+       /* is @str a UID ? */
+       rc = ul_strtou64(str, &uid, 10);
+       if (rc == -ERANGE) {
+               errno = ERANGE;
+               goto failed;
+       }
+       /* @str is an invalid number, let's assume it is the username */
+       if (rc == -EINVAL) {
+               rc = getpwnam_r(str, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+       } else {
+               if (uid > MAX_OF_UINT_TYPE(uid_t)) {
+                       errno = ERANGE;
+                       goto failed;
+               }
+               rc = getpwuid_r((uid_t)uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
+       }
 
-       errno = 0;
-       rc = getgrnam_r(groupname, grp, *grpbuf, UL_GETPW_BUFSIZ, &res);
        if (rc != 0) {
                errno = rc;
                goto failed;
@@ -66,25 +79,46 @@ struct group *xgetgrnam(const char *groupname, char **grpbuf)
                errno = EINVAL;
                goto failed;
        }
-       return grp;
+       return pwd;
 failed:
-       free(grp);
-       free(*grpbuf);
+       free(pwd);
+       free(*pwdbuf);
        return NULL;
 }
 
-struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
+/* Returns allocated group and allocated grpbuf for the group name or GID passed
+ * as @str. In case of error returns NULL and set errno, for unknown group it
+ * sets errno to EINVAL.
+ */
+struct group *xgetgroup(const char *str, char **grpbuf)
 {
-       struct passwd *pwd = NULL, *res = NULL;
+       struct group *grp = NULL, *res = NULL;
        int rc;
+       uint64_t gid;
 
-       assert(pwdbuf);
+       assert(grpbuf);
+       assert(str);
 
-       *pwdbuf = xmalloc(UL_GETPW_BUFSIZ);
-       pwd = xcalloc(1, sizeof(struct passwd));
+       *grpbuf = xmalloc(UL_GETPW_BUFSIZ);
+       grp = xcalloc(1, sizeof(struct group));
+
+       /* is @str a GID ? */
+       rc = ul_strtou64(str, &gid, 10);
+       if (rc == -ERANGE) {
+               errno = ERANGE;
+               goto failed;
+       }
+       /* @str is an invalid number, let's assume it is the group name */
+       if (rc == -EINVAL) {
+               rc = getgrnam_r(str, grp, *grpbuf, UL_GETPW_BUFSIZ, &res);
+       } else {
+               if (gid > MAX_OF_UINT_TYPE(gid_t)) {
+                       errno = ERANGE;
+                       goto failed;
+               }
+               rc = getgrgid_r((gid_t)gid, grp, *grpbuf, UL_GETPW_BUFSIZ, &res);
+       }
 
-       errno = 0;
-       rc = getpwuid_r(uid, pwd, *pwdbuf, UL_GETPW_BUFSIZ, &res);
        if (rc != 0) {
                errno = rc;
                goto failed;
@@ -93,10 +127,10 @@ struct passwd *xgetpwuid(uid_t uid, char **pwdbuf)
                errno = EINVAL;
                goto failed;
        }
-       return pwd;
+       return grp;
 failed:
-       free(pwd);
-       free(*pwdbuf);
+       free(grp);
+       free(*grpbuf);
        return NULL;
 }
 
@@ -127,6 +161,44 @@ char *xgetlogin(void)
        return NULL;
 }
 
+/*
+ * Return a pointer to a `struct group` for a matching group name or GID.
+ */
+struct group *ul_getgrp_str(const char *str)
+{
+        int rc;
+        uint64_t gid;
+
+        rc = ul_strtou64(str, &gid, 10);
+        if (rc == -ERANGE)
+                return NULL;
+        if (rc == -EINVAL)
+                return getgrnam(str);
+        if (gid > MAX_OF_UINT_TYPE(gid_t))
+                return NULL;
+
+        return getgrgid((gid_t)gid);
+}
+
+/*
+ * Return a pointer to a `struct passwd` for a matching username or UID.
+ */
+struct passwd *ul_getuserpw_str(const char *str)
+{
+        int rc;
+        uint64_t uid;
+
+        rc = ul_strtou64(str, &uid, 10);
+        if (rc == -ERANGE)
+                return NULL;
+        if (rc == -EINVAL)
+                return getpwnam(str);
+        if (uid > MAX_OF_UINT_TYPE(uid_t))
+                return NULL;
+
+        return getpwuid((uid_t)uid);
+}
+
 #ifdef TEST_PROGRAM
 int main(int argc, char *argv[])
 {
@@ -138,7 +210,7 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
-       pwd = xgetpwnam(argv[1], &buf);
+       pwd = xgetuserpw(argv[1], &buf);
        if (!pwd)
                err(EXIT_FAILURE, "failed to get %s pwd entry", argv[1]);