From b364492a8c1a2862440cb4a79edb0cb335f271eb Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Mon, 27 Apr 2020 00:49:55 +0200 Subject: [PATCH] Refactor prepare_tty() & C:o, pass tty around Most of the helper functions around TTYs assumed that STDIN_FILENO was already set up and unique for the give TTY they operated on. It turns out it wasn't. This patch refactors the open() of TTYs to ensure we do not clobber our TTY settings with multiple calls to tcsetattr() for the same TTY. Took a while to track this one down. Usually I don't run systems with more than one TTY, but the Alpine system on my home server did, and boy I've never been this close to giving up on computers, ever. Signed-off-by: Joachim Nilsson --- src/exec.c | 52 +++++++++++++++++++--------------------------------- src/getty.c | 50 +++++++++----------------------------------------- 2 files changed, 28 insertions(+), 74 deletions(-) diff --git a/src/exec.c b/src/exec.c index dc33ba0f..6248bda5 100644 --- a/src/exec.c +++ b/src/exec.c @@ -241,6 +241,25 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit struct sigaction sa; struct termios term; char name[80]; + int fd; + + /* Detach from initial controlling TTY and become session leader */ + vhangup(); + setsid(); + + fd = open(tty, O_RDWR); + if (fd < 0) { + logit(LOG_ERR, "Failed opening %s: %m", tty); + _exit(1); + } + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + close(fd); + + if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) + logit(LOG_WARNING, "Failed TIOCSCTTY on %s: %m", tty); /* * Reset to sane defaults in case of messup from prev. session @@ -251,7 +270,6 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit * Disable ISIG (INTR, QUIT, SUSP) before handing over to getty. * It is up to the getty process to allow them again. */ - tcdrain(STDIN_FILENO); if (!tcgetattr(STDIN_FILENO, &term)) { term.c_lflag &= ~ISIG; term.c_cc[VEOF] = _POSIX_VDISABLE; @@ -279,9 +297,6 @@ static void prepare_tty(char *tty, speed_t speed, char *procname, struct rlimit logit(LOG_WARNING, "%s: rlimit: Failed setting %s", tty, rlim2str(i)); } - /* Create new session and process group */ - setsid(); - /* Finit is responsible for the UTMP INIT_PROCESS record */ utmp_set_init(tty, 0); if (!strncmp("/dev/", tty, 5)) @@ -374,7 +389,6 @@ pid_t run_getty(char *tty, char *baud, char *term, int noclear, int nowait, stru speed = stty_parse_speed(baud); logit(LOG_INFO, "Starting built-in getty on %s, speed %u", tty, speed); prepare_tty(tty, speed, "tty", rlimit); - if (activate_console(noclear, nowait)) _exit(getty(tty, speed, term, NULL)); } @@ -388,40 +402,12 @@ pid_t run_getty2(char *tty, char *cmd, char *args[], int noclear, int nowait, st pid = fork(); if (!pid) { - int i, fd; - struct sigaction sa; - - /* Reset signal handlers that were set by the parent process */ - for (i = 1; i < NSIG; i++) - DFLSIG(sa, i, 0); - - /* Detach from initial controlling TTY */ - vhangup(); - - close(STDERR_FILENO); - close(STDOUT_FILENO); - close(STDIN_FILENO); - - /* Attach TTY to console */ - fd = open(tty, O_RDWR); - if (fd != STDIN_FILENO) - exit(1); - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - /* Dunno speed, tell stty() to not mess with it */ logit(LOG_INFO, "Starting external getty on %s, speed %u", tty, B0); prepare_tty(tty, B0, "getty", rlimit); - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) - _pe("Failed TIOCSCTTY"); - if (activate_console(noclear, nowait)) _exit(execv(cmd, args)); - close(fd); vhangup(); exit(0); } diff --git a/src/getty.c b/src/getty.c index 426cae26..c2432066 100644 --- a/src/getty.c +++ b/src/getty.c @@ -147,12 +147,6 @@ static void do_getty(char *tty, char *name, size_t len) int ch; char *np; - /* - * Clean up tty name. - */ - if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV))) - tty += 5; - /* * Display prompt. */ @@ -212,26 +206,16 @@ int getty(char *tty, speed_t speed, char *term, char *user) { const char cln[] = "\r\e[2K\n"; char name[30]; - int fd; - /* Detach from initial controlling TTY */ - vhangup(); - - fd = open(tty, O_RDWR); - if (fd < 0) - err(1, "Failed opening %s", tty); - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - close(fd); - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) - warn("Failed TIOCSCTTY"); + /* + * Clean up tty name. + */ + if (!strncmp(tty, _PATH_DEV, strlen(_PATH_DEV))) + tty += 5; /* Set up TTY, re-enabling ISIG et al. */ stty(STDIN_FILENO, speed); - (void)write(STDOUT_FILENO, cln, strlen(cln)); + (void)write(STDERR_FILENO, cln, strlen(cln)); /* The getty process is responsible for the UTMP login record */ utmp_set_login(tty, NULL); @@ -248,35 +232,19 @@ int getty(char *tty, speed_t speed, char *term, char *user) int sh(char *tty) { - int fd; - char *arg0; + struct termios term; char *args[2] = { NULL, NULL }; + char *arg0; size_t len; - struct termios term; - - /* Detach from initial controlling TTY */ - vhangup(); - - fd = open(tty, O_RDWR); - if (fd < 0) - err(1, "Failed opening %s", tty); - - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - dup2(fd, STDERR_FILENO); - - if (ioctl(STDIN_FILENO, TIOCSCTTY, 1) < 0) - warn("Failed TIOCSCTTY"); /* The getty process is usually responsible for the UTMP login record */ utmp_set_login(tty, NULL); /* Set up TTY, re-enabling ISIG et al. */ - stty(fd, B0); - close(fd); + stty(STDIN_FILENO, B0); /* Start /bin/sh as a login shell, i.e. with a prefix '-' */ len = strlen(_PATH_BSHELL) + 2;