]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/sulogin.c
Make the ways of using output stream consistent in usage()
[thirdparty/util-linux.git] / login-utils / sulogin.c
1 /*
2 * sulogin
3 *
4 * This program gives Linux machines a reasonable secure way to boot single
5 * user. It forces the user to supply the root password before a shell is
6 * started. If there is a shadow password file and the encrypted root password
7 * is "x" the shadow password will be used.
8 *
9 * Copyright (C) 1998-2003 Miquel van Smoorenburg.
10 * Copyright (C) 2012 Karel Zak <kzak@redhat.com>
11 * Copyright (C) 2012 Werner Fink <werner@suse.de>
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 */
27 #include <sys/mman.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <pwd.h>
38 #include <shadow.h>
39 #include <termios.h>
40 #include <errno.h>
41 #include <getopt.h>
42 #include <sys/ioctl.h>
43 #ifdef HAVE_CRYPT_H
44 # include <crypt.h>
45 #endif
46
47 #ifdef HAVE_LIBSELINUX
48 # include <selinux/selinux.h>
49 # include <selinux/get_context_list.h>
50 #endif
51
52 #ifdef __linux__
53 # include <sys/kd.h>
54 # include <sys/param.h>
55 # include <linux/serial.h>
56 #endif
57
58 #include "c.h"
59 #include "closestream.h"
60 #include "env.h"
61 #include "nls.h"
62 #include "pathnames.h"
63 #ifdef USE_PLYMOUTH_SUPPORT
64 # include "plymouth-ctrl.h"
65 #endif
66 #include "strutils.h"
67 #include "ttyutils.h"
68 #include "sulogin-consoles.h"
69 #define CONMAX 16
70
71 static unsigned int timeout;
72 static int profile;
73 static volatile uint32_t openfd; /* Remember higher file descriptors */
74
75 static struct sigaction saved_sigint;
76 static struct sigaction saved_sigtstp;
77 static struct sigaction saved_sigquit;
78 static struct sigaction saved_sighup;
79 static struct sigaction saved_sigchld;
80
81 static volatile sig_atomic_t alarm_rised;
82 static volatile sig_atomic_t sigchild;
83
84 #define SULOGIN_PASSWORD_BUFSIZ 128
85
86 #ifndef IUCLC
87 # define IUCLC 0
88 #endif
89
90 #ifndef WEXITED
91 # warning "WEXITED is missing, sulogin may not work as expected"
92 # define WEXITED 0
93 #endif
94
95 static int locked_account_password(const char * const passwd)
96 {
97 if (passwd && (*passwd == '*' || *passwd == '!'))
98 return 1;
99 return 0;
100 }
101
102 /*
103 * Fix the tty modes and set reasonable defaults.
104 */
105 static void tcinit(struct console *con)
106 {
107 int flags = 0, mode = 0;
108 struct termios *tio = &con->tio;
109 const int fd = con->fd;
110 #if defined(TIOCGSERIAL)
111 struct serial_struct serinfo = { .flags = 0 };
112 #endif
113 #ifdef USE_PLYMOUTH_SUPPORT
114 struct termios lock;
115 int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
116 if (i)
117 plymouth_command(MAGIC_QUIT);
118 while (i-- > 0) {
119 /*
120 * With plymouth the termios flags become changed after this
121 * function had changed the termios.
122 */
123 memset(&lock, 0, sizeof(struct termios));
124 if (ioctl(fd, TIOCGLCKTRMIOS, &lock) < 0)
125 break;
126 if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
127 break;
128 sleep(1);
129 }
130 memset(&lock, 0, sizeof(struct termios));
131 ioctl(fd, TIOCSLCKTRMIOS, &lock);
132 errno = 0;
133 #endif
134
135 #ifdef TIOCGSERIAL
136 if (ioctl(fd, TIOCGSERIAL, &serinfo) >= 0)
137 con->flags |= CON_SERIAL;
138 errno = 0;
139 #endif
140
141 #ifdef KDGKBMODE
142 if (!(con->flags & CON_SERIAL)
143 && ioctl(fd, KDGKBMODE, &mode) < 0)
144 con->flags |= CON_SERIAL;
145 errno = 0;
146 #endif
147 if (tcgetattr(fd, tio) < 0) {
148 int saveno = errno;
149 #if defined(KDGKBMODE) || defined(TIOCGSERIAL)
150 if (con->flags & CON_SERIAL) { /* Try to recover this */
151
152 # if defined(TIOCGSERIAL)
153 serinfo.flags |= ASYNC_SKIP_TEST; /* Skip test of UART */
154
155 if (ioctl(fd, TIOCSSERIAL, &serinfo) < 0)
156 goto tcgeterr;
157 if (ioctl(fd, TIOCSERCONFIG) < 0) /* Try to autoconfigure */
158 goto tcgeterr;
159 if (ioctl(fd, TIOCGSERIAL, &serinfo) < 0)
160 goto tcgeterr; /* Ouch */
161 # endif
162 if (tcgetattr(fd, tio) < 0) /* Retry to get tty attributes */
163 saveno = errno;
164 }
165 # if defined(TIOCGSERIAL)
166 tcgeterr:
167 # endif
168 if (saveno)
169 #endif
170 {
171 FILE *fcerr = fdopen(fd, "w");
172 if (fcerr) {
173 fprintf(fcerr, _("tcgetattr failed"));
174 fclose(fcerr);
175 }
176 warn(_("tcgetattr failed"));
177
178 con->flags &= ~CON_SERIAL;
179 if (saveno != EIO)
180 con->flags |= CON_NOTTY;
181 else
182 con->flags |= CON_EIO;
183
184 errno = 0;
185 return;
186 }
187 }
188
189 /* Handle lines other than virtual consoles here */
190 #if defined(KDGKBMODE) || defined(TIOCGSERIAL)
191 if (con->flags & CON_SERIAL)
192 #endif
193 {
194 speed_t ispeed, ospeed;
195 struct winsize ws;
196 errno = 0;
197
198 /* Flush input and output queues on modem lines */
199 tcflush(fd, TCIOFLUSH);
200
201 ispeed = cfgetispeed(tio);
202 ospeed = cfgetospeed(tio);
203
204 if (!ispeed) ispeed = TTYDEF_SPEED;
205 if (!ospeed) ospeed = TTYDEF_SPEED;
206
207 tio->c_cflag = CREAD | CS8 | HUPCL | (tio->c_cflag & CLOCAL);
208 tio->c_iflag = 0;
209 tio->c_lflag = 0;
210 tio->c_oflag &= OPOST | ONLCR;
211
212 cfsetispeed(tio, ispeed);
213 cfsetospeed(tio, ospeed);
214
215 #ifdef HAVE_STRUCT_TERMIOS_C_LINE
216 tio->c_line = 0;
217 #endif
218 tio->c_cc[VTIME] = 0;
219 tio->c_cc[VMIN] = 1;
220
221 if (ioctl(fd, TIOCGWINSZ, &ws) == 0) {
222 int update = 0;
223
224 if (ws.ws_row == 0) {
225 ws.ws_row = 24;
226 update++;
227 }
228 if (ws.ws_col == 0) {
229 ws.ws_col = 80;
230 update++;
231 }
232 if (update)
233 ignore_result( ioctl(fd, TIOCSWINSZ, &ws) );
234 }
235
236 setlocale(LC_CTYPE, "POSIX");
237 goto setattr;
238 }
239 #if defined(IUTF8) && defined(KDGKBMODE)
240 /* Handle mode of current keyboard setup, e.g. for UTF-8 */
241 switch(mode) {
242 case K_UNICODE:
243 setlocale(LC_CTYPE, "C.UTF-8");
244 flags |= UL_TTY_UTF8;
245 break;
246 case K_RAW:
247 case K_MEDIUMRAW:
248 case K_XLATE:
249 default:
250 setlocale(LC_CTYPE, "POSIX");
251 break;
252 }
253 #else
254 setlocale(LC_CTYPE, "POSIX");
255 #endif
256 reset_virtual_console(tio, flags);
257 setattr:
258 if (tcsetattr(fd, TCSANOW, tio))
259 warn(_("tcsetattr failed"));
260
261 /* Enable blocking mode for read and write */
262 if ((flags = fcntl(fd, F_GETFL, 0)) != -1)
263 ignore_result( fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) );
264 }
265
266 /*
267 * Finalize the tty modes on modem lines.
268 */
269 static void tcfinal(struct console *con)
270 {
271 struct termios *tio = &con->tio;
272 const int fd = con->fd;
273 char *term, *ttyname = NULL;
274
275 if (con->tty)
276 ttyname = strncmp(con->tty, "/dev/", 5) == 0 ?
277 con->tty + 5 : con->tty;
278
279 term = get_terminal_default_type(ttyname, con->flags & CON_SERIAL);
280 if (term) {
281 xsetenv("TERM", term, 0);
282 free(term);
283 }
284
285 if (!(con->flags & CON_SERIAL) || (con->flags & CON_NOTTY))
286 return;
287
288 tio->c_iflag |= (IXON | IXOFF);
289 tio->c_lflag |= (ICANON | ISIG | ECHO|ECHOE|ECHOK|ECHOKE);
290 tio->c_oflag |= OPOST;
291
292 tio->c_cc[VINTR] = CINTR;
293 tio->c_cc[VQUIT] = CQUIT;
294 tio->c_cc[VERASE] = con->cp.erase;
295 tio->c_cc[VKILL] = con->cp.kill;
296 tio->c_cc[VEOF] = CEOF;
297 #ifdef VSWTC
298 tio->c_cc[VSWTC] = _POSIX_VDISABLE;
299 #elif defined(VSWTCH)
300 tio->c_cc[VSWTCH] = _POSIX_VDISABLE;
301 #endif
302 tio->c_cc[VSTART] = CSTART;
303 tio->c_cc[VSTOP] = CSTOP;
304 tio->c_cc[VSUSP] = CSUSP;
305 tio->c_cc[VEOL] = _POSIX_VDISABLE;
306
307 if (con->cp.eol == CR) {
308 tio->c_iflag |= ICRNL;
309 tio->c_iflag &= ~(INLCR|IGNCR);
310 tio->c_oflag |= ONLCR;
311 tio->c_oflag &= ~(OCRNL|ONLRET);
312 }
313
314 switch (con->cp.parity) {
315 default:
316 case 0:
317 tio->c_cflag &= ~(PARODD | PARENB);
318 tio->c_iflag &= ~(INPCK | ISTRIP);
319 break;
320 case 1: /* odd parity */
321 tio->c_cflag |= PARODD;
322 /* fallthrough */
323 case 2: /* even parity */
324 tio->c_cflag |= PARENB;
325 tio->c_iflag |= (INPCK | ISTRIP);
326 /* fallthrough */
327 case (1 | 2): /* no parity bit */
328 tio->c_cflag &= ~CSIZE;
329 tio->c_cflag |= CS7;
330 break;
331 }
332
333 /* Set line attributes */
334 tcsetattr(fd, TCSANOW, tio);
335 }
336
337 /*
338 * Called at timeout.
339 */
340 static void alrm_handler(int sig __attribute__((unused)))
341 {
342 /* Timeout expired */
343 alarm_rised = 1;
344 }
345
346 static void chld_handler(int sig __attribute__((unused)))
347 {
348 sigchild = 1;
349 }
350
351 static void mask_signal(int signal, void (*handler)(int),
352 struct sigaction *origaction)
353 {
354 struct sigaction newaction;
355
356 newaction.sa_handler = handler;
357 sigemptyset(&newaction.sa_mask);
358 newaction.sa_flags = 0;
359
360 sigaction(signal, &newaction, origaction);
361 }
362
363 static void unmask_signal(int signal, struct sigaction *sa)
364 {
365 sigaction(signal, sa, NULL);
366 }
367
368 /*
369 * See if an encrypted password is valid. The encrypted password is checked for
370 * traditional-style DES and FreeBSD-style MD5 encryption.
371 */
372 static int valid(const char *pass)
373 {
374 const char *s;
375 char id[5];
376 size_t len;
377 off_t off;
378
379 if (pass[0] == 0)
380 return 1;
381 if (pass[0] != '$')
382 goto check_des;
383
384 /*
385 * up to 4 bytes for the signature e.g. $1$
386 */
387 for (s = pass+1; *s && *s != '$'; s++);
388
389 if (*s++ != '$')
390 return 0;
391
392 if ((off = (off_t)(s-pass)) > 4 || off < 3)
393 return 0;
394
395 memset(id, '\0', sizeof(id));
396 strncpy(id, pass, off);
397
398 /*
399 * up to 16 bytes for the salt
400 */
401 for (; *s && *s != '$'; s++);
402
403 if (*s++ != '$')
404 return 0;
405
406 if ((off_t)(s-pass) > 16)
407 return 0;
408
409 len = strlen(s);
410
411 /*
412 * the MD5 hash (128 bits or 16 bytes) encoded in base64 = 22 bytes
413 */
414 if ((strcmp(id, "$1$") == 0) && (len < 22 || len > 24))
415 return 0;
416
417 /*
418 * the SHA-256 hash 43 bytes
419 */
420 if ((strcmp(id, "$5$") == 0) && (len < 42 || len > 44))
421 return 0;
422
423 /*
424 * the SHA-512 hash 86 bytes
425 */
426 if ((strcmp(id, "$6$") == 0) && (len < 85 || len > 87))
427 return 0;
428
429 /*
430 * e.g. Blowfish hash
431 */
432 return 1;
433 check_des:
434 if (strlen(pass) != 13)
435 return 0;
436
437 for (s = pass; *s; s++) {
438 if ((*s < '0' || *s > '9') &&
439 (*s < 'a' || *s > 'z') &&
440 (*s < 'A' || *s > 'Z') &&
441 *s != '.' && *s != '/')
442 return 0;
443 }
444 return 1;
445 }
446
447 /*
448 * Set a variable if the value is not NULL.
449 */
450 static inline void set(char **var, char *val)
451 {
452 if (val)
453 *var = val;
454 }
455
456 /*
457 * Get the root password entry.
458 */
459 static struct passwd *getrootpwent(int try_manually)
460 {
461 static struct passwd pwd;
462 struct passwd *pw;
463 struct spwd *spw;
464 FILE *fp;
465 static char line[2 * BUFSIZ];
466 static char sline[2 * BUFSIZ];
467 char *p;
468
469 /*
470 * First, we try to get the password the standard way using normal
471 * library calls.
472 */
473 if ((pw = getpwnam("root")) &&
474 !strcmp(pw->pw_passwd, "x") &&
475 (spw = getspnam("root")))
476 pw->pw_passwd = spw->sp_pwdp;
477
478 if (pw || !try_manually)
479 return pw;
480
481 /*
482 * If we come here, we could not retrieve the root password through
483 * library calls and we try to read the password and shadow files
484 * manually.
485 */
486 pwd.pw_name = "root";
487 pwd.pw_passwd = "";
488 pwd.pw_gecos = "Super User";
489 pwd.pw_dir = "/";
490 pwd.pw_shell = "";
491 pwd.pw_uid = 0;
492 pwd.pw_gid = 0;
493
494 if ((fp = fopen(_PATH_PASSWD, "r")) == NULL) {
495 warn(_("cannot open %s"), _PATH_PASSWD);
496 return &pwd;
497 }
498
499 /*
500 * Find root in the password file.
501 */
502 while ((p = fgets(line, sizeof(line), fp)) != NULL) {
503 if (strncmp(line, "root:", 5) != 0)
504 continue;
505 p += 5;
506 set(&pwd.pw_passwd, strsep(&p, ":"));
507 strsep(&p, ":");
508 strsep(&p, ":");
509 set(&pwd.pw_gecos, strsep(&p, ":"));
510 set(&pwd.pw_dir, strsep(&p, ":"));
511 set(&pwd.pw_shell, strsep(&p, "\n"));
512 p = line;
513 break;
514 }
515 fclose(fp);
516
517 /*
518 * If the encrypted password is valid or not found, return.
519 */
520 if (p == NULL) {
521 warnx(_("%s: no entry for root\n"), _PATH_PASSWD);
522 return &pwd;
523 }
524 if (valid(pwd.pw_passwd))
525 return &pwd;
526
527 /*
528 * The password is invalid. If there is a shadow password, try it.
529 */
530 *pwd.pw_passwd = '\0';
531 if ((fp = fopen(_PATH_SHADOW_PASSWD, "r")) == NULL) {
532 warn(_("cannot open %s"), _PATH_PASSWD);
533 return &pwd;
534 }
535 while ((p = fgets(sline, sizeof(sline), fp)) != NULL) {
536 if (strncmp(sline, "root:", 5) != 0)
537 continue;
538 p += 5;
539 set(&pwd.pw_passwd, strsep(&p, ":"));
540 break;
541 }
542 fclose(fp);
543
544 /*
545 * If the password is still invalid, NULL it, and return.
546 */
547 if (p == NULL) {
548 warnx(_("%s: no entry for root"), _PATH_SHADOW_PASSWD);
549 *pwd.pw_passwd = '\0';
550 }
551 /* locked account passwords are valid too */
552 if (!locked_account_password(pwd.pw_passwd) && !valid(pwd.pw_passwd)) {
553 warnx(_("%s: root password garbled"), _PATH_SHADOW_PASSWD);
554 *pwd.pw_passwd = '\0';
555 }
556 return &pwd;
557 }
558
559 /*
560 * Ask by prompt for the password.
561 */
562 static void doprompt(const char *crypted, struct console *con, int deny)
563 {
564 struct termios tty;
565
566 if (con->flags & CON_SERIAL) {
567 tty = con->tio;
568 /*
569 * For prompting: map NL in output to CR-NL
570 * otherwise we may see stairs in the output.
571 */
572 tty.c_oflag |= (ONLCR | OPOST);
573 tcsetattr(con->fd, TCSADRAIN, &tty);
574 }
575 if (!con->file) {
576 con->file = fdopen(con->fd, "r+");
577 if (!con->file)
578 goto err;
579 }
580
581 if (deny)
582 fprintf(con->file, _("\nCannot open access to console, the root account is locked.\n"
583 "See sulogin(8) man page for more details.\n\n"
584 "Press Enter to continue.\n"));
585 else {
586 #if defined(USE_ONELINE)
587 if (crypted[0] && !locked_account_password(crypted))
588 fprintf(con->file, _("Give root password for login: "));
589 else
590 fprintf(con->file, _("Press Enter for login: "));
591 #else
592 if (crypted[0] && !locked_account_password(crypted))
593 fprintf(con->file, _("Give root password for maintenance\n"));
594 else
595 fprintf(con->file, _("Press Enter for maintenance\n"));
596 fprintf(con->file, _("(or press Control-D to continue): "));
597 #endif
598 }
599 fflush(con->file);
600 err:
601 if (con->flags & CON_SERIAL)
602 tcsetattr(con->fd, TCSADRAIN, &con->tio);
603 }
604
605 /*
606 * Make sure to have an own session and controlling terminal
607 */
608 static void setup(struct console *con)
609 {
610 int fd = con->fd;
611 const pid_t pid = getpid(), pgrp = getpgid(0), ppgrp = getpgid(getppid());
612 pid_t ttypgrp;
613
614 if (con->flags & CON_NOTTY)
615 goto notty;
616 if (con->flags & CON_EIO)
617 return;
618
619 ttypgrp = tcgetpgrp(fd);
620
621 /*
622 * Only go through this trouble if the new
623 * tty doesn't fall in this process group.
624 */
625 if (pgrp != ttypgrp && ppgrp != ttypgrp) {
626 if (pid != getsid(0)) {
627 if (pid == getpgid(0))
628 setpgid(0, getpgid(getppid()));
629 setsid();
630 }
631
632 mask_signal(SIGHUP, SIG_IGN, &saved_sighup);
633 if (ttypgrp > 0)
634 ioctl(STDIN_FILENO, TIOCNOTTY, (char *)1);
635 unmask_signal(SIGHUP, &saved_sighup);
636 if (fd > STDIN_FILENO) close(STDIN_FILENO);
637 if (fd > STDOUT_FILENO) close(STDOUT_FILENO);
638 if (fd > STDERR_FILENO) close(STDERR_FILENO);
639
640 ioctl(fd, TIOCSCTTY, (char *)1);
641 tcsetpgrp(fd, ppgrp);
642 }
643 notty:
644 dup2(fd, STDIN_FILENO);
645 dup2(fd, STDOUT_FILENO);
646 dup2(fd, STDERR_FILENO);
647 con->fd = STDIN_FILENO;
648
649 for (fd = STDERR_FILENO+1; fd < 32; fd++) {
650 if (openfd & (1<<fd)) {
651 close(fd);
652 openfd &= ~(1<<fd);
653 }
654 }
655 }
656
657 /*
658 * Ask for the password. Note that there is no default timeout as we normally
659 * skip this during boot.
660 */
661 static char *getpasswd(struct console *con)
662 {
663 struct sigaction sa;
664 struct termios tty;
665 static char pass[SULOGIN_PASSWORD_BUFSIZ], *ptr;
666 struct chardata *cp;
667 char *ret = NULL;
668 unsigned char tc;
669 char c, ascval;
670 int eightbit;
671 const int fd = con->fd;
672
673 if (con->flags & CON_EIO)
674 goto out;
675
676 cp = &con->cp;
677 tty = con->tio;
678 tc = 0;
679 ret = pass;
680
681 tty.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
682 tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP|ISIG);
683
684 if ((con->flags & CON_NOTTY) == 0)
685 tc = (tcsetattr(fd, TCSAFLUSH, &tty) == 0);
686
687 sigemptyset(&sa.sa_mask);
688 sa.sa_handler = alrm_handler;
689 sa.sa_flags = 0;
690 sigaction(SIGALRM, &sa, NULL);
691
692 if (timeout)
693 alarm(timeout);
694
695 ptr = &pass[0];
696 cp->eol = *ptr = '\0';
697
698 eightbit = ((con->flags & CON_SERIAL) == 0 || (tty.c_cflag & (PARODD|PARENB)) == 0);
699
700 while (cp->eol == '\0') {
701 errno = 0;
702
703 if (read(fd, &c, 1) < 1) {
704 if (errno == EINTR || errno == EAGAIN) {
705 if (alarm_rised) {
706 ret = NULL;
707 goto quit;
708 }
709 xusleep(250000);
710 continue;
711 }
712 ret = NULL;
713
714 switch (errno) {
715 case EIO:
716 con->flags |= CON_EIO;
717 /* fallthrough */
718 default:
719 warn(_("cannot read %s"), con->tty);
720 break;
721 case 0:
722 break;
723 }
724 goto quit;
725 }
726
727 if (eightbit)
728 ascval = c;
729 else if (c != (ascval = (c & 0177))) {
730 uint32_t bits, mask;
731 for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
732 if (mask & ascval)
733 bits++;
734 }
735 cp->parity |= ((bits & 1) ? 1 : 2);
736 }
737
738 switch (ascval) {
739 case 0:
740 *ptr = '\0';
741 goto quit;
742 case CR:
743 case NL:
744 *ptr = '\0';
745 cp->eol = ascval;
746 break;
747 case BS:
748 case CERASE:
749 cp->erase = ascval;
750 if (ptr > &pass[0])
751 ptr--;
752 break;
753 case CKILL:
754 cp->kill = ascval;
755 while (ptr > &pass[0])
756 ptr--;
757 break;
758 case CEOF:
759 ret = NULL;
760 goto quit;
761 default:
762 if ((size_t)(ptr - &pass[0]) >= (sizeof(pass) -1 )) {
763 fprintf(stderr, "sulogin: input overrun at %s\n\r", con->tty);
764 ret = NULL;
765 goto quit;
766 }
767 *ptr++ = ascval;
768 break;
769 }
770 }
771 quit:
772 alarm(0);
773 if (tc)
774 tcsetattr(fd, TCSAFLUSH, &con->tio);
775 tcfinal(con);
776 printf("\r\n");
777 out:
778 #ifdef HAVE_EXPLICIT_BZERO
779 if (ret == NULL)
780 explicit_bzero(pass, sizeof(pass));
781 #endif
782 return ret;
783 }
784
785 /*
786 * Password was OK, execute a shell.
787 */
788 static void sushell(struct passwd *pwd)
789 {
790 char shell[PATH_MAX];
791 char home[PATH_MAX];
792 char const *p;
793 char const *su_shell;
794
795 /*
796 * Set directory and shell.
797 */
798 if (chdir(pwd->pw_dir) != 0) {
799 warn(_("%s: change directory failed"), pwd->pw_dir);
800 printf(_("Logging in with home = \"/\".\n"));
801
802 if (chdir("/") != 0)
803 warn(_("change directory to system root failed"));
804 }
805
806 if ((p = getenv("SUSHELL")) != NULL)
807 su_shell = p;
808 else if ((p = getenv("sushell")) != NULL)
809 su_shell = p;
810 else {
811 if (pwd->pw_shell[0])
812 su_shell = pwd->pw_shell;
813 else
814 su_shell = "/bin/sh";
815 }
816 if ((p = strrchr(su_shell, '/')) == NULL)
817 p = su_shell;
818 else
819 p++;
820
821 snprintf(shell, sizeof(shell), profile ? "-%s" : "%s", p);
822
823 /*
824 * Set some important environment variables.
825 */
826 if (getcwd(home, sizeof(home)) == NULL)
827 strcpy(home, "/");
828
829 xsetenv("HOME", home, 1);
830 xsetenv("LOGNAME", "root", 1);
831 xsetenv("USER", "root", 1);
832 if (!profile)
833 xsetenv("SHLVL","0",1);
834
835 /*
836 * Try to execute a shell.
837 */
838 xsetenv("SHELL", su_shell, 1);
839 unmask_signal(SIGINT, &saved_sigint);
840 unmask_signal(SIGTSTP, &saved_sigtstp);
841 unmask_signal(SIGQUIT, &saved_sigquit);
842 mask_signal(SIGHUP, SIG_DFL, NULL);
843
844 #ifdef HAVE_LIBSELINUX
845 if (is_selinux_enabled() > 0) {
846 char *scon = NULL;
847 char *seuser = NULL;
848 char *level = NULL;
849
850 if (getseuserbyname("root", &seuser, &level) == 0) {
851 if (get_default_context_with_level(seuser, level, 0, &scon) == 0) {
852 if (setexeccon(scon) != 0)
853 warnx(_("setexeccon failed"));
854 freecon(scon);
855 }
856 }
857 free(seuser);
858 free(level);
859 }
860 #endif
861 execl(su_shell, shell, (char *)NULL);
862 warn(_("failed to execute %s"), su_shell);
863
864 xsetenv("SHELL", "/bin/sh", 1);
865 execl("/bin/sh", profile ? "-sh" : "sh", (char *)NULL);
866 warn(_("failed to execute %s"), "/bin/sh");
867 }
868
869 static void usage(void)
870 {
871 FILE *out = stdout;
872 fputs(USAGE_HEADER, out);
873 fprintf(out, _(
874 " %s [options] [tty device]\n"), program_invocation_short_name);
875
876 fputs(USAGE_SEPARATOR, out);
877 fputs(_("Single-user login.\n"), out);
878
879 fputs(USAGE_OPTIONS, out);
880 fputs(_(" -p, --login-shell start a login shell\n"
881 " -t, --timeout <seconds> max time to wait for a password (default: no limit)\n"
882 " -e, --force examine password files directly if getpwnam(3) fails\n"),
883 out);
884
885 fputs(USAGE_SEPARATOR, out);
886 fprintf(out, USAGE_HELP_OPTIONS(26));
887 fprintf(out, USAGE_MAN_TAIL("sulogin(8)"));
888
889 exit(EXIT_SUCCESS);
890 }
891
892 int main(int argc, char **argv)
893 {
894 struct list_head *ptr, consoles;
895 struct console *con;
896 char *tty = NULL;
897 struct passwd *pwd;
898 const struct timespec sigwait = { .tv_sec = 0, .tv_nsec = 50000000 };
899 siginfo_t status = { 0 };
900 sigset_t set;
901 int c, reconnect = 0;
902 int opt_e = 0;
903 int wait = 0;
904 pid_t pid;
905
906 static const struct option longopts[] = {
907 { "login-shell", no_argument, NULL, 'p' },
908 { "timeout", required_argument, NULL, 't' },
909 { "force", no_argument, NULL, 'e' },
910 { "help", no_argument, NULL, 'h' },
911 { "version", no_argument, NULL, 'V' },
912 { NULL, 0, NULL, 0 }
913 };
914
915 INIT_LIST_HEAD(&consoles);
916
917 /*
918 * If we are init we need to set up an own session.
919 */
920 if ((pid = getpid()) == 1) {
921 setsid();
922 ignore_result( ioctl(STDIN_FILENO, TIOCSCTTY, (char *) 1) );
923 }
924
925 setlocale(LC_ALL, "");
926 bindtextdomain(PACKAGE, LOCALEDIR);
927 textdomain(PACKAGE);
928 close_stdout_atexit();
929
930 /*
931 * See if we have a timeout flag.
932 */
933 while ((c = getopt_long(argc, argv, "ehpt:V", longopts, NULL)) != -1) {
934 switch(c) {
935 case 't':
936 timeout = strtou32_or_err(optarg, _("invalid timeout argument"));
937 break;
938 case 'p':
939 profile = 1;
940 break;
941 case 'e':
942 opt_e = 1;
943 break;
944 case 'V':
945 {
946 static const char *features[] = {
947 #ifdef USE_SULOGIN_EMERGENCY_MOUNT
948 "emergency-mount",
949 #endif
950 NULL
951 };
952 print_version_with_features(EXIT_SUCCESS, features);
953 }
954 case 'h':
955 usage();
956 default:
957 /* Do not exit! getopt prints a warning. */
958 break;
959 }
960 }
961
962 if (geteuid() != 0)
963 errx(EXIT_FAILURE, _("only superuser can run this program"));
964
965 mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
966 mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
967 mask_signal(SIGINT, SIG_IGN, &saved_sigint);
968 mask_signal(SIGHUP, SIG_IGN, &saved_sighup);
969
970
971 emergency_do_mounts();
972 atexit( emergency_do_umounts );
973
974 /*
975 * See if we need to open an other tty device.
976 */
977 if (optind < argc)
978 tty = argv[optind];
979
980 if (!tty || *tty == '\0')
981 tty = getenv("CONSOLE");
982
983 /*
984 * Detect possible consoles, use stdin as fallback.
985 * If an optional tty is given, reconnect it to stdin.
986 */
987 reconnect = detect_consoles(tty, STDIN_FILENO, &consoles);
988
989 /*
990 * If previous stdin was not the specified tty and therefore reconnected
991 * to the specified tty also reconnect stdout and stderr.
992 */
993 if (reconnect) {
994 if (isatty(STDOUT_FILENO) == 0)
995 dup2(STDOUT_FILENO, STDIN_FILENO);
996 if (isatty(STDERR_FILENO) == 0)
997 dup2(STDOUT_FILENO, STDERR_FILENO);
998 }
999
1000 /*
1001 * Should not happen
1002 */
1003 if (list_empty(&consoles)) {
1004 if (!errno)
1005 errno = ENOENT;
1006 err(EXIT_FAILURE, _("cannot open console"));
1007 }
1008
1009 /*
1010 * Get the root password.
1011 */
1012 if ((pwd = getrootpwent(opt_e)) == NULL) {
1013 warnx(_("cannot open password database"));
1014 sleep(2);
1015 return EXIT_FAILURE;
1016 }
1017
1018 /*
1019 * Ask for the password on the consoles.
1020 */
1021 list_for_each(ptr, &consoles) {
1022 con = list_entry(ptr, struct console, entry);
1023 if (con->id >= CONMAX)
1024 break;
1025 if (con->fd >= 0) {
1026 openfd |= (1 << con->fd);
1027 tcinit(con);
1028 continue;
1029 }
1030 if ((con->fd = open(con->tty, O_RDWR | O_NOCTTY | O_NONBLOCK)) < 0)
1031 continue;
1032 openfd |= (1 << con->fd);
1033 tcinit(con);
1034 }
1035 ptr = (&consoles)->next;
1036
1037 if (ptr->next == &consoles) {
1038 con = list_entry(ptr, struct console, entry);
1039 goto nofork;
1040 }
1041
1042
1043 mask_signal(SIGCHLD, chld_handler, &saved_sigchld);
1044 do {
1045 con = list_entry(ptr, struct console, entry);
1046 if (con->id >= CONMAX)
1047 break;
1048 if (con->flags & CON_EIO)
1049 goto next;
1050
1051 switch ((con->pid = fork())) {
1052 case 0:
1053 mask_signal(SIGCHLD, SIG_DFL, NULL);
1054 dup2(con->fd, STDERR_FILENO);
1055 nofork:
1056 setup(con);
1057 while (1) {
1058 const char *passwd = pwd->pw_passwd;
1059 char *answer;
1060 int doshell = 0;
1061 int deny = !opt_e && locked_account_password(pwd->pw_passwd);
1062
1063 doprompt(passwd, con, deny);
1064
1065 if ((answer = getpasswd(con)) == NULL)
1066 break;
1067 if (deny) {
1068 #ifdef HAVE_EXPLICIT_BZERO
1069 explicit_bzero(answer, SULOGIN_PASSWORD_BUFSIZ);
1070 #endif
1071 exit(EXIT_FAILURE);
1072 }
1073
1074 /* no password or locked account */
1075 if (!passwd[0] || locked_account_password(passwd))
1076 doshell++;
1077 else {
1078 const char *cryptbuf;
1079 cryptbuf = crypt(answer, passwd);
1080 if (cryptbuf == NULL)
1081 warn(_("crypt failed"));
1082 else if (strcmp(cryptbuf, pwd->pw_passwd) == 0)
1083 doshell++;
1084 }
1085 #ifdef HAVE_EXPLICIT_BZERO
1086 explicit_bzero(answer, SULOGIN_PASSWORD_BUFSIZ);
1087 #endif
1088 if (doshell) {
1089 /* sushell() unmask signals */
1090 sushell(pwd);
1091
1092 mask_signal(SIGQUIT, SIG_IGN, &saved_sigquit);
1093 mask_signal(SIGTSTP, SIG_IGN, &saved_sigtstp);
1094 mask_signal(SIGINT, SIG_IGN, &saved_sigint);
1095
1096 fprintf(stderr, _("cannot execute su shell\n\n"));
1097 break;
1098 }
1099 fprintf(stderr, _("Login incorrect\n\n"));
1100 }
1101 if (alarm_rised) {
1102 tcfinal(con);
1103 warnx(_("Timed out\n\n"));
1104 }
1105 /*
1106 * User pressed Control-D.
1107 */
1108 exit(0);
1109 case -1:
1110 warn(_("fork failed"));
1111 /* fallthrough */
1112 default:
1113 break;
1114 }
1115 next:
1116 ptr = ptr->next;
1117
1118 } while (ptr != &consoles);
1119
1120 do {
1121 int ret;
1122
1123 status.si_pid = 0;
1124 ret = waitid(P_ALL, 0, &status, WEXITED);
1125
1126 if (ret == 0)
1127 break;
1128 if (ret < 0) {
1129 if (errno == ECHILD)
1130 break;
1131 if (errno == EINTR)
1132 continue;
1133 }
1134
1135 errx(EXIT_FAILURE, _("cannot wait on su shell\n\n"));
1136
1137 } while (1);
1138
1139 list_for_each(ptr, &consoles) {
1140 con = list_entry(ptr, struct console, entry);
1141
1142 if (con->fd < 0)
1143 continue;
1144 if (con->pid < 0)
1145 continue;
1146 if (con->pid == status.si_pid)
1147 con->pid = -1;
1148 else {
1149 kill(con->pid, SIGTERM);
1150 wait++;
1151 }
1152 }
1153
1154 sigemptyset(&set);
1155 sigaddset(&set, SIGCHLD);
1156
1157 do {
1158 int signum, ret;
1159
1160 if (!wait)
1161 break;
1162
1163 status.si_pid = 0;
1164 ret = waitid(P_ALL, 0, &status, WEXITED|WNOHANG);
1165
1166 if (ret < 0) {
1167 if (errno == ECHILD)
1168 break;
1169 if (errno == EINTR)
1170 continue;
1171 }
1172
1173 if (!ret && status.si_pid > 0) {
1174 list_for_each(ptr, &consoles) {
1175 con = list_entry(ptr, struct console, entry);
1176
1177 if (con->fd < 0)
1178 continue;
1179 if (con->pid < 0)
1180 continue;
1181 if (con->pid == status.si_pid) {
1182 con->pid = -1;
1183 wait--;
1184 }
1185 }
1186 continue;
1187 }
1188
1189 signum = sigtimedwait(&set, NULL, &sigwait);
1190 if (signum != SIGCHLD && signum < 0 && errno == EAGAIN)
1191 break;
1192
1193 } while (1);
1194
1195 mask_signal(SIGCHLD, SIG_DFL, NULL);
1196 return EXIT_SUCCESS;
1197 }