su: Read password from /dev/tty instead of stdin
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-10-14 20:47:56 +02:00
parent c323a812a5
commit 56eb0c8130
Signed by: apio
GPG Key ID: B8A7D06E42258954

View File

@ -1,3 +1,4 @@
#include <fcntl.h>
#include <os/ArgumentParser.h> #include <os/ArgumentParser.h>
#include <pwd.h> #include <pwd.h>
#include <signal.h> #include <signal.h>
@ -7,10 +8,11 @@
#include <unistd.h> #include <unistd.h>
static struct termios orig; static struct termios orig;
static int fd = -1;
void restore_terminal() void restore_terminal()
{ {
tcsetattr(STDIN_FILENO, TCSANOW, &orig); tcsetattr(fd, TCSANOW, &orig);
} }
void signal_handler(int signo) void signal_handler(int signo)
@ -21,21 +23,25 @@ void signal_handler(int signo)
char* getpass() char* getpass()
{ {
if (!isatty(STDIN_FILENO)) FILE* f = fopen("/dev/tty", "r");
if (!f)
{ {
// FIXME: Just read from /dev/tty (the controlling terminal). Problem: that doesn't exist yet. perror("Failed to open /dev/tty");
fprintf(stderr, "error: password must be read from a terminal!");
return nullptr; return nullptr;
} }
tcsetpgrp(STDIN_FILENO, getpgid(0)); fd = fileno(f);
tcsetpgrp(fd, getpgid(0));
fputs("Password: ", stdout); fputs("Password: ", stdout);
fflush(stdout); fflush(stdout);
if (tcgetattr(STDIN_FILENO, &orig) < 0) if (tcgetattr(fd, &orig) < 0)
{ {
perror("tcgetattr"); perror("tcgetattr");
fclose(f);
fd = -1;
return nullptr; return nullptr;
} }
@ -51,18 +57,23 @@ char* getpass()
struct termios tc = orig; struct termios tc = orig;
tc.c_lflag &= ~ECHO; tc.c_lflag &= ~ECHO;
if (tcsetattr(STDIN_FILENO, TCSANOW, &tc) < 0) if (tcsetattr(fd, TCSANOW, &tc) < 0)
{ {
perror("tcsetattr"); perror("tcsetattr");
fclose(f);
fd = -1;
return nullptr; return nullptr;
} }
static char buf[BUFSIZ]; static char buf[BUFSIZ];
char* rc = fgets(buf, sizeof(buf), stdin); char* rc = fgets(buf, sizeof(buf), f);
restore_terminal(); restore_terminal();
putchar('\n'); putchar('\n');
fclose(f);
fd = -1;
if (!rc) if (!rc)
{ {
perror("fgets"); perror("fgets");