su: suppress "warning: unused variable 'user_buf'"
[platform/upstream/busybox.git] / loginutils / su.c
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
8 #include "libbb.h"
9 #include <syslog.h>
10
11 #if ENABLE_FEATURE_SU_CHECKS_SHELLS
12 /* Return 1 if SHELL is a restricted shell (one not returned by
13  * getusershell), else 0, meaning it is a standard shell.  */
14 static int restricted_shell(const char *shell)
15 {
16         char *line;
17         int result = 1;
18
19         /*setusershell(); - getusershell does it itself*/
20         while ((line = getusershell()) != NULL) {
21                 if (/* *line != '#' && */ strcmp(line, shell) == 0) {
22                         result = 0;
23                         break;
24                 }
25         }
26         if (ENABLE_FEATURE_CLEAN_UP)
27                 endusershell();
28         return result;
29 }
30 #endif
31
32 #define SU_OPT_mp (3)
33 #define SU_OPT_l  (4)
34
35 int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
36 int su_main(int argc UNUSED_PARAM, char **argv)
37 {
38         unsigned flags;
39         char *opt_shell = NULL;
40         char *opt_command = NULL;
41         const char *opt_username = "root";
42         struct passwd *pw;
43         uid_t cur_uid = getuid();
44         const char *tty;
45 #if ENABLE_FEATURE_UTMP
46         char user_buf[64];
47 #endif
48         const char *old_user;
49
50         flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
51         //argc -= optind;
52         argv += optind;
53
54         if (argv[0] && LONE_DASH(argv[0])) {
55                 flags |= SU_OPT_l;
56                 argv++;
57         }
58
59         /* get user if specified */
60         if (argv[0]) {
61                 opt_username = argv[0];
62                 argv++;
63         }
64
65         if (ENABLE_FEATURE_SU_SYSLOG) {
66                 /* The utmp entry (via getlogin) is probably the best way to
67                  * identify the user, especially if someone su's from a su-shell.
68                  * But getlogin can fail -- usually due to lack of utmp entry.
69                  * in this case resort to getpwuid.  */
70 #if ENABLE_FEATURE_UTMP
71                 old_user = user_buf;
72                 if (getlogin_r(user_buf, sizeof(user_buf)) != 0)
73 #endif
74                 {
75                         pw = getpwuid(cur_uid);
76                         old_user = pw ? xstrdup(pw->pw_name) : "";
77                 }
78                 tty = xmalloc_ttyname(2);
79                 if (!tty) {
80                         tty = "none";
81                 }
82                 openlog(applet_name, 0, LOG_AUTH);
83         }
84
85         pw = xgetpwnam(opt_username);
86
87         if (cur_uid == 0 || correct_password(pw)) {
88                 if (ENABLE_FEATURE_SU_SYSLOG)
89                         syslog(LOG_NOTICE, "%c %s %s:%s",
90                                 '+', tty, old_user, opt_username);
91         } else {
92                 if (ENABLE_FEATURE_SU_SYSLOG)
93                         syslog(LOG_NOTICE, "%c %s %s:%s",
94                                 '-', tty, old_user, opt_username);
95                 bb_error_msg_and_die("incorrect password");
96         }
97
98         if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) {
99                 closelog();
100         }
101
102         if (!opt_shell && (flags & SU_OPT_mp)) {
103                 /* -s SHELL is not given, but "preserve env" opt is */
104                 opt_shell = getenv("SHELL");
105         }
106
107         /* Make sure pw->pw_shell is non-NULL.  It may be NULL when NEW_USER
108          * is a username that is retrieved via NIS (YP), that doesn't have
109          * a default shell listed.  */
110         if (!pw->pw_shell || !pw->pw_shell[0])
111                 pw->pw_shell = (char *)DEFAULT_SHELL;
112
113 #if ENABLE_FEATURE_SU_CHECKS_SHELLS
114         if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) {
115                 /* The user being su'd to has a nonstandard shell, and so is
116                  * probably a uucp account or has restricted access.  Don't
117                  * compromise the account by allowing access with a standard
118                  * shell.  */
119                 bb_error_msg("using restricted shell");
120                 opt_shell = NULL;
121         }
122         /* else: user can run whatever he wants via "su -s PROG USER".
123          * This is safe since PROG is run under user's uid/gid. */
124 #endif
125         if (!opt_shell)
126                 opt_shell = pw->pw_shell;
127
128         change_identity(pw);
129         setup_environment(opt_shell,
130                         ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV)
131                         + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV),
132                         pw);
133         IF_SELINUX(set_current_security_context(NULL);)
134
135         /* Never returns */
136         run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
137
138         /* return EXIT_FAILURE; - not reached */
139 }