su: Use termios ioctls to turn off echoing and read a password
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-04-09 11:24:34 +02:00
parent 3e5957f9fc
commit 66c2896652
Signed by: apio
GPG Key ID: B8A7D06E42258954

View File

@ -1,16 +1,63 @@
#include <bits/termios.h>
#include <os/ArgumentParser.h> #include <os/ArgumentParser.h>
#include <pwd.h> #include <pwd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
static struct termios orig;
void restore_terminal()
{
ioctl(fileno(stdin), TCSETS, &orig);
}
char* getpass()
{
fputs("Password: ", stdout);
if (ioctl(fileno(stdin), TCGETS, &orig) < 0)
{
perror("ioctl(TCGETS)");
return nullptr;
}
atexit(restore_terminal);
struct termios tc = orig;
tc.c_lflag &= ~ECHO;
if (ioctl(fileno(stdin), TCSETS, &tc) < 0)
{
perror("ioctl(TCSETS)");
return nullptr;
}
static char buf[1024];
char* rc = fgets(buf, sizeof(buf), stdin);
restore_terminal();
putchar('\n');
if (!rc)
{
perror("fgets");
return nullptr;
}
char* newline = strrchr(rc, '\n');
if (newline) *newline = 0;
return buf;
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
StringView name; StringView name;
if (geteuid() != 0) if (geteuid() != 0)
{ {
fprintf(stderr, "su must be run as root!\n"); fprintf(stderr, "su must be setuid root!\n");
return 1; return 1;
} }
@ -25,12 +72,20 @@ int main(int argc, char** argv)
return 1; return 1;
} }
if (getuid() != geteuid()) if (getuid() != geteuid() && *entry->pw_passwd)
{ {
fprintf(stderr, "FIXME: you have to enter %s's password first!\n", name.chars()); char* pass = getpass();
if (!pass) return 1;
if (strcmp(pass, entry->pw_passwd))
{
fprintf(stderr, "Wrong password!\n");
return 1; return 1;
} }
memset(pass, 0, strlen(pass));
}
setgid(entry->pw_gid); setgid(entry->pw_gid);
setuid(entry->pw_uid); setuid(entry->pw_uid);