--- src/sulogin.c +++ src/sulogin.c 2005-10-19 11:56:43.000000000 +0200 @@ -23,13 +23,16 @@ #include #include #include +#include #include +#include #if defined(__GLIBC__) # include #endif #define CHECK_DES 1 #define CHECK_MD5 1 +#define FIXTTY 1 #define F_PASSWD "/etc/passwd" #define F_SHADOW "/etc/shadow" @@ -37,49 +40,80 @@ char *Version = "@(#)sulogin 2.85-3 23-Apr-2003 miquels@cistron.nl"; -int timeout = 0; -int profile = 0; +static int timeout; +static int profile; + +static void (*saved_sigint) = SIG_DFL; +static void (*saved_sigtstp) = SIG_DFL; +static void (*saved_sigquit) = SIG_DFL; #ifndef IUCLC # define IUCLC 0 #endif -#if 0 +#if FIXTTY /* * Fix the tty modes and set reasonable defaults. * (I'm not sure if this is needed under Linux, but..) */ +static void fixtty(void) { struct termios tty; + int serial; + + /* Skip serial console */ + if (ioctl (0, TIOCMGET, (char*)&serial) == 0) + goto out; + /* Expected error */ + serial = errno = 0; tcgetattr(0, &tty); - /* - * Set or adjust tty modes. - */ - tty.c_iflag &= ~(INLCR|IGNCR|IUCLC); - tty.c_iflag |= ICRNL; - tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL); - tty.c_oflag |= OPOST|ONLCR; - tty.c_cflag |= CLOCAL; - tty.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE; - - /* - * Set the most important characters */ - */ - tty.c_cc[VINTR] = 3; - tty.c_cc[VQUIT] = 28; - tty.c_cc[VERASE] = 127; - tty.c_cc[VKILL] = 24; - tty.c_cc[VEOF] = 4; - tty.c_cc[VTIME] = 0; - tty.c_cc[VMIN] = 1; - tty.c_cc[VSTART] = 17; - tty.c_cc[VSTOP] = 19; - tty.c_cc[VSUSP] = 26; + /* Use defaults of for base settings */ + tty.c_iflag |= TTYDEF_IFLAG; + tty.c_oflag |= TTYDEF_OFLAG; + tty.c_lflag |= TTYDEF_LFLAG; + tty.c_cflag |= (TTYDEF_SPEED | TTYDEF_CFLAG); + + /* Sane setting, allow eight bit characters, no carriage return delay + * the same result as `stty sane cr0 pass8' + */ + tty.c_iflag |= (BRKINT | ICRNL | IMAXBEL); + tty.c_iflag &= ~(IGNBRK | INLCR | IGNCR | IXOFF | IUCLC | IXANY | ISTRIP); + tty.c_oflag |= (OPOST | ONLCR | NL0 | CR0 | TAB0 | BS0 | VT0 | FF0); + tty.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL |\ + NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); + tty.c_lflag |= (ISIG | ICANON | IEXTEN | ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE); + tty.c_lflag &= ~(ECHONL | NOFLSH | XCASE | TOSTOP | ECHOPRT); + tty.c_cflag |= (CREAD | CS8 | B9600); + tty.c_cflag &= ~(PARENB); + + /* VTIME and VMIN can overlap with VEOF and VEOL since they are + * only used for non-canonical mode. We just set the at the + * beginning, so nothing bad should happen. + */ + tty.c_cc[VTIME] = 0; + tty.c_cc[VMIN] = 1; + tty.c_cc[VINTR] = CINTR; + tty.c_cc[VQUIT] = CQUIT; + tty.c_cc[VERASE] = CERASE; /* ASCII DEL (0177) */ + tty.c_cc[VKILL] = CKILL; + tty.c_cc[VEOF] = CEOF; + tty.c_cc[VSWTC] = _POSIX_VDISABLE; + tty.c_cc[VSTART] = CSTART; + tty.c_cc[VSTOP] = CSTOP; + tty.c_cc[VSUSP] = CSUSP; + tty.c_cc[VEOL] = _POSIX_VDISABLE; + tty.c_cc[VREPRINT] = CREPRINT; + tty.c_cc[VDISCARD] = CDISCARD; + tty.c_cc[VWERASE] = CWERASE; + tty.c_cc[VLNEXT] = CLNEXT; + tty.c_cc[VEOL2] = _POSIX_VDISABLE; tcsetattr(0, TCSANOW, &tty); +out: + return; } #endif @@ -87,7 +121,8 @@ /* * Called at timeout. */ -void alrm_handler() +static +void alrm_handler(int sig) { } @@ -96,6 +131,7 @@ * password is checked for traditional-style DES and * FreeBSD-style MD5 encryption. */ +static int valid(char *pass) { char *s; @@ -134,6 +170,7 @@ /* * Set a variable if the value is not NULL. */ +static void set(char **var, char *val) { if (val) *var = val; @@ -142,6 +179,7 @@ /* * Get the root password entry. */ +static struct passwd *getrootpwent(int try_manually) { static struct passwd pwd; @@ -244,6 +282,7 @@ * Ask for the password. Note that there is no * default timeout as we normally skip this during boot. */ +static char *getpasswd(char *crypted) { struct sigaction sa; @@ -252,11 +291,10 @@ char *ret = pass; int i; - if (crypted[0]) - printf("Give root password for maintenance\n"); - else - printf("Press enter for maintenance\n"); - printf("(or type Control-D to continue): "); + if (crypted[0]) { + printf("Give root password for login: "); + } else + printf("Press enter for login: "); fflush(stdout); tcgetattr(0, &old); @@ -291,6 +329,7 @@ /* * Password was OK, execute a shell. */ +static void sushell(struct passwd *pwd) { char shell[128]; @@ -332,9 +371,9 @@ * Try to execute a shell. */ setenv("SHELL", sushell, 1); - signal(SIGINT, SIG_DFL); - signal(SIGTSTP, SIG_DFL); - signal(SIGQUIT, SIG_DFL); + signal(SIGINT, saved_sigint); + signal(SIGTSTP, saved_sigtstp); + signal(SIGQUIT, saved_sigquit); execl(sushell, shell, NULL); perror(sushell); @@ -343,6 +382,7 @@ perror(BINSH); } +static void usage(void) { fprintf(stderr, "Usage: sulogin [-e] [-p] [-t timeout] [tty device]\n"); @@ -385,50 +425,69 @@ /* * See if we need to open an other tty device. */ - signal(SIGINT, SIG_IGN); - signal(SIGQUIT, SIG_IGN); - signal(SIGTSTP, SIG_IGN); + saved_sigint = signal(SIGINT, SIG_IGN); + saved_sigtstp = signal(SIGQUIT, SIG_IGN); + saved_sigquit = signal(SIGTSTP, SIG_IGN); if (optind < argc) tty = argv[optind]; - if (tty) { - if ((fd = open(tty, O_RDWR)) < 0) { - perror(tty); - } else if (!isatty(fd)) { - fprintf(stderr, "%s: not a tty\n", tty); - close(fd); - } else { - - /* - * Only go through this trouble if the new - * tty doesn't fall in this process group. - */ - pid = getpid(); - pgrp = getpgid(0); - ppgrp = getpgid(getppid()); - ioctl(fd, TIOCGPGRP, &ttypgrp); - - if (pgrp != ttypgrp && ppgrp != ttypgrp) { - if (pid != getsid(0)) { - if (pid == getpgid(0)) - setpgid(0, getpgid(getppid())); - setsid(); - } - signal(SIGHUP, SIG_IGN); + if (!tty && !(tty = getenv("CONSOLE"))) + tty = "/dev/console"; + + if ((fd = open(tty, O_RDWR)) < 0) { + perror(tty); + fd = dup(0); + } + + if (!isatty(fd)) { + fprintf(stderr, "%s: not a tty\n", tty); + close(fd); + } else { + + /* + * Only go through this trouble if the new + * tty doesn't fall in this process group. + */ + pid = getpid(); + pgrp = getpgid(0); + ppgrp = getpgid(getppid()); + ttypgrp = tcgetpgrp(fd); + + if (pgrp != ttypgrp && ppgrp != ttypgrp) { + if (pid != getsid(0)) { + if (pid == getpgid(0)) + setpgid(0, getpgid(getppid())); + setsid(); + } + + signal(SIGHUP, SIG_IGN); + if (ttypgrp > 0) ioctl(0, TIOCNOTTY, (char *)1); - signal(SIGHUP, SIG_DFL); - close(0); - close(1); - close(2); + signal(SIGHUP, SIG_DFL); + close(0); + close(1); + close(2); + if (fd > 2) close(fd); - fd = open(tty, O_RDWR); + if ((fd = open(tty, O_RDWR)) < 0) { + perror(tty); + } else { + tcsetpgrp(fd, ppgrp); ioctl(0, TIOCSCTTY, (char *)1); - dup(fd); - dup(fd); - } else + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + if (fd > 2) + close(fd); + } + } else + if (fd > 2) close(fd); - } } +#if FIXTTY + fixtty(); +#endif + /* * Get the root password. */ @@ -445,6 +504,9 @@ if (pwd->pw_passwd[0] == 0 || strcmp(crypt(p, pwd->pw_passwd), pwd->pw_passwd) == 0) sushell(pwd); + saved_sigquit = signal(SIGQUIT, SIG_IGN); + saved_sigtstp = signal(SIGTSTP, SIG_IGN); + saved_sigint = signal(SIGINT, SIG_IGN); printf("Login incorrect.\n"); } @@ -453,4 +515,3 @@ */ return 0; } -