f1545b78fab2be38426de2da502eb9e8c3d38fbe
[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 tarball for details.
6  */
7
8 #include <syslog.h>
9
10 #include "libbb.h"
11
12 static const char forbid[] ALIGN1 =
13         "ENV" "\0"
14         "BASH_ENV" "\0"
15         "HOME" "\0"
16         "IFS" "\0"
17         "PATH" "\0"
18         "SHELL" "\0"
19         "LD_LIBRARY_PATH" "\0"
20         "LD_PRELOAD" "\0"
21         "LD_TRACE_LOADED_OBJECTS" "\0"
22         "LD_BIND_NOW" "\0"
23         "LD_AOUT_LIBRARY_PATH" "\0"
24         "LD_AOUT_PRELOAD" "\0"
25         "LD_NOWARN" "\0"
26         "LD_KEEPDIR" "\0";
27
28 //static void catchalarm(int ATTRIBUTE_UNUSED junk)
29 //{
30 //      exit(EXIT_FAILURE);
31 //}
32
33
34 int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
35 int sulogin_main(int argc, char **argv)
36 {
37         char *cp;
38         int timeout = 0;
39         char *timeout_arg;
40         const char *p;
41         struct passwd *pwd;
42         const char *shell;
43 #if ENABLE_FEATURE_SHADOWPASSWDS
44         /* Using _r function to avoid pulling in static buffers */
45         char buffer[256];
46         struct spwd spw;
47 #endif
48
49         logmode = LOGMODE_BOTH;
50         openlog(applet_name, 0, LOG_AUTH);
51
52         if (getopt32(argv, "t:", &timeout_arg)) {
53                 timeout = xatoi_u(timeout_arg);
54         }
55
56         if (argv[optind]) {
57                 close(0);
58                 close(1);
59                 dup(xopen(argv[optind], O_RDWR));
60                 close(2);
61                 dup(0);
62         }
63
64         if (!isatty(0) || !isatty(1) || !isatty(2)) {
65                 logmode = LOGMODE_SYSLOG;
66                 bb_error_msg_and_die("not a tty");
67         }
68
69         /* Clear out anything dangerous from the environment */
70         p = forbid;
71         do {
72                 unsetenv(p);
73                 p += strlen(p) + 1;
74         } while (*p);
75
76 // bb_askpass() already handles this
77 //      signal(SIGALRM, catchalarm);
78
79         pwd = getpwuid(0);
80         if (!pwd) {
81                 goto auth_error;
82         }
83
84 #if ENABLE_FEATURE_SHADOWPASSWDS
85         {
86                 /* getspnam_r may return 0 yet set result to NULL.
87                  * At least glibc 2.4 does this. Be extra paranoid here. */
88                 struct spwd *result = NULL;
89                 int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result);
90                 if (r || !result) {
91                         goto auth_error;
92                 }
93                 pwd->pw_passwd = result->sp_pwdp;
94         }
95 #endif
96
97         while (1) {
98                 /* cp points to a static buffer that is zeroed every time */
99                 cp = bb_askpass(timeout,
100                                 "Give root password for system maintenance\n"
101                                 "(or type Control-D for normal startup):");
102
103                 if (!cp || !*cp) {
104                         bb_info_msg("Normal startup");
105                         return 0;
106                 }
107                 if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) {
108                         break;
109                 }
110                 bb_do_delay(FAIL_DELAY);
111                 bb_error_msg("login incorrect");
112         }
113         memset(cp, 0, strlen(cp));
114 //      signal(SIGALRM, SIG_DFL);
115
116         bb_info_msg("System Maintenance Mode");
117
118         USE_SELINUX(renew_current_security_context());
119
120         shell = getenv("SUSHELL");
121         if (!shell)
122                 shell = getenv("sushell");
123         if (!shell) {
124                 shell = "/bin/sh";
125                 if (pwd->pw_shell[0])
126                         shell = pwd->pw_shell;
127         }
128         /* Exec login shell with no additional parameters. Never returns. */
129         run_shell(shell, 1, NULL, NULL);
130
131  auth_error:
132         bb_error_msg_and_die("no password entry for root");
133 }