diff --git a/initrd/etc/passwd b/initrd/etc/passwd new file mode 100644 index 00000000..1abe67ef --- /dev/null +++ b/initrd/etc/passwd @@ -0,0 +1,2 @@ +root:toor:0:0:Administrator:/:/bin/sh +selene:moon:1000:1000:User:/home/selene:/bin/sh diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index e63b4626..0beb030f 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES src/dirent.cpp src/setjmp.cpp src/env.cpp + src/pwd.cpp src/sys/stat.cpp src/sys/mman.cpp src/sys/wait.cpp diff --git a/libc/include/pwd.h b/libc/include/pwd.h new file mode 100644 index 00000000..494f6e4c --- /dev/null +++ b/libc/include/pwd.h @@ -0,0 +1,43 @@ +/* pwd.h: Password file parsing. */ + +#ifndef _PWD_H +#define _PWD_H + +#include + +struct passwd +{ + char* pw_name; + char* pw_passwd; + uid_t pw_uid; + gid_t pw_gid; + char* pw_gecos; + char* pw_dir; + char* pw_shell; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Read the next entry from the password file. */ + struct passwd* getpwent(void); + + /* Find the entry with a matching username in the password file. */ + struct passwd* getpwnam(const char* name); + + /* Find the entry with a matching user ID in the password file. */ + struct passwd* getpwuid(uid_t uid); + + /* Rewind the password file. */ + void setpwent(void); + + /* End password file parsing. */ + void endpwent(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/src/pwd.cpp b/libc/src/pwd.cpp new file mode 100644 index 00000000..d39990f4 --- /dev/null +++ b/libc/src/pwd.cpp @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +static struct passwd pwd; +static FILE* f { nullptr }; +static char buf[4096]; + +extern "C" +{ + struct passwd* getpwent() + { + if (!f) + { + f = fopen("/etc/passwd", "r"); + if (!f) return nullptr; + } + + while (true) + { + char* rc = fgets(buf, sizeof(buf), f); + if (!rc) return nullptr; + + char* name = strtok(rc, ":\n"); + if (!name) continue; + + char* passwd = strtok(nullptr, ":\n"); + if (!passwd) continue; + + char* uid = strtok(nullptr, ":\n"); + if (!uid) continue; + + char* gid = strtok(nullptr, ":\n"); + if (!gid) continue; + + char* gecos = strtok(nullptr, ":\n"); + if (!gecos) continue; + + char* dir = strtok(nullptr, ":\n"); + if (!dir) continue; + + char* shell = strtok(nullptr, ":\n"); + if (!shell) continue; + + pwd.pw_name = name; + pwd.pw_passwd = passwd; + pwd.pw_uid = (uid_t)strtoul(uid, NULL, 10); + pwd.pw_gid = (gid_t)strtoul(gid, NULL, 10); + pwd.pw_gecos = gecos; + pwd.pw_dir = dir; + pwd.pw_shell = shell; + + return &pwd; + } + } + + struct passwd* getpwnam(const char* name) + { + setpwent(); + + struct passwd* entry; + + while ((entry = getpwent())) + { + if (!strcmp(entry->pw_name, name)) + { + endpwent(); + return entry; + } + } + + endpwent(); + return entry; + } + + struct passwd* getpwuid(uid_t uid) + { + setpwent(); + + struct passwd* entry; + + while ((entry = getpwent())) + { + if (entry->pw_uid == uid) + { + endpwent(); + return entry; + } + } + + endpwent(); + return entry; + } + + void setpwent() + { + if (f) rewind(f); + } + + void endpwent() + { + if (f) + { + fclose(f); + f = nullptr; + } + } +}