fef3760e99dbaebdd9cc7868a1b21f44ba9114c8
[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 "busybox.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 {
39         char *cp;
40         int timeout = 0;
41         char *timeout_arg;
42         const char * const *p;
43         struct passwd *pwd;
44         struct spwd *spwd;
45
46         logmode = LOGMODE_BOTH;
47         openlog(bb_applet_name, 0, LOG_AUTH);
48
49         if (bb_getopt_ulflags (argc, argv, "t:", &timeout_arg)) {
50                 if (safe_strtoi(timeout_arg, &timeout)) {
51                         timeout = 0;
52                 }
53         }
54
55         if (argv[optind]) {
56                 close(0);
57                 close(1);
58                 close(2);
59                 dup(xopen(argv[optind], O_RDWR));
60                 dup(0);
61         }
62
63         if (!isatty(0) || !isatty(1) || !isatty(2)) {
64                 logmode = LOGMODE_SYSLOG;
65                 bb_error_msg_and_die("not a tty");
66         }
67
68         /* Clear out anything dangerous from the environment */
69         for (p = forbid; *p; p++)
70                 unsetenv(*p);
71
72         signal(SIGALRM, catchalarm);
73
74         if (!(pwd = getpwuid(0))) {
75                 goto auth_error;
76         } 
77
78         if (ENABLE_FEATURE_SHADOWPASSWDS) {
79                 if (!(spwd = getspnam(pwd->pw_name))) {
80                         goto auth_error;
81                 }
82                 pwd->pw_passwd = spwd->sp_pwdp;
83         }
84
85         while (1) {
86                 /* cp points to a static buffer that is zeroed every time */
87                 cp = bb_askpass(timeout,
88                                 "Give root password for system maintenance\n"
89                                 "(or type Control-D for normal startup):");
90
91                 if (!cp || !*cp) {
92                         bb_info_msg("Normal startup");
93                         return 0;
94                 }
95                 if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) {
96                         break;
97                 }
98                 bb_do_delay(FAIL_DELAY);
99                 bb_error_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         USE_SELINUX(renew_current_security_context());
107
108         run_shell(pwd->pw_shell, 1, 0, 0);
109         /* never returns */
110
111 auth_error:     
112         bb_error_msg_and_die("no password entry for `root'");
113 }