From 810f46ab1cc801e54fc3836c22b5f1364cd632e6 Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Sun, 14 Jan 2018 22:09:08 -0600 Subject: pwd: Fully implement fgetpwent_r/getpwent_r These functions require a deep copy of the structure into the caller-provided buffer. Also make sure to store NULL in result on error. Use the stream to differentiate the two functions and avoid duplication. Signed-off-by: Samuel Holland --- libgcompat/pwd.c | 119 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 45 deletions(-) (limited to 'libgcompat') diff --git a/libgcompat/pwd.c b/libgcompat/pwd.c index 50d8da0..34c5d7b 100644 --- a/libgcompat/pwd.c +++ b/libgcompat/pwd.c @@ -1,63 +1,92 @@ /* some musl versions incorrectly mark fgetpwent() as a GNU extension */ #define _GNU_SOURCE +#include /* assert */ +#include /* ENOENT, ERANGE */ +#include /* pthread_mutex_* */ +#include /* fgetpwent, getpwent, struct passwd */ +#include /* NULL, size_t */ +#include /* FILE */ +#include /* memcpy, stpcpy, strlcpy, strlen */ -#include -#include -#include -#include +static pthread_mutex_t pwent_mutex = PTHREAD_MUTEX_INITIALIZER; -int getpwent_r(struct passwd *pwbuf, char *buf, size_t buflen, - struct passwd **pwbufp) +static int __fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, + size_t len, struct passwd **result) { - struct passwd *pwd; + struct passwd *pwtmp; + char *cursor = buf, *end = buf + len; - if (pwbufp == NULL || pwbuf == NULL) { - return ERANGE; + *result = NULL; + pthread_mutex_lock(&pwent_mutex); + pwtmp = stream != NULL ? fgetpwent(stream) : getpwent(); + if (pwtmp == NULL) { + pthread_mutex_unlock(&pwent_mutex); + return ENOENT; } - - if (buflen < 1) { - return ERANGE; + memcpy(pwd, pwtmp, sizeof(*pwd)); + if (pwtmp->pw_name != NULL) { + pwd->pw_name = cursor; + cursor += strlcpy(cursor, pwtmp->pw_name, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - if (buf != NULL) { - *buf = '\0'; + if (pwtmp->pw_passwd != NULL) { + pwd->pw_passwd = cursor; + cursor += strlcpy(cursor, pwtmp->pw_passwd, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - if ((pwd = getpwent()) == NULL) { - *pwbufp = NULL; - return ENOENT; + if (pwtmp->pw_gecos != NULL) { + pwd->pw_gecos = cursor; + cursor += strlcpy(cursor, pwtmp->pw_gecos, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } } - - memcpy(pwbuf, pwd, sizeof(*pwd)); - *pwbufp = pwbuf; + if (pwtmp->pw_dir != NULL) { + pwd->pw_dir = cursor; + cursor += strlcpy(cursor, pwtmp->pw_dir, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + if (pwtmp->pw_shell != NULL) { + pwd->pw_shell = cursor; + cursor += strlcpy(cursor, pwtmp->pw_shell, end - cursor) + 1; + if (cursor > end) { + goto err_unlock; + } + } + pthread_mutex_unlock(&pwent_mutex); + *result = pwd; return 0; + +err_unlock: + pthread_mutex_unlock(&pwent_mutex); + return ERANGE; } -int fgetpwent_r(FILE *filp, struct passwd *pwbuf, char *buf, size_t buflen, - struct passwd **pwbufp) +/** + * Get passwd file entry. + */ +int fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, size_t len, + struct passwd **result) { - struct passwd *pwd; - - if (pwbufp == NULL || pwbuf == NULL) { - return ERANGE; - } + assert(stream != NULL); - if (buflen < 1) { - return ERANGE; - } - - if (buf != NULL) { - *buf = '\0'; - } - - if ((pwd = fgetpwent(filp)) == NULL) { - *pwbufp = NULL; - return ENOENT; - } - - memcpy(pwbuf, pwd, sizeof(*pwd)); - *pwbufp = pwbuf; + return fgetpwent_r(stream, pwd, buf, len, result); +} - return 0; +/** + * Get user database entry. + * + * LSB 5.0: LSB-Core-generic/baselib-getpwent-r-1.html + */ +int getpwent_r(struct passwd *pwd, char *buf, size_t len, + struct passwd **result) +{ + return __fgetpwent_r(NULL, pwd, buf, len, result); } -- cgit v1.2.3-60-g2f50