hush: fix incorrect PS2 dispaly and trap handling while reading command
[oweals/busybox.git] / loginutils / sulogin.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini sulogin implementation for busybox
4  *
5  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6  */
7
8 //usage:#define sulogin_trivial_usage
9 //usage:       "[-t N] [TTY]"
10 //usage:#define sulogin_full_usage "\n\n"
11 //usage:       "Single user login\n"
12 //usage:     "\nOptions:"
13 //usage:     "\n        -t N    Timeout"
14
15 #include "libbb.h"
16 #include <syslog.h>
17
18 //static void catchalarm(int UNUSED_PARAM junk)
19 //{
20 //      exit(EXIT_FAILURE);
21 //}
22
23
24 int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
25 int sulogin_main(int argc UNUSED_PARAM, char **argv)
26 {
27         char *cp;
28         int timeout = 0;
29         struct passwd *pwd;
30         const char *shell;
31 #if ENABLE_FEATURE_SHADOWPASSWDS
32         /* Using _r function to avoid pulling in static buffers */
33         char buffer[256];
34         struct spwd spw;
35 #endif
36
37         logmode = LOGMODE_BOTH;
38         openlog(applet_name, 0, LOG_AUTH);
39
40         opt_complementary = "t+"; /* -t N */
41         getopt32(argv, "t:", &timeout);
42         argv += optind;
43
44         if (argv[0]) {
45                 close(0);
46                 close(1);
47                 dup(xopen(argv[0], O_RDWR));
48                 close(2);
49                 dup(0);
50         }
51
52         /* Malicious use like "sulogin /dev/sda"? */
53         if (!isatty(0) || !isatty(1) || !isatty(2)) {
54                 logmode = LOGMODE_SYSLOG;
55                 bb_error_msg_and_die("not a tty");
56         }
57
58         /* Clear dangerous stuff, set PATH */
59         sanitize_env_if_suid();
60
61         pwd = getpwuid(0);
62         if (!pwd) {
63                 goto auth_error;
64         }
65
66 #if ENABLE_FEATURE_SHADOWPASSWDS
67         {
68                 /* getspnam_r may return 0 yet set result to NULL.
69                  * At least glibc 2.4 does this. Be extra paranoid here. */
70                 struct spwd *result = NULL;
71                 int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result);
72                 if (r || !result) {
73                         goto auth_error;
74                 }
75                 pwd->pw_passwd = result->sp_pwdp;
76         }
77 #endif
78
79         while (1) {
80                 char *encrypted;
81                 int r;
82
83                 /* cp points to a static buffer that is zeroed every time */
84                 cp = bb_ask(STDIN_FILENO, timeout,
85                                 "Give root password for system maintenance\n"
86                                 "(or type Control-D for normal startup):");
87
88                 if (!cp || !*cp) {
89                         bb_info_msg("Normal startup");
90                         return 0;
91                 }
92                 encrypted = pw_encrypt(cp, pwd->pw_passwd, 1);
93                 r = strcmp(encrypted, pwd->pw_passwd);
94                 free(encrypted);
95                 if (r == 0) {
96                         break;
97                 }
98                 bb_do_delay(LOGIN_FAIL_DELAY);
99                 bb_info_msg("Login incorrect");
100         }
101         memset(cp, 0, strlen(cp));
102 //      signal(SIGALRM, SIG_DFL);
103
104         bb_info_msg("System Maintenance Mode");
105
106         IF_SELINUX(renew_current_security_context());
107
108         shell = getenv("SUSHELL");
109         if (!shell)
110                 shell = getenv("sushell");
111         if (!shell)
112                 shell = pwd->pw_shell;
113
114         /* Exec login shell with no additional parameters. Never returns. */
115         run_shell(shell, 1, NULL, NULL);
116
117  auth_error:
118         bb_error_msg_and_die("no password entry for root");
119 }