From: Christian Goeschel Ndjomouo Date: Wed, 26 Nov 2025 02:36:23 +0000 (-0500) Subject: lib: (pwdutils.c) new library routines to get a group/passwd struct by name or GID/UID X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=563ce081db1fdc11ae290e15f430193e1dcef85a;p=thirdparty%2Futil-linux.git lib: (pwdutils.c) new library routines to get a group/passwd struct by name or GID/UID 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 --- diff --git a/include/pwdutils.h b/include/pwdutils.h index 1d4424274..321b2ac59 100644 --- a/include/pwdutils.h +++ b/include/pwdutils.h @@ -9,10 +9,12 @@ #include #include -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 */ diff --git a/lib/Makemodule.am b/lib/Makemodule.am index a9da57734..e824593d6 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -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 diff --git a/lib/pwdutils.c b/lib/pwdutils.c index 1c1f13e92..35f1f7866 100644 --- a/lib/pwdutils.c +++ b/lib/pwdutils.c @@ -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 #include +#include #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]);