From 701dc30221d3c9de0e137374c36dd15ee904467f Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 10 Apr 2024 22:37:36 +0200 Subject: [PATCH] base+su+libc: Add support for a shadow file and use it by default --- apps/su.cpp | 23 ++++++++- base/etc/passwd | 6 +-- base/etc/shadow | 3 ++ libc/CMakeLists.txt | 1 + libc/include/shadow.h | 48 +++++++++++++++++ libc/src/shadow.cpp | 116 ++++++++++++++++++++++++++++++++++++++++++ tools/install.sh | 2 + 7 files changed, 194 insertions(+), 5 deletions(-) create mode 100644 base/etc/shadow create mode 100644 libc/include/shadow.h create mode 100644 libc/src/shadow.cpp diff --git a/apps/su.cpp b/apps/su.cpp index a2d9aa56..0787fa16 100644 --- a/apps/su.cpp +++ b/apps/su.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -148,7 +149,25 @@ Result luna_main(int argc, char** argv) { signal(SIGTTOU, SIG_IGN); - if (!strcmp(entry->pw_passwd, "!")) + const char* passwd = entry->pw_passwd; + + // If the user's password entry is 'x', read their password from the shadow file instead. + if (!strcmp(entry->pw_passwd, "x")) + { + struct spwd* sp = getspnam(name.chars()); + + if (!sp) + { + fprintf(stderr, "%s: user %s not found in shadow file!\n", argv[0], name.chars()); + return 1; + } + + endspent(); + + passwd = sp->sp_pwdp; + } + + if (!strcmp(passwd, "!")) { fprintf(stderr, "%s: %s's password is disabled!\n", argv[0], entry->pw_name); return 1; @@ -157,7 +176,7 @@ Result luna_main(int argc, char** argv) char* pass = getpass(); if (!pass) return 1; - if (strcmp(pass, entry->pw_passwd)) + if (strcmp(pass, passwd)) { fprintf(stderr, "%s: wrong password!\n", argv[0]); return 1; diff --git a/base/etc/passwd b/base/etc/passwd index 65dab9f1..12be7947 100644 --- a/base/etc/passwd +++ b/base/etc/passwd @@ -1,3 +1,3 @@ -root:toor:0:0:Administrator:/:/usr/bin/sh -wind:!:2:2:Window Manager:/:/usr/bin/init -selene:moon:1000:1000:User:/home/selene:/usr/bin/sh +root:x:0:0:Administrator:/:/usr/bin/sh +wind:x:2:2:Window Manager:/:/usr/bin/init +selene:x:1000:1000:User:/home/selene:/usr/bin/sh diff --git a/base/etc/shadow b/base/etc/shadow new file mode 100644 index 00000000..754da31f --- /dev/null +++ b/base/etc/shadow @@ -0,0 +1,3 @@ +root:toor:0:0:99999:7::: +wind:!:0:0:99999:7::: +selene:moon:0:0:99999:7::: diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt index 4788422d..dbf0b98a 100644 --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -27,6 +27,7 @@ set(SOURCES src/math.cpp src/pty.cpp src/utmp.cpp + src/shadow.cpp src/sys/stat.cpp src/sys/mman.cpp src/sys/wait.cpp diff --git a/libc/include/shadow.h b/libc/include/shadow.h new file mode 100644 index 00000000..56bacb9e --- /dev/null +++ b/libc/include/shadow.h @@ -0,0 +1,48 @@ +/* shadow.h: Password file parsing. */ + +#ifndef _SHADOW_H +#define _SHADOW_H + +#include + +struct spwd +{ + char* sp_namp; + char* sp_pwdp; + long sp_lstchg; + long sp_min; + long sp_max; + long sp_warn; + long sp_inact; + long sp_expire; + unsigned long sp_flag; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Read the next entry from the shadow file. */ + struct spwd* getspent(); + + /* Find the entry with a matching username in the shadow file. */ + struct spwd* getspnam(const char* name); + + /* Read the next entry from the shadow file (reentrant version). */ + int getspent_r(struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp); + + /* Read the next entry from a shadow file (reentrant version). */ + int fgetspent_r(FILE* stream, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp); + + /* Rewind the shadow file. */ + void setspent(void); + + /* End shadow file parsing. */ + void endspent(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libc/src/shadow.cpp b/libc/src/shadow.cpp new file mode 100644 index 00000000..4b3eaa9a --- /dev/null +++ b/libc/src/shadow.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include + +static struct spwd spwd; +static FILE* f { nullptr }; +static char s_buf[4096]; + +extern char* _strtok_once(char* str, const char* delim); + +extern "C" +{ + struct spwd* getspent() + { + struct spwd* result; + + getspent_r(&spwd, s_buf, sizeof(s_buf), &result); + + return result; + } + + int getspent_r(struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp) + { + *spbufp = nullptr; + + if (!f) + { + f = fopen("/etc/shadow", "r"); + if (!f) return 0; + fcntl(fileno(f), F_SETFD, FD_CLOEXEC); + } + + return fgetspent_r(f, spbuf, buf, buflen, spbufp); + } + + int fgetspent_r(FILE* stream, struct spwd* spbuf, char* buf, size_t buflen, struct spwd** spbufp) + { + *spbufp = nullptr; + + while (true) + { + char* rc = fgets(buf, buflen, stream); + if (!rc) return -1; + + char* name = _strtok_once(rc, ":\n"); + if (!name) continue; + + char* passwd = _strtok_once(nullptr, ":\n"); + if (!passwd) continue; + + char* lstchg = _strtok_once(nullptr, ":\n"); + if (!lstchg) continue; + + char* min = _strtok_once(nullptr, ":\n"); + if (!min) continue; + + char* max = _strtok_once(nullptr, ":\n"); + if (!max) continue; + + char* warn = _strtok_once(nullptr, ":\n"); + if (!warn) continue; + + char* inact = _strtok_once(nullptr, ":\n"); + if (!inact) continue; + + char* expire = _strtok_once(nullptr, ":\n"); + if (!expire) continue; + + char* flag = _strtok_once(nullptr, ":\n"); + if (!flag) continue; + + spbuf->sp_namp = name; + spbuf->sp_pwdp = passwd; + spbuf->sp_lstchg = (long)strtol(lstchg, nullptr, 10); + spbuf->sp_min = (long)strtol(min, nullptr, 10); + spbuf->sp_max = (long)strtol(max, nullptr, 10); + spbuf->sp_warn = (long)strtol(warn, nullptr, 10); + spbuf->sp_inact = (long)strtol(inact, nullptr, 10); + spbuf->sp_expire = (long)strtol(expire, nullptr, 10); + spbuf->sp_flag = (unsigned long)strtoul(flag, nullptr, 10); + + *spbufp = spbuf; + return 0; + } + } + + struct spwd* getspnam(const char* name) + { + setspent(); + + struct spwd* entry; + + while ((entry = getspent())) + { + if (!strcmp(entry->sp_namp, name)) { return entry; } + } + + return entry; + } + + void setspent() + { + if (f) rewind(f); + } + + void endspent() + { + if (f) + { + fclose(f); + f = nullptr; + } + } +} diff --git a/tools/install.sh b/tools/install.sh index c915e7ca..92c4b805 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -17,6 +17,8 @@ cmake --install $LUNA_BUILD_DIR chmod a+s base/usr/bin/su +chmod 600 base/etc/shadow + mkdir -p base/home/selene mkdir -p base/dev