2023-10-14 18:47:56 +00:00
|
|
|
#include <fcntl.h>
|
2023-04-08 11:50:18 +00:00
|
|
|
#include <os/ArgumentParser.h>
|
2023-04-08 14:31:33 +00:00
|
|
|
#include <pwd.h>
|
2023-07-12 11:49:37 +00:00
|
|
|
#include <signal.h>
|
2023-04-08 11:50:18 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2023-07-12 17:23:06 +00:00
|
|
|
#include <termios.h>
|
2023-04-08 11:50:18 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
static struct termios orig;
|
2023-10-14 18:47:56 +00:00
|
|
|
static int fd = -1;
|
2023-04-09 09:24:34 +00:00
|
|
|
|
|
|
|
void restore_terminal()
|
|
|
|
{
|
2023-10-14 18:47:56 +00:00
|
|
|
tcsetattr(fd, TCSANOW, &orig);
|
2023-04-09 09:24:34 +00:00
|
|
|
}
|
|
|
|
|
2023-07-12 11:52:49 +00:00
|
|
|
void signal_handler(int signo)
|
2023-07-12 11:49:37 +00:00
|
|
|
{
|
|
|
|
restore_terminal();
|
2023-07-12 11:52:49 +00:00
|
|
|
raise(signo);
|
2023-07-12 11:49:37 +00:00
|
|
|
}
|
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
char* getpass()
|
|
|
|
{
|
2023-10-14 18:47:56 +00:00
|
|
|
FILE* f = fopen("/dev/tty", "r");
|
|
|
|
if (!f)
|
2023-07-12 11:49:37 +00:00
|
|
|
{
|
2023-10-14 18:47:56 +00:00
|
|
|
perror("Failed to open /dev/tty");
|
2023-07-12 11:49:37 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-10-14 18:47:56 +00:00
|
|
|
fd = fileno(f);
|
|
|
|
|
|
|
|
tcsetpgrp(fd, getpgid(0));
|
2023-07-12 11:49:37 +00:00
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
fputs("Password: ", stdout);
|
2023-07-21 22:02:12 +00:00
|
|
|
fflush(stdout);
|
2023-04-09 09:24:34 +00:00
|
|
|
|
2023-10-14 18:47:56 +00:00
|
|
|
if (tcgetattr(fd, &orig) < 0)
|
2023-04-09 09:24:34 +00:00
|
|
|
{
|
2023-07-12 17:23:06 +00:00
|
|
|
perror("tcgetattr");
|
2023-10-14 18:47:56 +00:00
|
|
|
fclose(f);
|
|
|
|
fd = -1;
|
2023-04-09 09:24:34 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-07-12 11:49:37 +00:00
|
|
|
struct sigaction sa;
|
2023-07-12 11:52:49 +00:00
|
|
|
sa.sa_handler = signal_handler;
|
2023-07-12 11:49:37 +00:00
|
|
|
sigemptyset(&sa.sa_mask);
|
|
|
|
sa.sa_flags = SA_RESETHAND;
|
|
|
|
sigaction(SIGINT, &sa, NULL);
|
2023-07-12 11:52:49 +00:00
|
|
|
sigaction(SIGTERM, &sa, NULL);
|
|
|
|
sigaction(SIGQUIT, &sa, NULL);
|
2023-07-12 11:49:37 +00:00
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
atexit(restore_terminal);
|
|
|
|
|
|
|
|
struct termios tc = orig;
|
|
|
|
tc.c_lflag &= ~ECHO;
|
2023-10-14 18:47:56 +00:00
|
|
|
if (tcsetattr(fd, TCSANOW, &tc) < 0)
|
2023-04-09 09:24:34 +00:00
|
|
|
{
|
2023-07-12 17:23:06 +00:00
|
|
|
perror("tcsetattr");
|
2023-10-14 18:47:56 +00:00
|
|
|
fclose(f);
|
|
|
|
fd = -1;
|
2023-04-09 09:24:34 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2023-05-20 13:36:30 +00:00
|
|
|
static char buf[BUFSIZ];
|
2023-10-14 18:47:56 +00:00
|
|
|
char* rc = fgets(buf, sizeof(buf), f);
|
2023-04-09 09:24:34 +00:00
|
|
|
|
|
|
|
restore_terminal();
|
|
|
|
putchar('\n');
|
|
|
|
|
2023-10-14 18:47:56 +00:00
|
|
|
fclose(f);
|
|
|
|
fd = -1;
|
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
perror("fgets");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* newline = strrchr(rc, '\n');
|
|
|
|
if (newline) *newline = 0;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2023-04-13 15:04:59 +00:00
|
|
|
Result<int> luna_main(int argc, char** argv)
|
2023-04-08 11:50:18 +00:00
|
|
|
{
|
2023-04-08 14:31:33 +00:00
|
|
|
StringView name;
|
2023-05-06 20:03:50 +00:00
|
|
|
bool prompt_password;
|
2023-05-11 18:11:09 +00:00
|
|
|
bool login;
|
2023-04-08 11:50:18 +00:00
|
|
|
|
|
|
|
if (geteuid() != 0)
|
|
|
|
{
|
2023-05-06 20:03:50 +00:00
|
|
|
fprintf(stderr, "%s must be setuid root!\n", argv[0]);
|
2023-04-08 11:50:18 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
os::ArgumentParser parser;
|
2023-04-24 20:24:07 +00:00
|
|
|
parser.add_description("Switch to a different user (by default, root)."_sv);
|
2023-04-28 14:33:05 +00:00
|
|
|
parser.add_system_program_info("su"_sv);
|
2023-04-24 20:24:07 +00:00
|
|
|
parser.add_positional_argument(name, "name"_sv, "root"_sv);
|
2023-05-06 20:03:50 +00:00
|
|
|
parser.add_switch_argument(prompt_password, 'p', "prompt", "prompt for a password even if running as root");
|
2023-05-11 18:11:09 +00:00
|
|
|
parser.add_switch_argument(login, 'l', "login"_sv, "change directory to the user's home and start a login shell");
|
2023-04-08 11:50:18 +00:00
|
|
|
parser.parse(argc, argv);
|
|
|
|
|
2023-04-08 14:31:33 +00:00
|
|
|
struct passwd* entry = getpwnam(name.chars());
|
|
|
|
if (!entry)
|
|
|
|
{
|
2023-05-06 20:03:50 +00:00
|
|
|
fprintf(stderr, "%s: user %s not found!\n", argv[0], name.chars());
|
2023-04-08 14:31:33 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2023-04-08 11:50:18 +00:00
|
|
|
|
2023-05-18 19:47:46 +00:00
|
|
|
endpwent();
|
|
|
|
|
2023-05-06 20:03:50 +00:00
|
|
|
if ((prompt_password || getuid() != geteuid()) && *entry->pw_passwd)
|
2023-04-08 11:50:18 +00:00
|
|
|
{
|
2023-07-12 11:49:37 +00:00
|
|
|
signal(SIGTTOU, SIG_IGN);
|
|
|
|
|
2023-04-09 09:24:34 +00:00
|
|
|
char* pass = getpass();
|
|
|
|
if (!pass) return 1;
|
|
|
|
|
|
|
|
if (strcmp(pass, entry->pw_passwd))
|
|
|
|
{
|
2023-05-06 20:03:50 +00:00
|
|
|
fprintf(stderr, "%s: wrong password!\n", argv[0]);
|
2023-04-09 09:24:34 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(pass, 0, strlen(pass));
|
2023-04-08 11:50:18 +00:00
|
|
|
}
|
|
|
|
|
2023-04-08 14:31:33 +00:00
|
|
|
setgid(entry->pw_gid);
|
|
|
|
setuid(entry->pw_uid);
|
2023-04-08 11:50:18 +00:00
|
|
|
|
2023-05-11 18:11:09 +00:00
|
|
|
if (login)
|
|
|
|
{
|
|
|
|
chdir(entry->pw_dir);
|
|
|
|
clearenv();
|
2023-09-04 09:44:10 +00:00
|
|
|
setenv("PATH", "/usr/bin:/usr/local/bin", 1);
|
2023-07-12 11:49:37 +00:00
|
|
|
setpgid(0, 0);
|
2023-05-11 18:11:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (login || entry->pw_uid != 0) setenv("USER", entry->pw_name, 1);
|
2023-05-06 10:19:54 +00:00
|
|
|
|
|
|
|
setenv("HOME", entry->pw_dir, 1);
|
|
|
|
setenv("SHELL", entry->pw_shell, 1);
|
2023-04-11 20:15:46 +00:00
|
|
|
|
2023-04-08 14:31:33 +00:00
|
|
|
execl(entry->pw_shell, entry->pw_shell, NULL);
|
2023-04-13 15:04:59 +00:00
|
|
|
|
2023-04-30 12:46:34 +00:00
|
|
|
perror("execl");
|
2023-04-13 15:04:59 +00:00
|
|
|
return 1;
|
2023-04-08 11:50:18 +00:00
|
|
|
}
|