diff --git a/Libraries/LibC/grp.cpp b/Libraries/LibC/grp.cpp index 23eaef4cb0..9750389281 100644 --- a/Libraries/LibC/grp.cpp +++ b/Libraries/LibC/grp.cpp @@ -26,54 +26,51 @@ #include #include +#include #include #include #include #include -#include #include extern "C" { -#define GRDB_STR_MAX_LEN 256 +static FILE* s_stream = nullptr; +static unsigned s_line_number = 0; +static struct group s_group; -struct group_with_strings : public group { - char name_buffer[GRDB_STR_MAX_LEN]; - char passwd_buffer[GRDB_STR_MAX_LEN]; - char* members[32]; - char members_buffer[32][32]; -}; - -static FILE* __grdb_stream = nullptr; -static unsigned __grdb_line_number = 0; -static struct group_with_strings* __grdb_entry = nullptr; +static String s_name; +static String s_passwd; +static Vector s_members; +static Vector s_members_ptrs; void setgrent() { - __grdb_line_number = 0; - if (__grdb_stream) { - rewind(__grdb_stream); + s_line_number = 0; + if (s_stream) { + rewind(s_stream); } else { - __grdb_stream = fopen("/etc/group", "r"); - if (!__grdb_stream) { + s_stream = fopen("/etc/group", "r"); + if (!s_stream) { perror("open /etc/group"); } - assert(__grdb_stream); - __grdb_entry = (struct group_with_strings*)mmap_with_name(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "setgrent"); } } void endgrent() { - __grdb_line_number = 0; - if (__grdb_stream) { - fclose(__grdb_stream); - __grdb_stream = nullptr; - } - if (__grdb_entry) { - munmap(__grdb_entry, getpagesize()); - __grdb_entry = nullptr; + s_line_number = 0; + if (s_stream) { + fclose(s_stream); + s_stream = nullptr; } + + memset(&s_group, 0, sizeof(s_group)); + + s_name = {}; + s_passwd = {}; + s_members = {}; + s_members_ptrs = {}; } struct group* getgrgid(gid_t gid) @@ -96,52 +93,69 @@ struct group* getgrnam(const char* name) return nullptr; } +static bool parse_grpdb_entry(const String& line) +{ + auto parts = line.split_view(':', true); + if (parts.size() != 4) { + fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %zu parts\n", s_line_number, line.characters(), parts.size()); + return false; + } + + s_name = parts[0]; + s_passwd = parts[1]; + + auto& gid_string = parts[2]; + String members_string = parts[3]; + + auto gid = gid_string.to_uint(); + if (!gid.has_value()) { + fprintf(stderr, "getgrent(): Malformed GID on line %u\n", s_line_number); + return false; + } + + s_members = members_string.split(','); + s_members_ptrs.clear_with_capacity(); + s_members_ptrs.ensure_capacity(s_members.size() + 1); + for (auto& member : s_members) { + s_members_ptrs.append(member.characters()); + } + s_members_ptrs.append(nullptr); + + s_group.gr_gid = gid.value(); + s_group.gr_name = const_cast(s_name.characters()); + s_group.gr_passwd = const_cast(s_passwd.characters()); + s_group.gr_mem = const_cast(s_members_ptrs.data()); + + return true; +} + struct group* getgrent() { - if (!__grdb_stream) + if (!s_stream) setgrent(); - assert(__grdb_stream); - if (feof(__grdb_stream)) - return nullptr; + while (true) { + if (!s_stream || feof(s_stream)) + return nullptr; -next_entry: - char buffer[1024]; - ++__grdb_line_number; - char* s = fgets(buffer, sizeof(buffer), __grdb_stream); - if (!s) - return nullptr; - assert(__grdb_stream); - if (feof(__grdb_stream)) - return nullptr; - String line(s, Chomp); - auto parts = line.split(':', true); - if (parts.size() != 4) { - fprintf(stderr, "getgrent(): Malformed entry on line %u: '%s' has %zu parts\n", __grdb_line_number, line.characters(), parts.size()); - goto next_entry; + if (ferror(s_stream)) { + fprintf(stderr, "getgrent(): Read error: %s\n", strerror(ferror(s_stream))); + return nullptr; + } + + char buffer[1024]; + ++s_line_number; + char* s = fgets(buffer, sizeof(buffer), s_stream); + + // Silently tolerate an empty line at the end. + if ((!s || !s[0]) && feof(s_stream)) + return nullptr; + + String line(s, Chomp); + if (parse_grpdb_entry(line)) + return &s_group; + // Otherwise, proceed to the next line. } - auto& e_name = parts[0]; - auto& e_passwd = parts[1]; - auto& e_gid_string = parts[2]; - auto& e_members_string = parts[3]; - auto e_gid = e_gid_string.to_uint(); - if (!e_gid.has_value()) { - fprintf(stderr, "getgrent(): Malformed GID on line %u\n", __grdb_line_number); - goto next_entry; - } - auto members = e_members_string.split(','); - __grdb_entry->gr_gid = e_gid.value(); - __grdb_entry->gr_name = __grdb_entry->name_buffer; - __grdb_entry->gr_passwd = __grdb_entry->passwd_buffer; - for (size_t i = 0; i < members.size(); ++i) { - __grdb_entry->members[i] = __grdb_entry->members_buffer[i]; - strlcpy(__grdb_entry->members_buffer[i], members[i].characters(), sizeof(__grdb_entry->members_buffer[i])); - } - __grdb_entry->members[members.size()] = nullptr; - __grdb_entry->gr_mem = __grdb_entry->members; - strlcpy(__grdb_entry->name_buffer, e_name.characters(), GRDB_STR_MAX_LEN); - strlcpy(__grdb_entry->passwd_buffer, e_passwd.characters(), GRDB_STR_MAX_LEN); - return __grdb_entry; } int initgroups(const char* user, gid_t extra_gid) diff --git a/Libraries/LibC/netdb.cpp b/Libraries/LibC/netdb.cpp index fe5b6df7f1..e9257d694c 100644 --- a/Libraries/LibC/netdb.cpp +++ b/Libraries/LibC/netdb.cpp @@ -41,12 +41,10 @@ extern "C" { int h_errno; static hostent __gethostbyname_buffer; -static char __gethostbyname_name_buffer[512]; static in_addr_t __gethostbyname_address; static in_addr_t* __gethostbyname_address_list_buffer[2]; static hostent __gethostbyaddr_buffer; -static char __gethostbyaddr_name_buffer[512]; static in_addr_t* __gethostbyaddr_address_list_buffer[2]; //Get service entry buffers and file information for the getservent() family of functions @@ -55,8 +53,8 @@ static const char* services_path = "/etc/services"; static bool fill_getserv_buffers(char* line, ssize_t read); static servent __getserv_buffer; -static char __getserv_name_buffer[512]; -static char __getserv_protocol_buffer[10]; +static String __getserv_name_buffer; +static String __getserv_protocol_buffer; static int __getserv_port_buffer; static Vector __getserv_alias_list_buffer; static Vector __getserv_alias_list; @@ -69,7 +67,7 @@ static const char* protocols_path = "/etc/protocols"; static bool fill_getproto_buffers(char* line, ssize_t read); static protoent __getproto_buffer; -static char __getproto_name_buffer[512]; +static String __getproto_name_buffer; static Vector __getproto_alias_list_buffer; static Vector __getproto_alias_list; static int __getproto_protocol_buffer; @@ -98,12 +96,13 @@ static int connect_to_lookup_server() hostent* gethostbyname(const char* name) { + static String s_name_buffer; + auto ipv4_address = IPv4Address::from_string(name); + if (ipv4_address.has_value()) { - auto ip4_string = ipv4_address.value().to_string(); - ASSERT(ip4_string.length() < sizeof(__gethostbyname_name_buffer)); - strlcpy(__gethostbyname_name_buffer, ip4_string.characters(), sizeof(__gethostbyname_name_buffer)); - __gethostbyname_buffer.h_name = __gethostbyname_name_buffer; + s_name_buffer = ipv4_address.value().to_string(); + __gethostbyname_buffer.h_name = const_cast(s_name_buffer.characters()); __gethostbyname_buffer.h_aliases = nullptr; __gethostbyname_buffer.h_addrtype = AF_INET; new (&__gethostbyname_address) IPv4Address(ipv4_address.value()); @@ -152,9 +151,8 @@ hostent* gethostbyname(const char* name) if (rc <= 0) return nullptr; - strlcpy(__gethostbyname_name_buffer, name, sizeof(__gethostbyaddr_name_buffer)); - - __gethostbyname_buffer.h_name = __gethostbyname_name_buffer; + s_name_buffer = name; + __gethostbyname_buffer.h_name = const_cast(s_name_buffer.characters()); __gethostbyname_buffer.h_aliases = nullptr; __gethostbyname_buffer.h_addrtype = AF_INET; __gethostbyname_address_list_buffer[0] = &__gethostbyname_address; @@ -167,6 +165,8 @@ hostent* gethostbyname(const char* name) hostent* gethostbyaddr(const void* addr, socklen_t addr_size, int type) { + static String s_name_buffer; + if (type != AF_INET) { errno = EAFNOSUPPORT; return nullptr; @@ -214,11 +214,8 @@ hostent* gethostbyaddr(const void* addr, socklen_t addr_size, int type) if (responses.is_empty()) return nullptr; - auto& response = responses[0]; - - strlcpy(__gethostbyaddr_name_buffer, response.characters(), sizeof(__gethostbyaddr_name_buffer)); - - __gethostbyaddr_buffer.h_name = __gethostbyaddr_name_buffer; + s_name_buffer = responses[0]; + __gethostbyaddr_buffer.h_name = const_cast(s_name_buffer.characters()); __gethostbyaddr_buffer.h_aliases = nullptr; __gethostbyaddr_buffer.h_addrtype = AF_INET; // FIXME: Should we populate the hostent's address list here with a sockaddr_in for the provided host? @@ -275,9 +272,9 @@ struct servent* getservent() if (!fill_getserv_buffers(line, read)) return nullptr; - __getserv_buffer.s_name = __getserv_name_buffer; + __getserv_buffer.s_name = const_cast(__getserv_name_buffer.characters()); __getserv_buffer.s_port = __getserv_port_buffer; - __getserv_buffer.s_proto = __getserv_protocol_buffer; + __getserv_buffer.s_proto = const_cast(__getserv_protocol_buffer.characters()); __getserv_alias_list.clear(); for (auto& alias : __getserv_alias_list_buffer) { @@ -373,12 +370,7 @@ static bool fill_getserv_buffers(char* line, ssize_t read) perror("malformed services file: entry"); return false; } - if (sizeof(__getserv_name_buffer) >= split_line[0].length() + 1) { - strlcpy(__getserv_name_buffer, split_line[0].characters(), sizeof(__getserv_name_buffer)); - } else { - perror("invalid buffer length: service name"); - return false; - } + __getserv_name_buffer = split_line[0]; auto port_protocol_split = String(split_line[1]).split('/'); if (port_protocol_split.size() < 2) { @@ -396,13 +388,7 @@ static bool fill_getserv_buffers(char* line, ssize_t read) port_protocol_split[1].replace("\t", "", true); port_protocol_split[1].replace("\n", "", true); - if (sizeof(__getserv_protocol_buffer) >= port_protocol_split[1].length()) { - strlcpy(__getserv_protocol_buffer, port_protocol_split[1].characters(), sizeof(__getserv_protocol_buffer)); - } else { - perror("malformed services file: protocol"); - return false; - } - + __getserv_protocol_buffer = port_protocol_split[1]; __getserv_alias_list_buffer.clear(); //If there are aliases for the service, we will fill the alias list buffer. @@ -468,7 +454,7 @@ struct protoent* getprotoent() if (!fill_getproto_buffers(line, read)) return nullptr; - __getproto_buffer.p_name = __getproto_name_buffer; + __getproto_buffer.p_name = const_cast(__getproto_name_buffer.characters()); __getproto_buffer.p_proto = __getproto_protocol_buffer; __getproto_alias_list.clear(); @@ -565,12 +551,7 @@ static bool fill_getproto_buffers(char* line, ssize_t read) perror("malformed protocols file: entry"); return false; } - if (sizeof(__getproto_name_buffer) >= split_line[0].length() + 1) { - strlcpy(__getproto_name_buffer, split_line[0].characters(), sizeof(__getproto_name_buffer)); - } else { - perror("invalid buffer length: protocol name"); - return false; - } + __getproto_name_buffer = split_line[0]; auto number = split_line[1].to_int(); if (!number.has_value()) diff --git a/Libraries/LibC/pwd.cpp b/Libraries/LibC/pwd.cpp index 70716709c6..7af0d67d68 100644 --- a/Libraries/LibC/pwd.cpp +++ b/Libraries/LibC/pwd.cpp @@ -26,55 +26,53 @@ #include #include +#include #include #include #include #include -#include #include extern "C" { -#define PWDB_STR_MAX_LEN 256 +static FILE* s_stream = nullptr; +static unsigned s_line_number = 0; +static struct passwd s_passwd_entry; -struct passwd_with_strings : public passwd { - char name_buffer[PWDB_STR_MAX_LEN]; - char passwd_buffer[PWDB_STR_MAX_LEN]; - char gecos_buffer[PWDB_STR_MAX_LEN]; - char dir_buffer[PWDB_STR_MAX_LEN]; - char shell_buffer[PWDB_STR_MAX_LEN]; -}; - -static FILE* __pwdb_stream = nullptr; -static unsigned __pwdb_line_number = 0; -static struct passwd_with_strings* __pwdb_entry = nullptr; +static String s_name; +static String s_passwd; +static String s_gecos; +static String s_dir; +static String s_shell; void setpwent() { - __pwdb_line_number = 0; - if (__pwdb_stream) { - rewind(__pwdb_stream); + s_line_number = 0; + if (s_stream) { + rewind(s_stream); } else { - __pwdb_stream = fopen("/etc/passwd", "r"); - if (!__pwdb_stream) { + s_stream = fopen("/etc/passwd", "r"); + if (!s_stream) { perror("open /etc/passwd"); } - assert(__pwdb_stream); - __pwdb_entry = (struct passwd_with_strings*)mmap_with_name(nullptr, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0, "setpwent"); } } void endpwent() { - __pwdb_line_number = 0; - if (__pwdb_stream) { - fclose(__pwdb_stream); - __pwdb_stream = nullptr; - } - if (__pwdb_entry) { - munmap(__pwdb_entry, getpagesize()); - __pwdb_entry = nullptr; + s_line_number = 0; + if (s_stream) { + fclose(s_stream); + s_stream = nullptr; } + + memset(&s_passwd_entry, 0, sizeof(s_passwd_entry)); + + s_name = {}; + s_passwd = {}; + s_gecos = {}; + s_dir = {}; + s_shell = {}; } struct passwd* getpwuid(uid_t uid) @@ -97,61 +95,71 @@ struct passwd* getpwnam(const char* name) return nullptr; } +static bool parse_pwddb_entry(const String& line) +{ + auto parts = line.split_view(':', true); + if (parts.size() != 7) { + fprintf(stderr, "getpwent(): Malformed entry on line %u\n", s_line_number); + return false; + } + + s_name = parts[0]; + s_passwd = parts[1]; + auto& uid_string = parts[2]; + auto& gid_string = parts[3]; + s_gecos = parts[4]; + s_dir = parts[5]; + s_shell = parts[6]; + + auto uid = uid_string.to_uint(); + if (!uid.has_value()) { + fprintf(stderr, "getpwent(): Malformed UID on line %u\n", s_line_number); + return false; + } + auto gid = gid_string.to_uint(); + if (!gid.has_value()) { + fprintf(stderr, "getpwent(): Malformed GID on line %u\n", s_line_number); + return false; + } + + s_passwd_entry.pw_name = const_cast(s_name.characters()); + s_passwd_entry.pw_passwd = const_cast(s_passwd.characters()); + s_passwd_entry.pw_uid = uid.value(); + s_passwd_entry.pw_gid = gid.value(); + s_passwd_entry.pw_gecos = const_cast(s_gecos.characters()); + s_passwd_entry.pw_dir = const_cast(s_dir.characters()); + s_passwd_entry.pw_shell = const_cast(s_shell.characters()); + + return true; +} + struct passwd* getpwent() { - if (!__pwdb_stream) + if (!s_stream) setpwent(); - assert(__pwdb_stream); - if (feof(__pwdb_stream)) - return nullptr; + while (true) { + if (!s_stream || feof(s_stream)) + return nullptr; -next_entry: - char buffer[1024]; - ++__pwdb_line_number; - char* s = fgets(buffer, sizeof(buffer), __pwdb_stream); - if (!s) - return nullptr; - assert(__pwdb_stream); - if (feof(__pwdb_stream)) - return nullptr; - String line(s, Chomp); - auto parts = line.split(':', true); - if (parts.size() != 7) { - fprintf(stderr, "getpwent(): Malformed entry on line %u\n", __pwdb_line_number); - goto next_entry; - } - auto& e_name = parts[0]; - auto& e_passwd = parts[1]; - auto& e_uid_string = parts[2]; - auto& e_gid_string = parts[3]; - auto& e_gecos = parts[4]; - auto& e_dir = parts[5]; - auto& e_shell = parts[6]; - auto e_uid = e_uid_string.to_uint(); - if (!e_uid.has_value()) { - fprintf(stderr, "getpwent(): Malformed UID on line %u\n", __pwdb_line_number); - goto next_entry; - } - auto e_gid = e_gid_string.to_uint(); - if (!e_gid.has_value()) { - fprintf(stderr, "getpwent(): Malformed GID on line %u\n", __pwdb_line_number); - goto next_entry; - } - __pwdb_entry->pw_uid = e_uid.value(); - __pwdb_entry->pw_gid = e_gid.value(); - __pwdb_entry->pw_name = __pwdb_entry->name_buffer; - __pwdb_entry->pw_passwd = __pwdb_entry->passwd_buffer; - __pwdb_entry->pw_gecos = __pwdb_entry->gecos_buffer; - __pwdb_entry->pw_dir = __pwdb_entry->dir_buffer; - __pwdb_entry->pw_shell = __pwdb_entry->shell_buffer; + if (ferror(s_stream)) { + fprintf(stderr, "getpwent(): Read error: %s\n", strerror(ferror(s_stream))); + return nullptr; + } - strlcpy(__pwdb_entry->name_buffer, e_name.characters(), PWDB_STR_MAX_LEN); - strlcpy(__pwdb_entry->passwd_buffer, e_passwd.characters(), PWDB_STR_MAX_LEN); - strlcpy(__pwdb_entry->gecos_buffer, e_gecos.characters(), PWDB_STR_MAX_LEN); - strlcpy(__pwdb_entry->dir_buffer, e_dir.characters(), PWDB_STR_MAX_LEN); - strlcpy(__pwdb_entry->shell_buffer, e_shell.characters(), PWDB_STR_MAX_LEN); - return __pwdb_entry; + char buffer[1024]; + ++s_line_number; + char* s = fgets(buffer, sizeof(buffer), s_stream); + + // Silently tolerate an empty line at the end. + if ((!s || !s[0]) && feof(s_stream)) + return nullptr; + + String line(s, Chomp); + if (parse_pwddb_entry(line)) + return &s_passwd_entry; + // Otherwise, proceed to the next line. + } } int putpwent(const struct passwd* p, FILE* stream) diff --git a/Libraries/LibC/unistd.cpp b/Libraries/LibC/unistd.cpp index 04a0fd3289..94ccc26975 100644 --- a/Libraries/LibC/unistd.cpp +++ b/Libraries/LibC/unistd.cpp @@ -557,14 +557,14 @@ int set_process_icon(int icon_id) char* getlogin() { - static char __getlogin_buffer[256]; - if (auto* passwd = getpwuid(getuid())) { - strlcpy(__getlogin_buffer, passwd->pw_name, sizeof(__getlogin_buffer)); + static String buffer; + if (buffer.is_null()) { + if (auto* passwd = getpwuid(getuid())) { + buffer = String(passwd->pw_name); + } endpwent(); - return __getlogin_buffer; } - endpwent(); - return nullptr; + return const_cast(buffer.characters()); } int ftruncate(int fd, off_t length)