/* 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 */ static pthread_mutex_t pwent_mutex = PTHREAD_MUTEX_INITIALIZER; static int __fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, size_t len, struct passwd **result) { struct passwd *pwtmp; char *cursor = buf, *end = buf + len; *result = NULL; pthread_mutex_lock(&pwent_mutex); pwtmp = stream != NULL ? fgetpwent(stream) : getpwent(); if (pwtmp == NULL) { pthread_mutex_unlock(&pwent_mutex); return ENOENT; } 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 (pwtmp->pw_passwd != NULL) { pwd->pw_passwd = cursor; cursor += strlcpy(cursor, pwtmp->pw_passwd, end - cursor) + 1; if (cursor > end) { goto err_unlock; } } if (pwtmp->pw_gecos != NULL) { pwd->pw_gecos = cursor; cursor += strlcpy(cursor, pwtmp->pw_gecos, end - cursor) + 1; if (cursor > end) { goto err_unlock; } } 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; } /** * Get passwd file entry. */ int fgetpwent_r(FILE *stream, struct passwd *pwd, char *buf, size_t len, struct passwd **result) { assert(stream != NULL); return __fgetpwent_r(stream, pwd, buf, len, result); } /** * 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); }