diff options
Diffstat (limited to 'command/su.c')
-rw-r--r-- | command/su.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/command/su.c b/command/su.c new file mode 100644 index 0000000..942f37e --- /dev/null +++ b/command/su.c @@ -0,0 +1,104 @@ +#include "command.h" +#include "lslib.h" + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static struct { + bool clear_env; + bool update_env; + char* shell; + char* user; +} flags; + +static bool restricted_shell(const char *shell) { + char *line; + int result = true; + + while ((line = getusershell()) != NULL) { + if (strcmp(line, shell) == 0) { + result = false; + break; + } + } + endusershell(); + return result; +} + +static void help (void) { + printf("Usage: su [-lmp] [-s SH] [-] [USER [FILE ARGS]] \n\n"); + printf("Run shell under USER (by default, root)\n\n"); + printf("\t-,-l\tClear environment, go to home dir, run shell as login shell\n"); + printf("\t-p,-m\tDo not set new $HOME, $SHELL, $USER, $LOGNAME\n"); + printf("\t-s SH Shell\tto use instead of user's default\n"); +} + +static int short_arg (char c, char* next) { + switch (c) { + case 'l': + flags.clear_env = true; + break; + case 'p': + case 'm': + flags.update_env = false; + break; + case 's': + check_arg(next); + flags.shell = next; + return ARG_USED; + default: + return ARG_INVALID; + + } + return ARG_UNUSED; +} + +COMMAND (su) { + + int start, res; + uid_t cur_uid; + struct passwd* pw; + + flags.clear_env = false; + flags.update_env = true; + flags.shell = NULL; + flags.user = "root"; + + start = parse_args(argc, argv, help, short_arg, NULL); + + if (start < argc && streql(argv[start], "-")) { + flags.clear_env = true; + start++; + } + + if (start < argc) + flags.user = argv[start++]; + + pw = xgetpwnam(flags.user); + cur_uid = getuid(); + + if (cur_uid != 0) { + res = prompt_password(pw, "Password: "); + } else { + res = PASSWORD_VALID; + } + + if (res != PASSWORD_VALID) { + error("invalid password"); + } + + if (flags.shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) { + error_s("using restricted shell"); + flags.shell = NULL; + } + + if (!flags.shell) + flags.shell = pw->pw_shell; + + change_identity(pw); + setup_environment(flags.shell, flags.update_env, flags.clear_env, pw); + exec_shell(flags.shell, flags.clear_env, (const char**) &argv[start]); + + return EXIT_FAILURE; /* */ +} |