Luna/apps/src/session.c

109 lines
2.2 KiB
C
Raw Normal View History

#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;
}