static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo) { char salt[MAX_PW_SALT_LEN]; char *orig = (char*)""; char *newp = NULL; char *cp = NULL; char *ret = NULL; /* failure so far */ if (myuid != 0 && pw->pw_passwd[0]) { char *encrypted; orig = bb_ask_stdin("Old password: "******"incorrect password for %s", pw->pw_name); bb_do_delay(LOGIN_FAIL_DELAY); puts("Incorrect password"); goto err_ret; } if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); } orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ newp = bb_ask_stdin("New password: "******"Retype password: "******"Passwords don't match"); goto err_ret; } crypt_make_pw_salt(salt, algo); /* pw_encrypt returns malloced str */ ret = pw_encrypt(newp, salt, 1); /* whee, success! */ err_ret: nuke_str(orig); if (ENABLE_FEATURE_CLEAN_UP) free(orig); nuke_str(newp); if (ENABLE_FEATURE_CLEAN_UP) free(newp); nuke_str(cp); return ret; }
int vlock_main(int argc UNUSED_PARAM, char **argv) { #ifdef __linux__ struct vt_mode vtm; struct vt_mode ovtm; #endif struct termios term; struct termios oterm; struct passwd *pw; pw = xgetpwuid(getuid()); opt_complementary = "=0"; /* no params! */ getopt32(argv, "a"); /* Ignore some signals so that we don't get killed by them */ bb_signals(0 + (1 << SIGTSTP) + (1 << SIGTTIN) + (1 << SIGTTOU) + (1 << SIGHUP ) + (1 << SIGCHLD) /* paranoia :) */ + (1 << SIGQUIT) + (1 << SIGINT ) , SIG_IGN); #ifdef __linux__ /* We will use SIGUSRx for console switch control: */ /* 1: set handlers */ signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt); /* 2: unmask them */ sig_unblock(SIGUSR1); sig_unblock(SIGUSR2); #endif /* Revert stdin/out to our controlling tty * (or die if we have none) */ xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); #ifdef __linux__ xioctl(STDIN_FILENO, VT_GETMODE, &vtm); ovtm = vtm; /* "console switches are controlled by us, not kernel!" */ vtm.mode = VT_PROCESS; vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; ioctl(STDIN_FILENO, VT_SETMODE, &vtm); #endif //TODO: use set_termios_to_raw() tcgetattr(STDIN_FILENO, &oterm); term = oterm; term.c_iflag |= IGNBRK; /* ignore serial break (why? VTs don't have breaks, right?) */ term.c_iflag &= ~BRKINT; /* redundant? "dont translate break to SIGINT" */ term.c_lflag &= ~(ISIG | ECHO | ECHOCTL); /* ignore ^C ^Z, echo off */ tcsetattr_stdin_TCSANOW(&term); while (1) { printf("Virtual console%s locked by %s.\n", /* "s" if -a, else "": */ "s" + !option_mask32, pw->pw_name ); if (ask_and_check_password(pw) > 0) { break; } bb_do_delay(LOGIN_FAIL_DELAY); puts("Incorrect password"); } #ifdef __linux__ ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); #endif tcsetattr_stdin_TCSANOW(&oterm); fflush_stdout_and_exit(EXIT_SUCCESS); }
int sulogin_main(int argc, char **argv) { char *cp; char *device = NULL; const char *name = "root"; int timeout = 0; #define pass bb_common_bufsiz1 struct passwd pwent; struct passwd *pwd; const char * const *p; #if ENABLE_FEATURE_SHADOWPASSWDS struct spwd *spwd = NULL; #endif openlog("sulogin", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); if (argc > 1) { if (strncmp(argv[1], "-t", 2) == 0) { if (argv[1][2] == '\0') { /* -t NN */ if (argc > 2) { timeout = atoi(argv[2]); if (argc > 3) { device = argv[3]; } } } else { /* -tNNN */ timeout = atoi(&argv[1][2]); if (argc > 2) { device = argv[2]; } } } else { device = argv[1]; } if (device) { close(0); close(1); close(2); if (open(device, O_RDWR) == 0) { dup(0); dup(0); } else { syslog(LOG_WARNING, "cannot open %s\n", device); exit(EXIT_FAILURE); } } } if (access(bb_path_passwd_file, 0) == -1) { syslog(LOG_WARNING, "No password file\n"); bb_error_msg_and_die("No password file\n"); } if (!isatty(0) || !isatty(1) || !isatty(2)) { exit(EXIT_FAILURE); } /* Clear out anything dangerous from the environment */ for (p = forbid; *p; p++) unsetenv(*p); signal(SIGALRM, catchalarm); if (!(pwd = getpwnam(name))) { syslog(LOG_WARNING, "No password entry for `root'\n"); bb_error_msg_and_die("No password entry for `root'\n"); } pwent = *pwd; #if ENABLE_FEATURE_SHADOWPASSWDS spwd = NULL; if (pwd && ((strcmp(pwd->pw_passwd, "x") == 0) || (strcmp(pwd->pw_passwd, "*") == 0))) { endspent(); spwd = getspnam(name); if (spwd) { pwent.pw_passwd = spwd->sp_pwdp; } } #endif while (1) { cp = bb_askpass(timeout, SULOGIN_PROMPT); if (!cp || !*cp) { puts("\n"); fflush(stdout); syslog(LOG_INFO, "Normal startup\n"); exit(EXIT_SUCCESS); } else { safe_strncpy(pass, cp, sizeof(pass)); memset(cp, 0, strlen(cp)); } if (strcmp(pw_encrypt(pass, pwent.pw_passwd), pwent.pw_passwd) == 0) { break; } bb_do_delay(FAIL_DELAY); puts("Login incorrect"); fflush(stdout); syslog(LOG_WARNING, "Incorrect root password\n"); } memset(pass, 0, strlen(pass)); signal(SIGALRM, SIG_DFL); puts("Entering System Maintenance Mode\n"); fflush(stdout); syslog(LOG_INFO, "System Maintenance Mode\n"); #if ENABLE_SELINUX renew_current_security_context(); #endif run_shell(pwent.pw_shell, 1, 0, 0); return (0); }
int sulogin_main(int argc, char **argv) { char *cp; int timeout = 0; char *timeout_arg; const char * const *p; struct passwd *pwd; const char *shell; #if ENABLE_FEATURE_SHADOWPASSWDS /* Using _r function to avoid pulling in static buffers */ char buffer[256]; struct spwd spw; struct spwd *result; #endif logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); if (getopt32(argc, argv, "t:", &timeout_arg)) { timeout = xatoi_u(timeout_arg); } if (argv[optind]) { close(0); close(1); dup(xopen(argv[optind], O_RDWR)); close(2); dup(0); } if (!isatty(0) || !isatty(1) || !isatty(2)) { logmode = LOGMODE_SYSLOG; bb_error_msg_and_die("not a tty"); } /* Clear out anything dangerous from the environment */ for (p = forbid; *p; p++) unsetenv(*p); signal(SIGALRM, catchalarm); pwd = getpwuid(0); if (!pwd) { goto auth_error; } #if ENABLE_FEATURE_SHADOWPASSWDS if (getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result)) { goto auth_error; } pwd->pw_passwd = spw.sp_pwdp; #endif while (1) { /* cp points to a static buffer that is zeroed every time */ cp = bb_askpass(timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):"); if (!cp || !*cp) { bb_info_msg("Normal startup"); return 0; } if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) { break; } bb_do_delay(FAIL_DELAY); bb_error_msg("login incorrect"); } memset(cp, 0, strlen(cp)); signal(SIGALRM, SIG_DFL); bb_info_msg("System Maintenance Mode"); USE_SELINUX(renew_current_security_context()); shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); if (!shell) { shell = "/bin/sh"; if (pwd->pw_shell[0]) shell = pwd->pw_shell; } run_shell(shell, 1, 0, 0); /* never returns */ auth_error: bb_error_msg_and_die("no password entry for 'root'"); }
int vlock_main(int argc, char **argv) { sigset_t sig; struct sigaction sa; struct vt_mode vtm; struct termios term; uid_t uid = getuid(); pw = getpwuid(uid); if (pw == NULL) bb_error_msg_and_die("unknown uid %d", uid); if (argc > 2) { bb_show_usage(); } o_lock_all = getopt32(argc, argv, "a"); vfd = xopen(CURRENT_TTY, O_RDWR); if (ioctl(vfd, VT_GETMODE, &vtm) < 0) { bb_perror_msg_and_die("VT_GETMODE"); } /* mask a bunch of signals */ sigprocmask(SIG_SETMASK, NULL, &sig); sigdelset(&sig, SIGUSR1); sigdelset(&sig, SIGUSR2); sigaddset(&sig, SIGTSTP); sigaddset(&sig, SIGTTIN); sigaddset(&sig, SIGTTOU); sigaddset(&sig, SIGHUP); sigaddset(&sig, SIGCHLD); sigaddset(&sig, SIGQUIT); sigaddset(&sig, SIGINT); sigemptyset(&(sa.sa_mask)); sa.sa_flags = SA_RESTART; sa.sa_handler = release_vt; sigaction(SIGUSR1, &sa, NULL); sa.sa_handler = acquire_vt; sigaction(SIGUSR2, &sa, NULL); /* need to handle some signals so that we don't get killed by them */ sa.sa_handler = SIG_IGN; sigaction(SIGHUP, &sa, NULL); sigaction(SIGQUIT, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGTSTP, &sa, NULL); ovtm = vtm; vtm.mode = VT_PROCESS; vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; ioctl(vfd, VT_SETMODE, &vtm); tcgetattr(STDIN_FILENO, &oterm); term = oterm; term.c_iflag &= ~BRKINT; term.c_iflag |= IGNBRK; term.c_lflag &= ~ISIG; term.c_lflag &= ~(ECHO | ECHOCTL); tcsetattr(STDIN_FILENO, TCSANOW, &term); do { printf("Virtual Console%s locked by %s.\n", (o_lock_all) ? "s" : "", pw->pw_name); if (correct_password(pw)) { break; } bb_do_delay(FAIL_DELAY); puts("Password incorrect"); } while (1); restore_terminal(); fflush_stdout_and_exit(0); }
int vlock_main(int argc ATTRIBUTE_UNUSED, char **argv) { struct vt_mode vtm; struct termios term; struct termios oterm; struct vt_mode ovtm; uid_t uid; struct passwd *pw; uid = getuid(); pw = getpwuid(uid); if (pw == NULL) bb_error_msg_and_die("unknown uid %d", (int)uid); opt_complementary = "=0"; /* no params! */ getopt32(argv, "a"); /* Ignore some signals so that we don't get killed by them */ bb_signals(0 + (1 << SIGTSTP) + (1 << SIGTTIN) + (1 << SIGTTOU) + (1 << SIGHUP ) + (1 << SIGCHLD) /* paranoia :) */ + (1 << SIGQUIT) + (1 << SIGINT ) , SIG_IGN); /* We will use SIGUSRx for console switch control: */ /* 1: set handlers */ signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); signal_SA_RESTART_empty_mask(SIGUSR2, acquire_vt); /* 2: unmask them */ sig_unblock(SIGUSR1); sig_unblock(SIGUSR2); /* Revert stdin/out to our controlling tty * (or die if we have none) */ xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); xioctl(STDIN_FILENO, VT_GETMODE, &vtm); ovtm = vtm; /* "console switches are controlled by us, not kernel!" */ vtm.mode = VT_PROCESS; vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; ioctl(STDIN_FILENO, VT_SETMODE, &vtm); tcgetattr(STDIN_FILENO, &oterm); term = oterm; term.c_iflag &= ~BRKINT; term.c_iflag |= IGNBRK; term.c_lflag &= ~ISIG; term.c_lflag &= ~(ECHO | ECHOCTL); tcsetattr(STDIN_FILENO, TCSANOW, &term); do { printf("Virtual console%s locked by %s.\n", option_mask32 /*o_lock_all*/ ? "s" : "", pw->pw_name); if (correct_password(pw)) { break; } bb_do_delay(FAIL_DELAY); puts("Password incorrect"); } while (1); ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); tcsetattr(STDIN_FILENO, TCSANOW, &oterm); fflush_stdout_and_exit(EXIT_SUCCESS); }
int login_main(int argc, char **argv) { char tty[BUFSIZ]; char full_tty[200]; char fromhost[512]; char username[USERNAME_SIZE]; const char *tmp; int amroot; int flag; int failed; int count=0; struct passwd *pw, pw_copy; #ifdef CONFIG_WHEEL_GROUP struct group *grp; #endif int opt_preserve = 0; int opt_fflag = 0; char *opt_host = 0; int alarmstarted = 0; #ifdef CONFIG_SELINUX security_context_t stat_sid = NULL, sid = NULL, old_tty_sid=NULL, new_tty_sid=NULL; #endif username[0]=0; amroot = ( getuid ( ) == 0 ); signal ( SIGALRM, alarm_handler ); alarm ( TIMEOUT ); alarmstarted = 1; while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) { switch ( flag ) { case 'p': opt_preserve = 1; break; case 'f': /* * username must be a separate token * (-f root, *NOT* -froot). --marekm */ if ( optarg != argv[optind-1] ) bb_show_usage( ); if ( !amroot ) /* Auth bypass only if real UID is zero */ bb_error_msg_and_die ( "-f permission denied" ); safe_strncpy(username, optarg, USERNAME_SIZE); opt_fflag = 1; break; case 'h': opt_host = optarg; break; default: bb_show_usage( ); } } if (optind < argc) // user from command line (getty) safe_strncpy(username, argv[optind], USERNAME_SIZE); if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 )) return EXIT_FAILURE; /* Must be a terminal */ #ifdef CONFIG_FEATURE_UTMP checkutmp ( !amroot ); #endif tmp = ttyname ( 0 ); if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 )) safe_strncpy ( tty, tmp + 5, sizeof( tty )); else if ( tmp && *tmp == '/' ) safe_strncpy ( tty, tmp, sizeof( tty )); else safe_strncpy ( tty, "UNKNOWN", sizeof( tty )); #ifdef CONFIG_FEATURE_UTMP if ( amroot ) memset ( utent.ut_host, 0, sizeof utent.ut_host ); #endif if ( opt_host ) { #ifdef CONFIG_FEATURE_UTMP safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host )); #endif snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host ); } else snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty ); setpgrp(); openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH ); while ( 1 ) { failed = 0; if ( !username[0] ) if(!login_prompt ( username )) return EXIT_FAILURE; if ( !alarmstarted && ( TIMEOUT > 0 )) { alarm ( TIMEOUT ); alarmstarted = 1; } if (!( pw = getpwnam ( username ))) { pw_copy.pw_name = "UNKNOWN"; pw_copy.pw_passwd = "!"; opt_fflag = 0; failed = 1; } else pw_copy = *pw; pw = &pw_copy; if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' )) failed = 1; if ( opt_fflag ) { opt_fflag = 0; goto auth_ok; } if (!failed && ( pw-> pw_uid == 0 ) && ( !check_tty ( tty ))) failed = 1; /* Don't check the password if password entry is empty (!) */ if ( !pw-> pw_passwd[0] ) goto auth_ok; /* authorization takes place here */ if ( correct_password ( pw )) goto auth_ok; failed = 1; auth_ok: if ( !failed) break; bb_do_delay(FAIL_DELAY); puts("Login incorrect"); username[0] = 0; if ( ++count == 3 ) { syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw->pw_name, fromhost); return EXIT_FAILURE; } } alarm ( 0 ); if ( check_nologin ( pw-> pw_uid == 0 )) return EXIT_FAILURE; #ifdef CONFIG_FEATURE_UTMP setutmp ( username, tty ); #endif if ( *tty != '/' ) snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty); else safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 ); #ifdef CONFIG_SELINUX if (is_selinux_enabled()) { struct stat st; int rc; if (get_default_context(username, NULL, &sid)) { fprintf(stderr, "Unable to get SID for %s\n", username); exit(1); } rc = getfilecon(full_tty,&stat_sid); freecon(stat_sid); if ((rc<0) || (stat(full_tty, &st)<0)) { fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", full_tty, strerror(errno)); return EXIT_FAILURE; } if (security_compute_relabel (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0) { fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", full_tty, strerror(errno)); return EXIT_FAILURE; } if(setfilecon(full_tty, new_tty_sid) != 0) { fprintf(stderr, "chsid(%.100s, %s) failed: %.100s\n", full_tty, new_tty_sid, strerror(errno)); return EXIT_FAILURE; } freecon(sid); freecon(old_tty_sid); freecon(new_tty_sid); } #endif if ( !is_my_tty ( full_tty )) syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty ); /* Try these, but don't complain if they fail * (for example when the root fs is read only) */ chown ( full_tty, pw-> pw_uid, pw-> pw_gid ); chmod ( full_tty, 0600 ); change_identity ( pw ); tmp = pw-> pw_shell; if(!tmp || !*tmp) tmp = DEFAULT_SHELL; setup_environment ( tmp, 1, !opt_preserve, pw ); motd ( ); signal ( SIGALRM, SIG_DFL ); /* default alarm signal */ if ( pw-> pw_uid == 0 ) syslog ( LOG_INFO, "root login %s\n", fromhost ); #ifdef CONFIG_SELINUX set_current_security_context(sid); #endif run_shell ( tmp, 1, 0, 0); /* exec the shell finally. */ return EXIT_FAILURE; }
int sulogin_main(int argc UNUSED_PARAM, char **argv) { char *cp; int timeout = 0; struct passwd *pwd; const char *shell; #if ENABLE_FEATURE_SHADOWPASSWDS /* Using _r function to avoid pulling in static buffers */ char buffer[256]; struct spwd spw; #endif logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); opt_complementary = "t+"; /* -t N */ getopt32(argv, "t:", &timeout); argv += optind; if (argv[0]) { close(0); close(1); dup(xopen(argv[0], O_RDWR)); close(2); dup(0); } /* Malicious use like "sulogin /dev/sda"? */ if (!isatty(0) || !isatty(1) || !isatty(2)) { logmode = LOGMODE_SYSLOG; bb_error_msg_and_die("not a tty"); } /* Clear dangerous stuff, set PATH */ sanitize_env_if_suid(); pwd = getpwuid(0); if (!pwd) { goto auth_error; } #if ENABLE_FEATURE_SHADOWPASSWDS { /* getspnam_r may return 0 yet set result to NULL. * At least glibc 2.4 does this. Be extra paranoid here. */ struct spwd *result = NULL; int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result); if (r || !result) { goto auth_error; } pwd->pw_passwd = result->sp_pwdp; } #endif while (1) { char *encrypted; int r; /* cp points to a static buffer */ cp = bb_ask(STDIN_FILENO, timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):"); if (!cp) { /* ^D, ^C, timeout, or read error */ bb_info_msg("Normal startup"); return 0; } encrypted = pw_encrypt(cp, pwd->pw_passwd, 1); r = strcmp(encrypted, pwd->pw_passwd); free(encrypted); if (r == 0) { break; } bb_do_delay(LOGIN_FAIL_DELAY); bb_info_msg("Login incorrect"); } memset(cp, 0, strlen(cp)); // signal(SIGALRM, SIG_DFL); bb_info_msg("System Maintenance Mode"); IF_SELINUX(renew_current_security_context()); shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); if (!shell) shell = pwd->pw_shell; /* Exec login shell with no additional parameters. Never returns. */ run_shell(shell, 1, NULL, NULL); auth_error: bb_error_msg_and_die("no password entry for root"); }
int su_main(int argc UNUSED_PARAM, char **argv) { unsigned flags; char *opt_shell = NULL; char *opt_command = NULL; const char *opt_username = "******"; struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; #if ENABLE_FEATURE_UTMP char user_buf[64]; #endif const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); //argc -= optind; argv += optind; if (argv[0] && LONE_DASH(argv[0])) { flags |= SU_OPT_l; argv++; } /* get user if specified */ if (argv[0]) { opt_username = argv[0]; argv++; } if (ENABLE_FEATURE_SU_SYSLOG) { /* The utmp entry (via getlogin) is probably the best way to * identify the user, especially if someone su's from a su-shell. * But getlogin can fail -- usually due to lack of utmp entry. * in this case resort to getpwuid. */ #if ENABLE_FEATURE_UTMP old_user = user_buf; if (getlogin_r(user_buf, sizeof(user_buf)) != 0) #endif { pw = getpwuid(cur_uid); old_user = pw ? xstrdup(pw->pw_name) : ""; } tty = xmalloc_ttyname(2); if (!tty) { tty = "none"; } openlog(applet_name, 0, LOG_AUTH); } pw = xgetpwnam(opt_username); if (cur_uid == 0 || ask_and_check_password(pw) > 0) { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); } else { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '-', tty, old_user, opt_username); bb_do_delay(LOGIN_FAIL_DELAY); bb_error_msg_and_die("incorrect password"); } if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { closelog(); } if (!opt_shell && (flags & SU_OPT_mp)) { /* -s SHELL is not given, but "preserve env" opt is */ opt_shell = getenv("SHELL"); } #if ENABLE_FEATURE_SU_CHECKS_SHELLS if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) { /* The user being su'd to has a nonstandard shell, and so is * probably a uucp account or has restricted access. Don't * compromise the account by allowing access with a standard * shell. */ bb_error_msg("using restricted shell"); opt_shell = NULL; /* ignore -s PROG */ } /* else: user can run whatever he wants via "su -s PROG USER". * This is safe since PROG is run under user's uid/gid. */ #endif if (!opt_shell) opt_shell = pw->pw_shell; change_identity(pw); setup_environment(opt_shell, ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV) + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR), pw); IF_SELINUX(set_current_security_context(NULL);)
int sulogin_main(int argc UNUSED_PARAM, char **argv) { int timeout = 0; struct passwd *pwd; const char *shell; /* Note: sulogin is not a suid app. It is meant to be run by init * for single user / emergency mode. init starts it as root. * Normal users (potentially malisious ones) can only run it under * their UID, therefore no paranoia here is warranted: * $LD_LIBRARY_PATH in env, TTY = /dev/sda * are no more dangerous here than in e.g. cp applet. */ logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); getopt32(argv, "t:+", &timeout); argv += optind; if (argv[0]) { close(0); close(1); dup(xopen(argv[0], O_RDWR)); close(2); dup(0); } pwd = getpwuid(0); if (!pwd) { bb_error_msg_and_die("no password entry for root"); } while (1) { int r; r = ask_and_check_password_extended(pwd, timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):" ); if (r < 0) { /* ^D, ^C, timeout, or read error */ bb_error_msg("normal startup"); return 0; } if (r > 0) { break; } bb_do_delay(LOGIN_FAIL_DELAY); bb_error_msg("Login incorrect"); } bb_error_msg("starting shell for system maintenance"); IF_SELINUX(renew_current_security_context()); shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); if (!shell) shell = pwd->pw_shell; /* Exec login shell with no additional parameters. Never returns. */ run_shell(shell, 1, NULL); }
int sulogin_main(int argc, char **argv) { char *cp; int timeout = 0; char *timeout_arg; struct passwd *pwd; const char *shell; #if ENABLE_FEATURE_SHADOWPASSWDS /* Using _r function to avoid pulling in static buffers */ char buffer[256]; struct spwd spw; #endif logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); if (getopt32(argv, "t:", &timeout_arg)) { timeout = xatoi_u(timeout_arg); } if (argv[optind]) { close(0); close(1); dup(xopen(argv[optind], O_RDWR)); close(2); dup(0); } if (!isatty(0) || !isatty(1) || !isatty(2)) { logmode = LOGMODE_SYSLOG; bb_error_msg_and_die("not a tty"); } /* Clear dangerous stuff, set PATH */ sanitize_env_for_suid(); // bb_askpass() already handles this // signal(SIGALRM, catchalarm); pwd = getpwuid(0); if (!pwd) { goto auth_error; } #if ENABLE_FEATURE_SHADOWPASSWDS { /* getspnam_r may return 0 yet set result to NULL. * At least glibc 2.4 does this. Be extra paranoid here. */ struct spwd *result = NULL; int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result); if (r || !result) { goto auth_error; } pwd->pw_passwd = result->sp_pwdp; } #endif while (1) { /* cp points to a static buffer that is zeroed every time */ cp = bb_askpass(timeout, "Give root password for system maintenance\n" "(or type Control-D for normal startup):"); if (!cp || !*cp) { bb_info_msg("Normal startup"); return 0; } if (strcmp(pw_encrypt(cp, pwd->pw_passwd), pwd->pw_passwd) == 0) { break; } bb_do_delay(FAIL_DELAY); bb_error_msg("login incorrect"); } memset(cp, 0, strlen(cp)); // signal(SIGALRM, SIG_DFL); bb_info_msg("System Maintenance Mode"); USE_SELINUX(renew_current_security_context()); shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); if (!shell) { shell = "/bin/sh"; if (pwd->pw_shell[0]) shell = pwd->pw_shell; } /* Exec login shell with no additional parameters. Never returns. */ run_shell(shell, 1, NULL, NULL); auth_error: bb_error_msg_and_die("no password entry for root"); }