1 | /* vi: set sw=4 ts=4: */
|
---|
2 | /*
|
---|
3 | * Mini su implementation for busybox
|
---|
4 | *
|
---|
5 | * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
|
---|
6 | */
|
---|
7 |
|
---|
8 | #include "libbb.h"
|
---|
9 | #include <syslog.h>
|
---|
10 |
|
---|
11 | #define SU_OPT_mp (3)
|
---|
12 | #define SU_OPT_l (4)
|
---|
13 |
|
---|
14 | int su_main(int argc, char **argv);
|
---|
15 | int su_main(int argc, char **argv)
|
---|
16 | {
|
---|
17 | unsigned flags;
|
---|
18 | char *opt_shell = NULL;
|
---|
19 | char *opt_command = NULL;
|
---|
20 | const char *opt_username = "root";
|
---|
21 | struct passwd *pw;
|
---|
22 | uid_t cur_uid = getuid();
|
---|
23 | const char *tty;
|
---|
24 | char *old_user;
|
---|
25 |
|
---|
26 | flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell);
|
---|
27 | argc -= optind;
|
---|
28 | argv += optind;
|
---|
29 |
|
---|
30 | if (argc && LONE_DASH(argv[0])) {
|
---|
31 | flags |= SU_OPT_l;
|
---|
32 | argc--;
|
---|
33 | argv++;
|
---|
34 | }
|
---|
35 |
|
---|
36 | /* get user if specified */
|
---|
37 | if (argc) {
|
---|
38 | opt_username = argv[0];
|
---|
39 | // argc--;
|
---|
40 | argv++;
|
---|
41 | }
|
---|
42 |
|
---|
43 | if (ENABLE_FEATURE_SU_SYSLOG) {
|
---|
44 | /* The utmp entry (via getlogin) is probably the best way to identify
|
---|
45 | the user, especially if someone su's from a su-shell.
|
---|
46 | But getlogin can fail -- usually due to lack of utmp entry.
|
---|
47 | in this case resort to getpwuid. */
|
---|
48 | old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : "");
|
---|
49 | tty = ttyname(2) ? : "none";
|
---|
50 | openlog(applet_name, 0, LOG_AUTH);
|
---|
51 | }
|
---|
52 |
|
---|
53 | pw = getpwnam(opt_username);
|
---|
54 | if (!pw)
|
---|
55 | bb_error_msg_and_die("unknown id: %s", opt_username);
|
---|
56 |
|
---|
57 | /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER
|
---|
58 | is a username that is retrieved via NIS (YP), but that doesn't have
|
---|
59 | a default shell listed. */
|
---|
60 | if (!pw->pw_shell || !pw->pw_shell[0])
|
---|
61 | pw->pw_shell = (char *)DEFAULT_SHELL;
|
---|
62 |
|
---|
63 | if ((cur_uid == 0) || correct_password(pw)) {
|
---|
64 | if (ENABLE_FEATURE_SU_SYSLOG)
|
---|
65 | syslog(LOG_NOTICE, "%c %s %s:%s",
|
---|
66 | '+', tty, old_user, opt_username);
|
---|
67 | } else {
|
---|
68 | if (ENABLE_FEATURE_SU_SYSLOG)
|
---|
69 | syslog(LOG_NOTICE, "%c %s %s:%s",
|
---|
70 | '-', tty, old_user, opt_username);
|
---|
71 | bb_error_msg_and_die("incorrect password");
|
---|
72 | }
|
---|
73 |
|
---|
74 | if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) {
|
---|
75 | closelog();
|
---|
76 | free(old_user);
|
---|
77 | }
|
---|
78 |
|
---|
79 | if (!opt_shell && (flags & SU_OPT_mp))
|
---|
80 | opt_shell = getenv("SHELL");
|
---|
81 |
|
---|
82 | #if ENABLE_FEATURE_SU_CHECKS_SHELLS
|
---|
83 | if (opt_shell && cur_uid && restricted_shell(pw->pw_shell)) {
|
---|
84 | /* The user being su'd to has a nonstandard shell, and so is
|
---|
85 | probably a uucp account or has restricted access. Don't
|
---|
86 | compromise the account by allowing access with a standard
|
---|
87 | shell. */
|
---|
88 | bb_error_msg("using restricted shell");
|
---|
89 | opt_shell = 0;
|
---|
90 | }
|
---|
91 | #endif
|
---|
92 | if (!opt_shell)
|
---|
93 | opt_shell = pw->pw_shell;
|
---|
94 |
|
---|
95 | change_identity(pw);
|
---|
96 | setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw);
|
---|
97 | USE_SELINUX(set_current_security_context(NULL);)
|
---|
98 |
|
---|
99 | /* Never returns */
|
---|
100 | run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
|
---|
101 |
|
---|
102 | return EXIT_FAILURE;
|
---|
103 | }
|
---|