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