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 || correct_password(pw)) { 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_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), pw); IF_SELINUX(set_current_security_context(NULL);)
int su_main ( int argc, char **argv ) { unsigned long flags; char *opt_shell = 0; char *opt_command = 0; char *opt_username = DEFAULT_USER; char **opt_args = 0; struct passwd *pw; uid_t cur_uid = getuid(); #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) const char *tty; const char *old_user; #endif flags = bb_getopt_ulflags(argc, argv, "mplc:s:", &opt_command, &opt_shell); #define SU_OPT_m (3) #define SU_OPT_p (3) #define SU_OPT_l (4) if (optind < argc && argv[optind][0] == '-' && argv[optind][1] == 0) { flags |= SU_OPT_l; ++optind; } /* get user if specified */ if ( optind < argc ) opt_username = argv [optind++]; if ( optind < argc ) opt_args = argv + optind; #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) #ifdef CONFIG_FEATURE_UTMP /* The utmp entry (via getlogin) is probably the best way to identify the user, especially if someone su's from a su-shell. */ old_user = getlogin ( ); if ( !old_user ) #endif { /* getlogin can fail -- usually due to lack of utmp entry. Resort to getpwuid. */ pw = getpwuid ( cur_uid ); old_user = ( pw ? pw->pw_name : "" ); } tty = ttyname ( 2 ); if(!tty) tty = "none"; openlog ( bb_applet_name, 0, LOG_AUTH ); #endif pw = getpwnam ( opt_username ); if ( !pw ) bb_error_msg_and_die ( "user %s does not exist", opt_username ); /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER is a username that is retrieved via NIS (YP), but that doesn't have a default shell listed. */ if ( !pw->pw_shell || !pw->pw_shell [0] ) pw->pw_shell = (char *) DEFAULT_SHELL; if ((( cur_uid == 0 ) || correct_password ( pw ))) { log_su_successful(pw->pw_uid, old_user, tty ); } else { log_su_failure (pw->pw_uid, old_user, tty ); bb_error_msg_and_die ( "incorrect password" ); } #if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE ) closelog(); #endif if ( !opt_shell && (flags & SU_OPT_p)) opt_shell = getenv ( "SHELL" ); if ( opt_shell && cur_uid && 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. */ fputs ( "using restricted shell\n", stderr ); opt_shell = 0; } if ( !opt_shell ) opt_shell = pw->pw_shell; change_identity ( pw ); setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_p), pw); #if ENABLE_SELINUX set_current_security_context(NULL); #endif run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)opt_args); return EXIT_FAILURE; }
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; }