From 0b838572e120dfcb772ac2a3176a421afa916800 Mon Sep 17 00:00:00 2001 From: apio Date: Fri, 28 Oct 2022 21:56:52 +0200 Subject: [PATCH] apps: Add a new session program which manages user login --- apps/Makefile | 2 +- apps/src/init.c | 10 ++++- apps/src/session.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 apps/src/session.c diff --git a/apps/Makefile b/apps/Makefile index 76046766..f8233bfc 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,4 +1,4 @@ -APPS := init sh uname uptime hello ps ls args cat stat su +APPS := init sh uname uptime hello ps ls args cat stat su session APPS_DIR := $(LUNA_ROOT)/apps APPS_SRC := $(APPS_DIR)/src diff --git a/apps/src/init.c b/apps/src/init.c index ff4bd6b3..96b665ab 100644 --- a/apps/src/init.c +++ b/apps/src/init.c @@ -41,7 +41,13 @@ int main() { if (getpid() != 1) { - fprintf(stderr, "init should be started as PID 1\n"); + fprintf(stderr, "init must be started as PID 1\n"); + return 1; + } + + if (getuid() != 0) + { + fprintf(stderr, "init must be started as root\n"); return 1; } @@ -57,7 +63,7 @@ int main() } if (child == 0) { - char* argv[] = {"/bin/sh", NULL}; + char* argv[] = {"/bin/session", NULL}; execv(argv[0], argv); perror("execv"); return 1; diff --git a/apps/src/session.c b/apps/src/session.c new file mode 100644 index 00000000..116e01a5 --- /dev/null +++ b/apps/src/session.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include + +static char* echoing_fgets(char* buf, size_t size, FILE* stream) +{ + char* s = buf; + memset(buf, 0, size); + while (size) + { + int c = fgetc(stream); + if (c == EOF) + { + if (ferror(stream)) return NULL; + if (feof(stream)) + { + if (s != buf) return s; + else + return NULL; + }; + } + size--; + *buf = (char)c; + buf++; + *buf = 0; + putchar((char)c); + if ((char)c == '\n') return s; + } + return s; +} + +static void strip_newline(char* str) +{ + size_t len = strlen(str); + if (str[len - 1] == '\n') str[len - 1] = 0; +} + +static void login_as(struct passwd* user) +{ + pid_t child = fork(); + if (child < 0) + { + perror("fork"); + return; + } + if (child == 0) + { + setuid(user->pw_uid); + setgid(user->pw_gid); + char* argv[] = {user->pw_shell, NULL}; + execv(argv[0], argv); + perror("execv"); + exit(EXIT_FAILURE); + } + wait(NULL); +} + +static int login() +{ + printf("Username: "); + char username[BUFSIZ]; + echoing_fgets(username, BUFSIZ, stdin); + strip_newline(username); + if (strcmp("exit", username) == 0) return 1; + struct passwd* user = getpwnam(username); + if (!user) + { + if (errno) perror("getpwnam"); + else + printf("Unknown user %s\n", username); + return 0; + } + printf("Password: "); + char password[BUFSIZ]; + fgets(password, BUFSIZ, stdin); + strip_newline(password); + puts("\n"); + if (strcmp(user->pw_passwd, password) == 0) + { + login_as(user); + puts("logout\n"); + } + else + puts("Invalid password.\n"); + return 0; +} + +int main(int argc, char** argv) +{ + if (getuid() != 0) + { + fprintf(stderr, + "%s must be run as root.\nYou are probably looking for the 'su' command, which lets you switch users " + "once logged in.\n", + argv[0]); + return EXIT_FAILURE; + } + + for (;;) + { + if (login()) return EXIT_SUCCESS; + } + + (void)argc; +} \ No newline at end of file