Esempio n. 1
0
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, 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]);
    }
}
Esempio n. 3
0
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);)