apps: Add a new session program which manages user login

This commit is contained in:
apio 2022-10-28 21:56:52 +02:00
parent 702cc0442c
commit 0b838572e1
3 changed files with 118 additions and 3 deletions

View File

@ -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_DIR := $(LUNA_ROOT)/apps
APPS_SRC := $(APPS_DIR)/src APPS_SRC := $(APPS_DIR)/src

View File

@ -41,7 +41,13 @@ int main()
{ {
if (getpid() != 1) 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; return 1;
} }
@ -57,7 +63,7 @@ int main()
} }
if (child == 0) if (child == 0)
{ {
char* argv[] = {"/bin/sh", NULL}; char* argv[] = {"/bin/session", NULL};
execv(argv[0], argv); execv(argv[0], argv);
perror("execv"); perror("execv");
return 1; return 1;

109
apps/src/session.c Normal file
View File

@ -0,0 +1,109 @@
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
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;
}