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