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