aboutsummaryrefslogtreecommitdiff
path: root/loginutils/sulogin.c
blob: 15f3fb260491277775fda48728d899ca0d89fb17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* vi: set sw=4 ts=4: */
/*
 * Mini sulogin implementation for busybox
 *
 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
 */

#include <syslog.h>

#include "busybox.h"


#define SULOGIN_PROMPT "Give root password for system maintenance\n" \
	"(or type Control-D for normal startup):"

static const char * const forbid[] = {
	"ENV",
	"BASH_ENV",
	"HOME",
	"IFS",
	"PATH",
	"SHELL",
	"LD_LIBRARY_PATH",
	"LD_PRELOAD",
	"LD_TRACE_LOADED_OBJECTS",
	"LD_BIND_NOW",
	"LD_AOUT_LIBRARY_PATH",
	"LD_AOUT_PRELOAD",
	"LD_NOWARN",
	"LD_KEEPDIR",
	(char *) 0
};



static void catchalarm(int ATTRIBUTE_UNUSED junk)
{
	exit(EXIT_FAILURE);
}


int sulogin_main(int argc, char **argv)
{
	char *cp;
	int timeout = 0;
	char *timeout_arg;
	const char * const *p;
	struct passwd *pwd;
	struct spwd *spwd;

	if (ENABLE_FEATURE_SYSLOG) {
		logmode = LOGMODE_BOTH;
		openlog(bb_applet_name, LOG_CONS | LOG_NOWAIT, LOG_AUTH);
	}

	if (bb_getopt_ulflags (argc, argv, "t:", &timeout_arg)) {
		if (safe_strtoi(timeout_arg, &timeout)) {
			timeout = 0;
		}
	}

	if (argv[optind]) {
		close(0);
		close(1);
		close(2);
		dup(xopen(argv[optind], O_RDWR));
		dup(0);
	}

	if (!isatty(0) || !isatty(1) || !isatty(2)) {
		bb_error_msg_and_die("Not a tty");
	}

	/* Clear out anything dangerous from the environment */
	for (p = forbid; *p; p++)
		unsetenv(*p);

	signal(SIGALRM, catchalarm);

	if (!(pwd = getpwuid(0))) {
		goto AUTH_ERROR;
	} 

	if (ENABLE_FEATURE_SHADOWPASSWDS) {
		if (!(spwd = getspnam(pwd->pw_name))) {
			goto AUTH_ERROR;
		}
		pwd->pw_passwd = spwd->sp_pwdp;
	}

	while (1) {
		/* cp points to a static buffer that is zeroed every time */
		cp = bb_askpass(timeout, SULOGIN_PROMPT);
		if (!cp || !*cp) {
			bb_info_msg("Normal startup");
			exit(EXIT_SUCCESS);
		}
		if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) {
			break;
		}
		bb_do_delay(FAIL_DELAY);
		bb_error_msg("Login incorrect");
	}
	memset(cp, 0, strlen(cp));
	signal(SIGALRM, SIG_DFL);

	bb_info_msg("System Maintenance Mode");

	USE_SELINUX(renew_current_security_context());

	run_shell(pwd->pw_shell, 1, 0, 0);
	/* never returns */
AUTH_ERROR:	
	bb_error_msg_and_die("No password entry for `root'");
}