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 | /* |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 3 | * Mini su implementation for busybox |
| 4 | * |
Bernhard Reutner-Fischer | 7fee0c4 | 2006-09-13 16:39:19 +0000 | [diff] [blame] | 5 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. |
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 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 11 | #define SU_OPT_mp (3) |
| 12 | #define SU_OPT_l (4) |
| 13 | |
Denis Vlasenko | 9b49a5e | 2007-10-11 10:05:36 +0000 | [diff] [blame] | 14 | int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 15 | int su_main(int argc ATTRIBUTE_UNUSED, char **argv) |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 16 | { |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 17 | unsigned flags; |
Denis Vlasenko | 06c0a71 | 2007-01-29 22:51:44 +0000 | [diff] [blame] | 18 | char *opt_shell = NULL; |
| 19 | char *opt_command = NULL; |
| 20 | const char *opt_username = "root"; |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 21 | struct passwd *pw; |
| 22 | uid_t cur_uid = getuid(); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 23 | const char *tty; |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 24 | char *old_user; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 25 | |
Denis Vlasenko | fe7cd64 | 2007-08-18 15:32:12 +0000 | [diff] [blame] | 26 | flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 27 | //argc -= optind; |
Denis Vlasenko | e13a537 | 2006-12-23 02:59:06 +0000 | [diff] [blame] | 28 | argv += optind; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 29 | |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 30 | if (argv[0] && LONE_DASH(argv[0])) { |
Bernhard Reutner-Fischer | df798b7 | 2006-06-14 16:36:45 +0000 | [diff] [blame] | 31 | flags |= SU_OPT_l; |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 32 | argv++; |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 33 | } |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 34 | |
| 35 | /* get user if specified */ |
Denis Vlasenko | 62a90cd | 2008-03-17 09:07:36 +0000 | [diff] [blame] | 36 | if (argv[0]) { |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 37 | opt_username = argv[0]; |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 38 | argv++; |
| 39 | } |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 40 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 41 | if (ENABLE_FEATURE_SU_SYSLOG) { |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 42 | /* The utmp entry (via getlogin) is probably the best way to identify |
| 43 | the user, especially if someone su's from a su-shell. |
| 44 | But getlogin can fail -- usually due to lack of utmp entry. |
| 45 | in this case resort to getpwuid. */ |
Rob Landley | d921b2e | 2006-08-03 15:41:12 +0000 | [diff] [blame] | 46 | old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : ""); |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 47 | tty = ttyname(2) ? : "none"; |
Denis Vlasenko | 8f8f268 | 2006-10-03 21:00:43 +0000 | [diff] [blame] | 48 | openlog(applet_name, 0, LOG_AUTH); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 49 | } |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 50 | |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 51 | pw = getpwnam(opt_username); |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 52 | if (!pw) |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 53 | bb_error_msg_and_die("unknown id: %s", opt_username); |
Eric Andersen | c7bda1c | 2004-03-15 08:29:22 +0000 | [diff] [blame] | 54 | |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 55 | /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER |
| 56 | is a username that is retrieved via NIS (YP), but that doesn't have |
| 57 | a default shell listed. */ |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 58 | if (!pw->pw_shell || !pw->pw_shell[0]) |
| 59 | pw->pw_shell = (char *)DEFAULT_SHELL; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 60 | |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 61 | if ((cur_uid == 0) || correct_password(pw)) { |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 62 | if (ENABLE_FEATURE_SU_SYSLOG) |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 63 | syslog(LOG_NOTICE, "%c %s %s:%s", |
| 64 | '+', tty, old_user, opt_username); |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 65 | } else { |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 66 | if (ENABLE_FEATURE_SU_SYSLOG) |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 67 | syslog(LOG_NOTICE, "%c %s %s:%s", |
| 68 | '-', tty, old_user, opt_username); |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 69 | bb_error_msg_and_die("incorrect password"); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 70 | } |
| 71 | |
Bernhard Reutner-Fischer | 359d7ca | 2006-12-19 08:55:38 +0000 | [diff] [blame] | 72 | if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 73 | closelog(); |
| 74 | free(old_user); |
| 75 | } |
Glenn L McGrath | a6b7bdc | 2003-08-29 07:38:56 +0000 | [diff] [blame] | 76 | |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 77 | if (!opt_shell && (flags & SU_OPT_mp)) |
| 78 | opt_shell = getenv("SHELL"); |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 79 | |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 80 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 81 | if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) { |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 82 | /* The user being su'd to has a nonstandard shell, and so is |
| 83 | probably a uucp account or has restricted access. Don't |
| 84 | compromise the account by allowing access with a standard |
| 85 | shell. */ |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 86 | bb_error_msg("using restricted shell"); |
Denis Vlasenko | a2f6101 | 2007-09-10 13:15:28 +0000 | [diff] [blame] | 87 | opt_shell = NULL; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 88 | } |
Denis Vlasenko | 15b213e | 2006-12-19 00:20:20 +0000 | [diff] [blame] | 89 | #endif |
| 90 | if (!opt_shell) |
| 91 | opt_shell = pw->pw_shell; |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 92 | |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 93 | change_identity(pw); |
Denis Vlasenko | cdf6277 | 2008-03-17 08:42:43 +0000 | [diff] [blame] | 94 | /* setup_environment params: shell, clear_env, change_env, pw */ |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 95 | setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw); |
Denis Vlasenko | a980165 | 2006-09-07 16:20:03 +0000 | [diff] [blame] | 96 | USE_SELINUX(set_current_security_context(NULL);) |
Rob Landley | 3bfcf3c | 2006-07-10 03:05:46 +0000 | [diff] [blame] | 97 | |
Rob Landley | 1870737 | 2006-07-15 19:46:46 +0000 | [diff] [blame] | 98 | /* Never returns */ |
Denis Vlasenko | 9f73944 | 2006-12-16 23:49:13 +0000 | [diff] [blame] | 99 | 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] | 100 | |
Denis Vlasenko | a2f6101 | 2007-09-10 13:15:28 +0000 | [diff] [blame] | 101 | /* return EXIT_FAILURE; - not reached */ |
Robert Griebl | 1fca558 | 2002-06-04 20:45:46 +0000 | [diff] [blame] | 102 | } |