source: MondoRescue/branches/3.3/mindi-busybox/loginutils/su.c@ 3803

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 4.7 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini su implementation for busybox
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */
7//config:config SU
8//config: bool "su"
9//config: default y
10//config: select FEATURE_SYSLOG
11//config: help
12//config: su is used to become another user during a login session.
13//config: Invoked without a username, su defaults to becoming the super user.
14//config:
15//config: Note that Busybox binary must be setuid root for this applet to
16//config: work properly.
17//config:
18//config:config FEATURE_SU_SYSLOG
19//config: bool "Enable su to write to syslog"
20//config: default y
21//config: depends on SU
22//config:
23//config:config FEATURE_SU_CHECKS_SHELLS
24//config: bool "Enable su to check user's shell to be listed in /etc/shells"
25//config: depends on SU
26//config: default y
27
28//applet:/* Needs to be run by root or be suid root - needs to change uid and gid: */
29//applet:IF_SU(APPLET(su, BB_DIR_BIN, BB_SUID_REQUIRE))
30
31//kbuild:lib-$(CONFIG_SU) += su.o
32
33//usage:#define su_trivial_usage
34//usage: "[OPTIONS] [-] [USER]"
35//usage:#define su_full_usage "\n\n"
36//usage: "Run shell under USER (by default, root)\n"
37//usage: "\n -,-l Clear environment, run shell as login shell"
38//usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME"
39//usage: "\n -c CMD Command to pass to 'sh -c'"
40//usage: "\n -s SH Shell to use instead of user's default"
41
42#include "libbb.h"
43#include <syslog.h>
44
45#if ENABLE_FEATURE_SU_CHECKS_SHELLS
46/* Return 1 if SHELL is a restricted shell (one not returned by
47 * getusershell), else 0, meaning it is a standard shell. */
48static int restricted_shell(const char *shell)
49{
50 char *line;
51 int result = 1;
52
53 /*setusershell(); - getusershell does it itself*/
54 while ((line = getusershell()) != NULL) {
55 if (/* *line != '#' && */ strcmp(line, shell) == 0) {
56 result = 0;
57 break;
58 }
59 }
60 if (ENABLE_FEATURE_CLEAN_UP)
61 endusershell();
62 return result;
63}
64#endif
65
66#define SU_OPT_mp (3)
67#define SU_OPT_l (4)
68
69int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
70int su_main(int argc UNUSED_PARAM, char **argv)
71{
72 unsigned flags;
73 char *opt_shell = NULL;
74 char *opt_command = NULL;
75 const char *opt_username = "root";
76 struct passwd *pw;
77 uid_t cur_uid = getuid();
78 const char *tty;
79#if ENABLE_FEATURE_UTMP
80 char user_buf[64];
81#endif
82 const char *old_user;
83
84 flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
85 //argc -= optind;
86 argv += optind;
87
88 if (argv[0] && LONE_DASH(argv[0])) {
89 flags |= SU_OPT_l;
90 argv++;
91 }
92
93 /* get user if specified */
94 if (argv[0]) {
95 opt_username = argv[0];
96 argv++;
97 }
98
99 if (ENABLE_FEATURE_SU_SYSLOG) {
100 /* The utmp entry (via getlogin) is probably the best way to
101 * identify the user, especially if someone su's from a su-shell.
102 * But getlogin can fail -- usually due to lack of utmp entry.
103 * in this case resort to getpwuid. */
104#if ENABLE_FEATURE_UTMP
105 old_user = user_buf;
106 if (getlogin_r(user_buf, sizeof(user_buf)) != 0)
107#endif
108 {
109 pw = getpwuid(cur_uid);
110 old_user = pw ? xstrdup(pw->pw_name) : "";
111 }
112 tty = xmalloc_ttyname(2);
113 if (!tty) {
114 tty = "none";
115 }
116 openlog(applet_name, 0, LOG_AUTH);
117 }
118
119 pw = xgetpwnam(opt_username);
120
121 if (cur_uid == 0 || ask_and_check_password(pw) > 0) {
122 if (ENABLE_FEATURE_SU_SYSLOG)
123 syslog(LOG_NOTICE, "%c %s %s:%s",
124 '+', tty, old_user, opt_username);
125 } else {
126 if (ENABLE_FEATURE_SU_SYSLOG)
127 syslog(LOG_NOTICE, "%c %s %s:%s",
128 '-', tty, old_user, opt_username);
129 bb_do_delay(LOGIN_FAIL_DELAY);
130 bb_error_msg_and_die("incorrect password");
131 }
132
133 if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) {
134 closelog();
135 }
136
137 if (!opt_shell && (flags & SU_OPT_mp)) {
138 /* -s SHELL is not given, but "preserve env" opt is */
139 opt_shell = getenv("SHELL");
140 }
141
142#if ENABLE_FEATURE_SU_CHECKS_SHELLS
143 if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) {
144 /* The user being su'd to has a nonstandard shell, and so is
145 * probably a uucp account or has restricted access. Don't
146 * compromise the account by allowing access with a standard
147 * shell. */
148 bb_error_msg("using restricted shell");
149 opt_shell = NULL; /* ignore -s PROG */
150 }
151 /* else: user can run whatever he wants via "su -s PROG USER".
152 * This is safe since PROG is run under user's uid/gid. */
153#endif
154 if (!opt_shell)
155 opt_shell = pw->pw_shell;
156
157 change_identity(pw);
158 setup_environment(opt_shell,
159 ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV)
160 + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV)
161 + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR),
162 pw);
163 IF_SELINUX(set_current_security_context(NULL);)
164
165 /* Never returns */
166 run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
167
168 /* return EXIT_FAILURE; - not reached */
169}
Note: See TracBrowser for help on using the repository browser.