1 /* vi: set sw=4 ts=4: */
3 * Mini su implementation for busybox
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 //usage:#define su_trivial_usage
12 //usage: "[OPTIONS] [-] [USER]"
13 //usage:#define su_full_usage "\n\n"
14 //usage: "Run shell under USER (by default, root)\n"
15 //usage: "\n -,-l Clear environment, run shell as login shell"
16 //usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME"
17 //usage: "\n -c CMD Command to pass to 'sh -c'"
18 //usage: "\n -s SH Shell to use instead of user's default"
20 #if ENABLE_FEATURE_SU_CHECKS_SHELLS
21 /* Return 1 if SHELL is a restricted shell (one not returned by
22 * getusershell), else 0, meaning it is a standard shell. */
23 static int restricted_shell(const char *shell
)
28 /*setusershell(); - getusershell does it itself*/
29 while ((line
= getusershell()) != NULL
) {
30 if (/* *line != '#' && */ strcmp(line
, shell
) == 0) {
35 if (ENABLE_FEATURE_CLEAN_UP
)
44 int su_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
45 int su_main(int argc UNUSED_PARAM
, char **argv
)
48 char *opt_shell
= NULL
;
49 char *opt_command
= NULL
;
50 const char *opt_username
= "root";
52 uid_t cur_uid
= getuid();
54 #if ENABLE_FEATURE_UTMP
59 flags
= getopt32(argv
, "mplc:s:", &opt_command
, &opt_shell
);
63 if (argv
[0] && LONE_DASH(argv
[0])) {
68 /* get user if specified */
70 opt_username
= argv
[0];
74 if (ENABLE_FEATURE_SU_SYSLOG
) {
75 /* The utmp entry (via getlogin) is probably the best way to
76 * identify the user, especially if someone su's from a su-shell.
77 * But getlogin can fail -- usually due to lack of utmp entry.
78 * in this case resort to getpwuid. */
79 #if ENABLE_FEATURE_UTMP
81 if (getlogin_r(user_buf
, sizeof(user_buf
)) != 0)
84 pw
= getpwuid(cur_uid
);
85 old_user
= pw
? xstrdup(pw
->pw_name
) : "";
87 tty
= xmalloc_ttyname(2);
91 openlog(applet_name
, 0, LOG_AUTH
);
94 pw
= xgetpwnam(opt_username
);
96 if (cur_uid
== 0 || correct_password(pw
)) {
97 if (ENABLE_FEATURE_SU_SYSLOG
)
98 syslog(LOG_NOTICE
, "%c %s %s:%s",
99 '+', tty
, old_user
, opt_username
);
101 if (ENABLE_FEATURE_SU_SYSLOG
)
102 syslog(LOG_NOTICE
, "%c %s %s:%s",
103 '-', tty
, old_user
, opt_username
);
104 bb_error_msg_and_die("incorrect password");
107 if (ENABLE_FEATURE_CLEAN_UP
&& ENABLE_FEATURE_SU_SYSLOG
) {
111 if (!opt_shell
&& (flags
& SU_OPT_mp
)) {
112 /* -s SHELL is not given, but "preserve env" opt is */
113 opt_shell
= getenv("SHELL");
116 #if ENABLE_FEATURE_SU_CHECKS_SHELLS
117 if (opt_shell
&& cur_uid
!= 0 && pw
->pw_shell
&& restricted_shell(pw
->pw_shell
)) {
118 /* The user being su'd to has a nonstandard shell, and so is
119 * probably a uucp account or has restricted access. Don't
120 * compromise the account by allowing access with a standard
122 bb_error_msg("using restricted shell");
123 opt_shell
= NULL
; /* ignore -s PROG */
125 /* else: user can run whatever he wants via "su -s PROG USER".
126 * This is safe since PROG is run under user's uid/gid. */
129 opt_shell
= pw
->pw_shell
;
132 setup_environment(opt_shell
,
133 ((flags
& SU_OPT_l
) / SU_OPT_l
* SETUP_ENV_CLEARENV
)
134 + (!(flags
& SU_OPT_mp
) * SETUP_ENV_CHANGEENV
),
136 IF_SELINUX(set_current_security_context(NULL
);)
139 run_shell(opt_shell
, flags
& SU_OPT_l
, opt_command
, (const char**)argv
);
141 /* return EXIT_FAILURE; - not reached */