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