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