From 71054c4c06c8199e0d2e362c293941730e3074da Mon Sep 17 00:00:00 2001 From: AnotherTest Date: Fri, 12 Feb 2021 05:40:57 +0330 Subject: [PATCH] LibC: Add reentrant versions of getpw{uid,nam} Pretty hacky, but it should be fine. --- Userland/Libraries/LibC/pwd.cpp | 88 +++++++++++++++++++++++++++++++++ Userland/Libraries/LibC/pwd.h | 3 ++ 2 files changed, 91 insertions(+) diff --git a/Userland/Libraries/LibC/pwd.cpp b/Userland/Libraries/LibC/pwd.cpp index 7af0d67d68..1d104e29c9 100644 --- a/Userland/Libraries/LibC/pwd.cpp +++ b/Userland/Libraries/LibC/pwd.cpp @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -162,6 +163,93 @@ struct passwd* getpwent() } } +static void construct_pwd(struct passwd* pwd, char* buf, struct passwd** result) +{ + auto* buf_name = &buf[0]; + auto* buf_passwd = &buf[s_name.length() + 1]; + auto* buf_gecos = &buf[s_name.length() + 1 + s_gecos.length() + 1]; + auto* buf_dir = &buf[s_gecos.length() + 1 + s_name.length() + 1 + s_gecos.length() + 1]; + auto* buf_shell = &buf[s_dir.length() + 1 + s_gecos.length() + 1 + s_name.length() + 1 + s_gecos.length() + 1]; + + bool ok = true; + ok = ok || s_name.copy_characters_to_buffer(buf_name, s_name.length() + 1); + ok = ok || s_passwd.copy_characters_to_buffer(buf_passwd, s_passwd.length() + 1); + ok = ok || s_gecos.copy_characters_to_buffer(buf_gecos, s_gecos.length() + 1); + ok = ok || s_dir.copy_characters_to_buffer(buf_dir, s_dir.length() + 1); + ok = ok || s_shell.copy_characters_to_buffer(buf_shell, s_shell.length() + 1); + + ASSERT(ok); + + *result = pwd; + pwd->pw_name = buf_name; + pwd->pw_passwd = buf_passwd; + pwd->pw_gecos = buf_gecos; + pwd->pw_dir = buf_dir; + pwd->pw_shell = buf_shell; +} + +int getpwnam_r(const char* name, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result) +{ + // FIXME: This is a HACK! + TemporaryChange name_change { s_name, {} }; + TemporaryChange passwd_change { s_passwd, {} }; + TemporaryChange gecos_change { s_gecos, {} }; + TemporaryChange dir_change { s_dir, {} }; + TemporaryChange shell_change { s_shell, {} }; + + setpwent(); + bool found = false; + while (auto* pw = getpwent()) { + if (!strcmp(pw->pw_name, name)) { + found = true; + break; + } + } + + if (!found) { + *result = nullptr; + return 0; + } + + const auto total_buffer_length = s_name.length() + s_passwd.length() + s_gecos.length() + s_dir.length() + s_shell.length() + 5; + if (buflen < total_buffer_length) + return ERANGE; + + construct_pwd(pwd, buf, result); + return 0; +} + +int getpwuid_r(uid_t uid, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result) +{ + // FIXME: This is a HACK! + TemporaryChange name_change { s_name, {} }; + TemporaryChange passwd_change { s_passwd, {} }; + TemporaryChange gecos_change { s_gecos, {} }; + TemporaryChange dir_change { s_dir, {} }; + TemporaryChange shell_change { s_shell, {} }; + + setpwent(); + bool found = false; + while (auto* pw = getpwent()) { + if (pw->pw_uid == uid) { + found = true; + break; + } + } + + if (!found) { + *result = nullptr; + return 0; + } + + const auto total_buffer_length = s_name.length() + s_passwd.length() + s_gecos.length() + s_dir.length() + s_shell.length() + 5; + if (buflen < total_buffer_length) + return ERANGE; + + construct_pwd(pwd, buf, result); + return 0; +} + int putpwent(const struct passwd* p, FILE* stream) { if (!p || !stream || !p->pw_passwd || !p->pw_name || !p->pw_dir || !p->pw_gecos || !p->pw_shell) { diff --git a/Userland/Libraries/LibC/pwd.h b/Userland/Libraries/LibC/pwd.h index 334b04b05f..256f23ee0d 100644 --- a/Userland/Libraries/LibC/pwd.h +++ b/Userland/Libraries/LibC/pwd.h @@ -49,4 +49,7 @@ struct passwd* getpwnam(const char* name); struct passwd* getpwuid(uid_t); int putpwent(const struct passwd* p, FILE* stream); +int getpwnam_r(const char* name, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result); +int getpwuid_r(uid_t, struct passwd* pwd, char* buf, size_t buflen, struct passwd** result); + __END_DECLS