base+su+libc: Add support for a shadow file and use it by default
All checks were successful
Build and test / build (push) Successful in 1m39s

This commit is contained in:
apio 2024-04-10 22:37:36 +02:00
parent 6968961d5c
commit 701dc30221
Signed by: apio
GPG Key ID: B8A7D06E42258954
7 changed files with 194 additions and 5 deletions

View File

@ -3,6 +3,7 @@
#include <grp.h> #include <grp.h>
#include <os/ArgumentParser.h> #include <os/ArgumentParser.h>
#include <pwd.h> #include <pwd.h>
#include <shadow.h>
#include <signal.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -148,7 +149,25 @@ Result<int> luna_main(int argc, char** argv)
{ {
signal(SIGTTOU, SIG_IGN); 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); fprintf(stderr, "%s: %s's password is disabled!\n", argv[0], entry->pw_name);
return 1; return 1;
@ -157,7 +176,7 @@ Result<int> luna_main(int argc, char** argv)
char* pass = getpass(); char* pass = getpass();
if (!pass) return 1; if (!pass) return 1;
if (strcmp(pass, entry->pw_passwd)) if (strcmp(pass, passwd))
{ {
fprintf(stderr, "%s: wrong password!\n", argv[0]); fprintf(stderr, "%s: wrong password!\n", argv[0]);
return 1; return 1;

View File

@ -1,3 +1,3 @@
root:toor:0:0:Administrator:/:/usr/bin/sh root:x:0:0:Administrator:/:/usr/bin/sh
wind:!:2:2:Window Manager:/:/usr/bin/init wind:x:2:2:Window Manager:/:/usr/bin/init
selene:moon:1000:1000:User:/home/selene:/usr/bin/sh selene:x:1000:1000:User:/home/selene:/usr/bin/sh

3
base/etc/shadow Normal file
View File

@ -0,0 +1,3 @@
root:toor:0:0:99999:7:::
wind:!:0:0:99999:7:::
selene:moon:0:0:99999:7:::

View File

@ -27,6 +27,7 @@ set(SOURCES
src/math.cpp src/math.cpp
src/pty.cpp src/pty.cpp
src/utmp.cpp src/utmp.cpp
src/shadow.cpp
src/sys/stat.cpp src/sys/stat.cpp
src/sys/mman.cpp src/sys/mman.cpp
src/sys/wait.cpp src/sys/wait.cpp

48
libc/include/shadow.h Normal file
View File

@ -0,0 +1,48 @@
/* shadow.h: Password file parsing. */
#ifndef _SHADOW_H
#define _SHADOW_H
#include <stdio.h>
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

116
libc/src/shadow.cpp Normal file
View File

@ -0,0 +1,116 @@
#include <fcntl.h>
#include <shadow.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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;
}
}
}

View File

@ -17,6 +17,8 @@ cmake --install $LUNA_BUILD_DIR
chmod a+s base/usr/bin/su chmod a+s base/usr/bin/su
chmod 600 base/etc/shadow
mkdir -p base/home/selene mkdir -p base/home/selene
mkdir -p base/dev mkdir -p base/dev