Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
Bernhard Reutner-Fischer | 5a620ea | 2006-01-19 18:04:15 +0000 | [diff] [blame] | 2 | /* |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 3 | * Mini su implementation for busybox |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 4 | * |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 6 | */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 7 | |
Denis Vlasenko | b6adbf1 | 2007-05-26 19:00:18 +0000 | [diff] [blame] | 8 | #include "libbb.h" |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 9 | #include <syslog.h> |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 10 | |
Denys Vlasenko | a9e25ff | 2010-12-31 02:52:35 +0100 | [diff] [blame] | 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" |
Denys Vlasenko | a9e25ff | 2010-12-31 02:52:35 +0100 | [diff] [blame] | 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" |
| 19 | |
Denys Vlasenko | 26ffe81 | 2010-02-26 10:01:18 +0100 | [diff] [blame] | 20 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS |
| 21 | /* Return 1 if SHELL is a restricted shell (one not returned by |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 22 | * getusershell), else 0, meaning it is a standard shell. */ |
Denys Vlasenko | 26ffe81 | 2010-02-26 10:01:18 +0100 | [diff] [blame] | 23 | static int restricted_shell(const char *shell) |
| 24 | { |
| 25 | char *line; |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 26 | int result = 1; |
Denys Vlasenko | 26ffe81 | 2010-02-26 10:01:18 +0100 | [diff] [blame] | 27 | |
| 28 | /*setusershell(); - getusershell does it itself*/ |
| 29 | while ((line = getusershell()) != NULL) { |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 30 | if (/* *line != '#' && */ strcmp(line, shell) == 0) { |
| 31 | result = 0; |
| 32 | break; |
| 33 | } |
Denys Vlasenko | 26ffe81 | 2010-02-26 10:01:18 +0100 | [diff] [blame] | 34 | } |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 35 | if (ENABLE_FEATURE_CLEAN_UP) |
| 36 | endusershell(); |
| 37 | return result; |
Denys Vlasenko | 26ffe81 | 2010-02-26 10:01:18 +0100 | [diff] [blame] | 38 | } |
| 39 | #endif |
| 40 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 41 | #define SU_OPT_mp (3) |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 42 | #define SU_OPT_l (4) |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 43 | |
Denis Vlasenko | 9b49a5e | 2007-10-11 10:05:36 +0000 | [diff] [blame] | 44 | int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
Denis Vlasenko | a60f84e | 2008-07-05 09:18:54 +0000 | [diff] [blame] | 45 | int su_main(int argc UNUSED_PARAM, char **argv) |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 46 | { |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 47 | unsigned flags; |
Denis Vlasenko | 06c0a71 | 2007-01-29 22:51:44 +0000 | [diff] [blame] | 48 | char *opt_shell = NULL; |
| 49 | char *opt_command = NULL; |
| 50 | const char *opt_username = "root"; |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 51 | struct passwd *pw; |
| 52 | uid_t cur_uid = getuid(); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 53 | const char *tty; |
Denys Vlasenko | 631fd5c | 2010-11-30 09:47:56 +0100 | [diff] [blame] | 54 | #if ENABLE_FEATURE_UTMP |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 55 | char user_buf[64]; |
Denys Vlasenko | 631fd5c | 2010-11-30 09:47:56 +0100 | [diff] [blame] | 56 | #endif |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 57 | const char *old_user; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 58 | |
Denis Vlasenko | fe7cd64 | 2007-08-18 15:32:12 +0000 | [diff] [blame] | 59 | flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 60 | //argc -= optind; |
Denis Vlasenko | e13a537 | 2006-12-23 02:59:06 +0000 | [diff] [blame] | 61 | argv += optind; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 62 | |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 63 | if (argv[0] && LONE_DASH(argv[0])) { |
Bernhard Reutner-Fischer | df798b7 | 2006-06-14 16:36:45 +0000 | [diff] [blame] | 64 | flags |= SU_OPT_l; |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 65 | argv++; |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 66 | } |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 67 | |
| 68 | /* get user if specified */ |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 69 | if (argv[0]) { |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 70 | opt_username = argv[0]; |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 71 | argv++; |
| 72 | } |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 73 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 74 | if (ENABLE_FEATURE_SU_SYSLOG) { |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 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. |
Denys Vlasenko | d069e53 | 2009-09-09 23:12:10 +0200 | [diff] [blame] | 77 | * But getlogin can fail -- usually due to lack of utmp entry. |
| 78 | * in this case resort to getpwuid. */ |
Denys Vlasenko | d069e53 | 2009-09-09 23:12:10 +0200 | [diff] [blame] | 79 | #if ENABLE_FEATURE_UTMP |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 80 | old_user = user_buf; |
Denys Vlasenko | d069e53 | 2009-09-09 23:12:10 +0200 | [diff] [blame] | 81 | if (getlogin_r(user_buf, sizeof(user_buf)) != 0) |
| 82 | #endif |
| 83 | { |
| 84 | pw = getpwuid(cur_uid); |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 85 | old_user = pw ? xstrdup(pw->pw_name) : ""; |
Denys Vlasenko | d069e53 | 2009-09-09 23:12:10 +0200 | [diff] [blame] | 86 | } |
Denys Vlasenko | d069e53 | 2009-09-09 23:12:10 +0200 | [diff] [blame] | 87 | tty = xmalloc_ttyname(2); |
| 88 | if (!tty) { |
| 89 | tty = "none"; |
| 90 | } |
Denis Vlasenko | 8f8f268 | 2006-10-03 21:00:43 +0000 | [diff] [blame] | 91 | openlog(applet_name, 0, LOG_AUTH); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 92 | } |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 93 | |
Denis Vlasenko | d7a805e | 2008-12-03 19:05:55 +0000 | [diff] [blame] | 94 | pw = xgetpwnam(opt_username); |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 95 | |
maxwen | 27116ba | 2015-08-14 21:41:28 +0200 | [diff] [blame] | 96 | if (cur_uid == 0 || ask_and_check_password(pw) > 0) { |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 97 | if (ENABLE_FEATURE_SU_SYSLOG) |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 98 | syslog(LOG_NOTICE, "%c %s %s:%s", |
| 99 | '+', tty, old_user, opt_username); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 100 | } else { |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 101 | if (ENABLE_FEATURE_SU_SYSLOG) |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 102 | syslog(LOG_NOTICE, "%c %s %s:%s", |
| 103 | '-', tty, old_user, opt_username); |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 104 | bb_error_msg_and_die("incorrect password"); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 105 | } |
| 106 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 107 | if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 108 | closelog(); |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 109 | } |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 110 | |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 111 | if (!opt_shell && (flags & SU_OPT_mp)) { |
| 112 | /* -s SHELL is not given, but "preserve env" opt is */ |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 113 | opt_shell = getenv("SHELL"); |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 114 | } |
| 115 | |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 116 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS |
Denys Vlasenko | bd74e3d | 2011-03-06 18:49:40 +0100 | [diff] [blame] | 117 | if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) { |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 118 | /* The user being su'd to has a nonstandard shell, and so is |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 119 | * probably a uucp account or has restricted access. Don't |
| 120 | * compromise the account by allowing access with a standard |
| 121 | * shell. */ |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 122 | bb_error_msg("using restricted shell"); |
Denys Vlasenko | bd74e3d | 2011-03-06 18:49:40 +0100 | [diff] [blame] | 123 | opt_shell = NULL; /* ignore -s PROG */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 124 | } |
Ladislav Michl | a73b87e | 2010-06-27 03:23:31 +0200 | [diff] [blame] | 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. */ |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 127 | #endif |
| 128 | if (!opt_shell) |
| 129 | opt_shell = pw->pw_shell; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 130 | |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 131 | change_identity(pw); |
Denys Vlasenko | fd686a2 | 2010-02-26 09:52:45 +0100 | [diff] [blame] | 132 | setup_environment(opt_shell, |
| 133 | ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) |
Pascal Bellard | 0414e02 | 2012-06-12 13:21:02 +0200 | [diff] [blame] | 134 | + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV) |
| 135 | + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR), |
Denys Vlasenko | fd686a2 | 2010-02-26 09:52:45 +0100 | [diff] [blame] | 136 | pw); |
Denis Vlasenko | 5e34ff2 | 2009-04-21 11:09:40 +0000 | [diff] [blame] | 137 | IF_SELINUX(set_current_security_context(NULL);) |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 138 | |
Rob Landley | 1870737 | 2006-07-15 19:46:46 +0000 | [diff] [blame] | 139 | /* Never returns */ |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 140 | run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 141 | |
Denis Vlasenko | a2f6101 | 2007-09-10 13:15:28 +0000 | [diff] [blame] | 142 | /* return EXIT_FAILURE; - not reached */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 143 | } |