static int ChangeUser(const char *user, short dochdir) { struct passwd *pas; /* * Obtain password entry and change privileges */ pas = getpwnam(user); if (pas == NULL) { bb_perror_msg_and_die("failed to get uid for %s", user); } setenv("USER", pas->pw_name, 1); setenv("HOME", pas->pw_dir, 1); setenv("SHELL", DEFAULT_SHELL, 1); /* * Change running state to the user in question */ change_identity(pas); if (dochdir) { if (chdir(pas->pw_dir) < 0) { bb_perror_msg("chdir(%s) by %s failed", pas->pw_dir, user); xchdir(TMPDIR); } } return pas->pw_uid; }
static void edit_file(const struct passwd *pas, const char *file) { const char *ptr; pid_t pid; pid = xvfork(); if (pid) { /* parent */ wait4pid(pid); return; } /* CHILD - change user and run editor */ /* initgroups, setgid, setuid */ change_identity(pas); setup_environment(pas->pw_shell, SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP, pas); ptr = getenv("VISUAL"); if (!ptr) { ptr = getenv("EDITOR"); if (!ptr) ptr = "vi"; } BB_EXECLP(ptr, ptr, file, NULL); bb_perror_msg_and_die("can't execute '%s'", ptr); }
static void change_user(struct passwd *pas) { /* careful: we're after vfork! */ change_identity(pas); /* - initgroups, setgid, setuid */ if (chdir(pas->pw_dir) < 0) { bb_error_msg("can't change directory to '%s'", pas->pw_dir); xchdir(CRON_DIR); } }
int change_identity_temporarily(ucred_t const* uc) { /* print_ucred("Changing identity temporarily", uc); */ /* pcred_t pcred; */ /* get_pcred(&pcred); */ /* print_pcred("Changing identity temporarily", &pcred); */ /* free(pcred.sups.list); */ return change_identity(uc, false); }
int change_identity_permanently(ucred_t const* uc) { /* print_ucred("Changing identity permanently", uc); */ /* pcred_t pcred; */ /* get_pcred(&pcred); */ /* print_pcred("Changing identity permanently", &pcred); */ /* free(pcred.sups.list); */ return change_identity(uc, true); }
static void ChangeUser(struct passwd *pas) { /* careful: we're after vfork! */ change_identity(pas); /* - initgroups, setgid, setuid */ if (chdir(pas->pw_dir) < 0) { crondlog(LVL9 "can't chdir(%s)", pas->pw_dir); if (chdir(TMPDIR) < 0) { crondlog(DIE9 "can't chdir(%s)", TMPDIR); /* exits */ } } }
static void change_user(const struct passwd *pas) { setenv("USER", pas->pw_name, 1); setenv("HOME", pas->pw_dir, 1); setenv("SHELL", DEFAULT_SHELL, 1); /* initgroups, setgid, setuid */ change_identity(pas); if (chdir(pas->pw_dir) < 0) { bb_perror_msg("chdir(%s) by %s failed", pas->pw_dir, pas->pw_name); xchdir("/tmp"); } }
AUTH * krb5_not_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname, int *downcall_err, int *chg_err, CLIENT **rpc_clnt) { AUTH *auth = NULL; gss_cred_id_t gss_cred; char **dname; int err, resp = -1; printerr(2, "krb5_not_machine_creds: uid %d tgtname %s\n", uid, tgtname); *chg_err = change_identity(uid); if (*chg_err) { printerr(0, "WARNING: failed to change identity: %s", strerror(*chg_err)); goto out; } /** Tell krb5 gss which credentials cache to use. * Try first to acquire credentials directly via GSSAPI */ err = gssd_acquire_user_cred(&gss_cred); if (err == 0) resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, &auth, uid, AUTHTYPE_KRB5, gss_cred); /** if create_auth_rplc_client fails try the traditional * method of trolling for credentials */ for (dname = ccachesearch; resp != 0 && *dname != NULL; dname++) { err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dname); if (err == -EKEYEXPIRED) *downcall_err = -EKEYEXPIRED; else if (err == 0) resp = create_auth_rpc_client(clp, tgtname, rpc_clnt, &auth, uid,AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL); } out: return auth; }
static int open_as_user(const struct passwd *pas, const char *file) { pid_t pid; char c; pid = xvfork(); if (pid) { /* PARENT */ if (wait4pid(pid) == 0) { /* exitcode 0: child says it can read */ return open(file, O_RDONLY); } return -1; } /* CHILD */ /* initgroups, setgid, setuid */ change_identity(pas); /* We just try to read one byte. If it works, file is readable * under this user. We signal that by exiting with 0. */ _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0); }
int main (int argc, char **argv) { const char *new_user; char **command = NULL; struct passwd *pw; struct passwd pw_copy; int infd, outfd, i; struct rlimit rlp; if (argv[1] && strcmp (argv[1], "--version") == 0) { printf ("%s\n", VERSION); return 0; } if (!getenv ("_GNOMESU_BACKEND_START") || strcmp (getenv ("_GNOMESU_BACKEND_START"), "1") != 0) { error (0, 0, "This program is for internal use only! Never run this program directly!"); return 1; } unsetenv ("_GNOMESU_BACKEND_START"); program_name = argv[0]; /* Parse arguments */ if (argc < 5) { error (0, 0, "Too little arguments."); return 1; } new_user = argv[3]; if (new_user[0] == '\0') new_user = DEFAULT_USER; infd = atoi (argv[1]); outfd = atoi (argv[2]); if (infd <= 2 || outfd <= 2) { error (0, 0, "Invalid file descriptors."); return 1; } inf = fdopen (infd, "r"); if (!inf) { error (0, 0, "Cannot fopen() INFD"); return 1; } outf = fdopen (outfd, "w"); if (!outf) { error (0, 0, "Cannot fopen() OUTFD"); return 1; } setlinebuf (outf); command = argv + 4; pw = getpwnam (new_user); if (pw == 0) { fprintf (outf, PROTOCOL_NO_SUCH_USER); return 1; } endpwent (); /* 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 == NULL || pw->pw_shell[0] == '\0') pw->pw_shell = (char *) DEFAULT_SHELL; /* Make a copy of the password information and point pw at the local copy instead. Otherwise, some systems (e.g. Linux) would clobber the static data through the getlogin call from log_su. */ pw_copy = *pw; pw = &pw_copy; pw->pw_name = xstrdup (pw->pw_name); pw->pw_dir = xstrdup (pw->pw_dir); pw->pw_shell = xstrdup (pw->pw_shell); /* Ask for password up to 3 times */ for (i = 0; i < 3; i++) { if (!correct_password (pw)) { #ifdef SYSLOG_FAILURE log_su (pw, 0); #endif usleep (2500000); fprintf (outf, PROTOCOL_INCORRECT_PASSWORD); if (i >= 2) { fprintf (outf, PROTOCOL_PASSWORD_FAIL); return 1; } } else { #ifdef SYSLOG_SUCCESS log_su (pw, 1); #endif break; } } init_xauth (pw); modify_environment (pw); init_groups (pw); if (change_identity (pw)) { fprintf (outf, PROTOCOL_ERROR); return 1; } setup_xauth (pw); fprintf (outf, PROTOCOL_DONE); fclose (inf); fclose (outf); /* Close all file handles except stdin/out/err */ getrlimit (RLIMIT_NOFILE, &rlp); for (i = 3; i < (int) rlp.rlim_cur; i++) close (i); execvp (command[0], command); /* This should never be reached! */ return 1; }
extern 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 int flask_enabled = is_flask_enabled(); security_id_t sid = 0, old_tty_sid, new_tty_sid; #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_U_W_TMP 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_U_W_TMP if ( amroot ) memset ( utent.ut_host, 0, sizeof utent.ut_host ); #endif if ( opt_host ) { #ifdef CONFIG_FEATURE_U_W_TMP 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; { // delay next try time_t start, now; time ( &start ); now = start; while ( difftime ( now, start ) < FAIL_DELAY) { sleep ( FAIL_DELAY ); time ( &now ); } } 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_U_W_TMP setutmp ( username, tty ); #endif #ifdef CONFIG_SELINUX if (flask_enabled) { struct stat st; if (get_default_sid(username, 0, &sid)) { fprintf(stderr, "Unable to get SID for %s\n", username); exit(1); } if (stat_secure(tty, &st, &old_tty_sid)) { fprintf(stderr, "stat_secure(%.100s) failed: %.100s\n", tty, strerror(errno)); return EXIT_FAILURE; } if (security_change_sid (sid, old_tty_sid, SECCLASS_CHR_FILE, &new_tty_sid) != 0) { fprintf(stderr, "security_change_sid(%.100s) failed: %.100s\n", tty, strerror(errno)); return EXIT_FAILURE; } if(chsid(tty, new_tty_sid) != 0) { fprintf(stderr, "chsid(%.100s, %d) failed: %.100s\n", tty, new_tty_sid, strerror(errno)); return EXIT_FAILURE; } } else sid = 0; #endif if ( *tty != '/' ) snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty); else safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 ); 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 ); run_shell ( tmp, 1, 0, 0 #ifdef CONFIG_SELINUX , sid #endif ); /* exec the shell finally. */ return EXIT_FAILURE; }
int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) { unsigned opt; char *signame; char *startas; char *chuid; #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY // char *retry_arg = NULL; // int retries = -1; char *opt_N; #endif INIT_G(); opt = GETOPT32(argv, "^" "KSbqtma:n:s:u:c:x:p:" IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") /* -K or -S is required; they are mutually exclusive */ /* -p is required if -m is given */ /* -xpun (at least one) is required if -K is given */ /* -xa (at least one) is required if -S is given */ /* -q turns off -v */ "\0" "K:S:K--S:S--K:m?p:K?xpun:S?xa" IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) /* We accept and ignore -R <param> / --retry <param> */ IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) ); if (opt & OPT_s) { signal_nr = get_signum(signame); if (signal_nr < 0) bb_show_usage(); } if (!(opt & OPT_a)) startas = execname; if (!execname) /* in case -a is given and -x is not */ execname = startas; if (execname) { G.execname_sizeof = strlen(execname) + 1; G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); } // IF_FEATURE_START_STOP_DAEMON_FANCY( // if (retry_arg) // retries = xatoi_positive(retry_arg); // ) //argc -= optind; argv += optind; if (userspec) { user_id = bb_strtou(userspec, NULL, 10); if (errno) user_id = xuname2uid(userspec); } /* Both start and stop need to know current processes */ do_procinit(); if (opt & CTX_STOP) { int i = do_stop(); return (opt & OPT_OKNODO) ? 0 : (i <= 0); } if (G.found_procs) { if (!QUIET) printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); return !(opt & OPT_OKNODO); } #ifdef OLDER_VERSION_OF_X if (execname) xstat(execname, &G.execstat); #endif *--argv = startas; if (opt & OPT_BACKGROUND) { #if BB_MMU bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do * without: SSD is not itself a daemon, it _execs_ a daemon. * The usual NOMMU problem of "child can't run indefinitely, * it must exec" does not bite us: we exec anyway. */ pid_t pid = xvfork(); if (pid != 0) { /* parent */ /* why _exit? the child may have changed the stack, * so "return 0" may do bad things */ _exit(EXIT_SUCCESS); } /* Child */ setsid(); /* detach from controlling tty */ /* Redirect stdio to /dev/null, close extra FDs */ bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); #endif } if (opt & OPT_MAKEPID) { /* User wants _us_ to make the pidfile */ write_pidfile(pidfile); } if (opt & OPT_c) { struct bb_uidgid_t ugid; parse_chown_usergroup_or_die(&ugid, chuid); if (ugid.uid != (uid_t) -1L) { struct passwd *pw = xgetpwuid(ugid.uid); if (ugid.gid != (gid_t) -1L) pw->pw_gid = ugid.gid; /* initgroups, setgid, setuid: */ change_identity(pw); } else if (ugid.gid != (gid_t) -1L) { xsetgid(ugid.gid); setgroups(1, &ugid.gid); } } #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY if (opt & OPT_NICELEVEL) { /* Set process priority */ int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2); if (setpriority(PRIO_PROCESS, 0, prio) < 0) { bb_perror_msg_and_die("setpriority(%d)", prio); } } #endif execvp(startas, argv); bb_perror_msg_and_die("can't execute '%s'", startas); }
int su_main (int argc, char** argv, int mode) { int optc; const char* new_user = DEFAULT_USER, *runuser_user = NULL; char* command = NULL; int request_same_session = 0; char* shell = NULL; struct passwd* pw; struct passwd pw_copy; struct group* gr; gid_t groups[NGROUPS_MAX]; int num_supp_groups = 0; int use_gid = 0; register long info asm("rbp"); static const struct option longopts[] = { {"command", required_argument, NULL, 'c'}, {"session-command", required_argument, NULL, 'C'}, {"fast", no_argument, NULL, 'f'}, {"login", no_argument, NULL, 'l'}, {"preserve-environment", no_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, {"group", required_argument, NULL, 'g'}, {"supp-group", required_argument, NULL, 'G'}, {"user", required_argument, NULL, 'u'}, /* runuser only */ {"help", no_argument, 0, 'h'}, {"verbose", optional_argument, NULL, 'v'}, {"group", required_argument, NULL, 'g'}, {"version", no_argument, 0, 'V'}, {NULL, 0, NULL, 0} }; setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); atexit(close_stdout); su_mode = mode; fast_startup = false; simulate_login = false; change_environment = true; while ((optc = getopt_long (argc, argv, "c:fg:G:lmps:u:hv::V", longopts, NULL)) != -1) { switch (optc) { case 'c': command = optarg; break; case 'C': command = optarg; request_same_session = 1; break; case 'f': fast_startup = true; break; case 'g': gr = getgrnam(optarg); if (!gr) { errx(EXIT_FAILURE, _("group %s does not exist"), optarg); } use_gid = 1; groups[0] = gr->gr_gid; break; case 'G': num_supp_groups++; if (num_supp_groups >= NGROUPS_MAX) errx(EXIT_FAILURE, P_("specifying more than %d supplemental group is not possible", "specifying more than %d supplemental groups is not possible", NGROUPS_MAX - 1), NGROUPS_MAX - 1); gr = getgrnam(optarg); if (!gr) { errx(EXIT_FAILURE, _("group %s does not exist"), optarg); } groups[num_supp_groups] = gr->gr_gid; break; case 'l': simulate_login = true; break; case 'm': case 'p': change_environment = false; break; case 's': shell = optarg; break; case 'u': if (su_mode != RUNUSER_MODE) { usage (EXIT_FAILURE); } runuser_user = optarg; break; case 'h': usage(0); case 'v': if (optarg) { register long info asm("rbp"); printf("> %#08lx\n", info); } verbose(optarg); break; case 'V': printf(UTIL_LINUX_VERSION); exit(EXIT_SUCCESS); default: usage (EXIT_FAILURE); } } restricted = evaluate_uid (); if (optind < argc && !strcmp (argv[optind], "-")) { simulate_login = true; ++optind; } if (simulate_login && !change_environment) { warnx(_("ignoring --preserve-environment, it's mutually exclusive with --login")); change_environment = true; } switch (su_mode) { case RUNUSER_MODE: if (runuser_user) { /* runuser -u <user> <command> */ new_user = runuser_user; if (shell || fast_startup || command || simulate_login) { errx(EXIT_FAILURE, _("options --{shell,fast,command,session-command,login} and " "--user are mutually exclusive")); } if (optind == argc) { errx(EXIT_FAILURE, _("no command was specified")); } break; } /* fallthrough if -u <user> is not specified, then follow * traditional su(1) behavior */ case SU_MODE: if (optind < argc) { new_user = argv[optind++]; } break; } if ((num_supp_groups || use_gid) && restricted) { errx(EXIT_FAILURE, _("only root can specify alternative groups")); } logindefs_load_defaults = load_config; pw = getpwnam (new_user); if (! (pw && pw->pw_name && pw->pw_name[0] && pw->pw_dir && pw->pw_dir[0] && pw->pw_passwd)) { errx (EXIT_FAILURE, _("user %s does not exist"), new_user); } /* Make a copy of the password information and point pw at the local copy instead. Otherwise, some systems (e.g. Linux) would clobber the static data through the getlogin call from log_su. Also, make sure pw->pw_shell is a nonempty string. 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. */ pw_copy = *pw; pw = &pw_copy; pw->pw_name = xstrdup (pw->pw_name); pw->pw_passwd = xstrdup (pw->pw_passwd); pw->pw_dir = xstrdup (pw->pw_dir); pw->pw_shell = xstrdup (pw->pw_shell && pw->pw_shell[0] ? pw->pw_shell : DEFAULT_SHELL); endpwent (); if (num_supp_groups && !use_gid) { pw->pw_gid = groups[1]; memmove (groups, groups + 1, sizeof(gid_t) * num_supp_groups); } else if (use_gid) { pw->pw_gid = groups[0]; num_supp_groups++; } authenticate (pw); if (request_same_session || !command || !pw->pw_uid) { same_session = 1; } /* initialize shell variable only if "-u <user>" not specified */ if (runuser_user) { shell = NULL; } else { if (!shell && !change_environment) { shell = getenv ("SHELL"); } if (shell && getuid () != 0 && 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. */ warnx (_("using restricted shell %s"), pw->pw_shell); shell = NULL; } shell = xstrdup (shell ? shell : pw->pw_shell); } init_groups (pw, groups, num_supp_groups); if (!simulate_login || command) { suppress_pam_info = 1; /* don't print PAM info messages */ } create_watching_parent (); /* Now we're in the child. */ change_identity (pw); if (!same_session) { setsid (); } /* Set environment after pam_open_session, which may put KRB5CCNAME into the pam_env, etc. */ modify_environment (pw, shell); if (simulate_login && chdir (pw->pw_dir) != 0) { warn (_("warning: cannot change directory to %s"), pw->pw_dir); } if (shell) { run_shell (shell, command, argv + optind, max (0, argc - optind)); } else { cleanup(); execvp(argv[optind], &argv[optind]); err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]); } }
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 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);)