예제 #1
0
/*
 * Validate the list of environment variables passed in on the command
 * line against env_delete, env_check, and env_keep.
 * Calls log_error() if any specified variables are not allowed.
 */
void
validate_env_vars(char * const env_vars[])
{
    char * const *ep;
    char *eq, *bad = NULL;
    size_t len, blen = 0, bsize = 0;
    int okvar;

    if (env_vars == NULL)
	return;

    /* Add user-specified environment variables. */
    for (ep = env_vars; *ep != NULL; ep++) {
	if (def_secure_path && !user_is_exempt() &&
	    strncmp(*ep, "PATH=", 5) == 0) {
	    okvar = FALSE;
	} else if (def_env_reset) {
	    okvar = matches_env_check(*ep);
	    if (okvar == -1)
		okvar = matches_env_keep(*ep);
	} else {
	    okvar = matches_env_delete(*ep) == FALSE;
	    if (okvar == FALSE)
		okvar = matches_env_check(*ep) != FALSE;
	}
	if (okvar == FALSE) {
	    /* Not allowed, add to error string, allocating as needed. */
	    if ((eq = strchr(*ep, '=')) != NULL)
		*eq = '\0';
	    len = strlen(*ep) + 2;
	    if (blen + len >= bsize) {
		do {
		    bsize += 1024;
		} while (blen + len >= bsize);
		bad = erealloc(bad, bsize);
		bad[blen] = '\0';
	    }
	    strlcat(bad, *ep, bsize);
	    strlcat(bad, ", ", bsize);
	    blen += len;
	    if (eq != NULL)
		*eq = '=';
	}
    }
    if (bad != NULL) {
	bad[blen - 2] = '\0';		/* remove trailing ", " */
	log_error(NO_MAIL,
	    _("sorry, you are not allowed to set the following environment variables: %s"), bad);
	/* NOTREACHED */
	efree(bad);
    }
}
예제 #2
0
/*
 * Returns true if the user successfully authenticates, false if not
 * or -1 on error.
 */
int
check_user(int validated, int mode)
{
    struct passwd *auth_pw;
    int rval = -1;
    debug_decl(check_user, SUDOERS_DEBUG_AUTH)

    /*
     * Init authentication system regardless of whether we need a password.
     * Required for proper PAM session support.
     */
    if ((auth_pw = get_authpw(mode)) == NULL)
	goto done;
    if (sudo_auth_init(auth_pw) == -1)
	goto done;

    /*
     * Don't prompt for the root passwd or if the user is exempt.
     * If the user is not changing uid/gid, no need for a password.
     */
    if (!def_authenticate || user_is_exempt()) {
	rval = true;
	goto done;
    }
    if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
	(!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name)))) {
#ifdef HAVE_SELINUX
	if (user_role == NULL && user_type == NULL)
#endif
#ifdef HAVE_PRIV_SET
	if (runas_privs == NULL && runas_limitprivs == NULL)
#endif
	{
	    rval = true;
	    goto done;
	}
    }

    rval = check_user_interactive(validated, mode, auth_pw);

done:
    sudo_auth_cleanup(auth_pw);
    sudo_pw_delref(auth_pw);

    debug_return_bool(rval);
}
예제 #3
0
/*
 * Build a new environment and ether clear potentially dangerous
 * variables from the old one or start with a clean slate.
 * Also adds sudo-specific variables (SUDO_*).
 */
void
rebuild_env(void)
{
    char **old_envp, **ep, *cp, *ps1;
    char idbuf[MAX_UID_T_LEN];
    unsigned int didvar;
    int reset_home = FALSE;

    /*
     * Either clean out the environment or reset to a safe default.
     */
    ps1 = NULL;
    didvar = 0;
    env.env_len = 0;
    env.env_size = 128;
    old_envp = env.envp;
    env.envp = emalloc2(env.env_size, sizeof(char *));
#ifdef ENV_DEBUG
    memset(env.envp, 0, env.env_size * sizeof(char *));
#endif

    /* Reset HOME based on target user if configured to. */
    if (ISSET(sudo_mode, MODE_RUN)) {
	if (def_always_set_home ||
	    ISSET(sudo_mode, MODE_RESET_HOME | MODE_LOGIN_SHELL) || 
	    (ISSET(sudo_mode, MODE_SHELL) && def_set_home))
	    reset_home = TRUE;
    }

    if (def_env_reset || ISSET(sudo_mode, MODE_LOGIN_SHELL)) {
	/* Pull in vars we want to keep from the old environment. */
	for (ep = old_envp; *ep; ep++) {
	    int keepit;

	    /* Skip variables with values beginning with () (bash functions) */
	    if ((cp = strchr(*ep, '=')) != NULL) {
		if (strncmp(cp, "=() ", 3) == 0)
		    continue;
	    }

	    /*
	     * First check certain variables for '%' and '/' characters.
	     * If no match there, check the keep list.
	     * If nothing matched, we remove it from the environment.
	     */
	    keepit = matches_env_check(*ep);
	    if (keepit == -1)
		keepit = matches_env_keep(*ep);

	    /* For SUDO_PS1 -> PS1 conversion. */
	    if (strncmp(*ep, "SUDO_PS1=", 8) == 0)
		ps1 = *ep + 5;

	    if (keepit) {
		/* Preserve variable. */
		switch (**ep) {
		    case 'H':
			if (strncmp(*ep, "HOME=", 5) == 0)
			    SET(didvar, DID_HOME);
			break;
		    case 'L':
			if (strncmp(*ep, "LOGNAME=", 8) == 0)
			    SET(didvar, DID_LOGNAME);
			break;
		    case 'M':
			if (strncmp(*ep, "MAIL=", 5) == 0)
			    SET(didvar, DID_MAIL);
			break;
		    case 'P':
			if (strncmp(*ep, "PATH=", 5) == 0)
			    SET(didvar, DID_PATH);
			break;
		    case 'S':
			if (strncmp(*ep, "SHELL=", 6) == 0)
			    SET(didvar, DID_SHELL);
			break;
		    case 'T':
			if (strncmp(*ep, "TERM=", 5) == 0)
			    SET(didvar, DID_TERM);
			break;
		    case 'U':
			if (strncmp(*ep, "USER="******"USERNAME="******"SHELL", runas_pw->pw_shell, ISSET(didvar, DID_SHELL));
	    sudo_setenv("LOGNAME", runas_pw->pw_name,
		ISSET(didvar, DID_LOGNAME));
	    sudo_setenv("USER", runas_pw->pw_name, ISSET(didvar, DID_USER));
	    sudo_setenv("USERNAME", runas_pw->pw_name,
		ISSET(didvar, DID_USERNAME));
	} else {
	    if (!ISSET(didvar, DID_SHELL))
		sudo_setenv("SHELL", sudo_user.pw->pw_shell, FALSE);
	    if (!ISSET(didvar, DID_LOGNAME))
		sudo_setenv("LOGNAME", user_name, FALSE);
	    if (!ISSET(didvar, DID_USER))
		sudo_setenv("USER", user_name, FALSE);
	    if (!ISSET(didvar, DID_USERNAME))
		sudo_setenv("USERNAME", user_name, FALSE);
	}

	/* If we didn't keep HOME, reset it based on target user. */
	if (!ISSET(didvar, KEPT_HOME))
	    reset_home = TRUE;

	/*
	 * Set MAIL to target user in -i mode or if MAIL is not preserved
	 * from user's environment.
	 */
	if (ISSET(sudo_mode, MODE_LOGIN_SHELL) || !ISSET(didvar, KEPT_MAIL)) {
	    cp = _PATH_MAILDIR;
	    if (cp[sizeof(_PATH_MAILDIR) - 2] == '/')
		easprintf(&cp, "MAIL=%s%s", _PATH_MAILDIR, runas_pw->pw_name);
	    else
		easprintf(&cp, "MAIL=%s/%s", _PATH_MAILDIR, runas_pw->pw_name);
	    sudo_putenv(cp, ISSET(didvar, DID_MAIL), TRUE);
	}
    } else {
	/*
	 * Copy environ entries as long as they don't match env_delete or
	 * env_check.
	 */
	for (ep = old_envp; *ep; ep++) {
	    int okvar;

	    /* Skip variables with values beginning with () (bash functions) */
	    if ((cp = strchr(*ep, '=')) != NULL) {
		if (strncmp(cp, "=() ", 3) == 0)
		    continue;
	    }

	    /*
	     * First check variables against the blacklist in env_delete.
	     * If no match there check for '%' and '/' characters.
	     */
	    okvar = matches_env_delete(*ep) != TRUE;
	    if (okvar)
		okvar = matches_env_check(*ep) != FALSE;

	    if (okvar) {
		if (strncmp(*ep, "SUDO_PS1=", 9) == 0)
		    ps1 = *ep + 5;
		else if (strncmp(*ep, "PATH=", 5) == 0)
		    SET(didvar, DID_PATH);
		else if (strncmp(*ep, "TERM=", 5) == 0)
		    SET(didvar, DID_TERM);
		sudo_putenv(*ep, FALSE, FALSE);
	    }
	}
    }
    /* Replace the PATH envariable with a secure one? */
    if (def_secure_path && !user_is_exempt()) {
	sudo_setenv("PATH", def_secure_path, TRUE);
	SET(didvar, DID_PATH);
    }

    /*
     * Set $USER, $LOGNAME and $USERNAME to target if "set_logname" is not
     * disabled.  We skip this if we are running a login shell (because
     * they have already been set them) or sudoedit (because we want the
     * editor to find the user's startup files).
     */
    if (def_set_logname && !ISSET(sudo_mode, MODE_LOGIN_SHELL|MODE_EDIT)) {
	if (!ISSET(didvar, KEPT_LOGNAME))
	    sudo_setenv("LOGNAME", runas_pw->pw_name, TRUE);
	if (!ISSET(didvar, KEPT_USER))
	    sudo_setenv("USER", runas_pw->pw_name, TRUE);
	if (!ISSET(didvar, KEPT_USERNAME))
	    sudo_setenv("USERNAME", runas_pw->pw_name, TRUE);
    }

    /* Set $HOME to target user if not preserving user's value. */
    if (reset_home)
	sudo_setenv("HOME", runas_pw->pw_dir, TRUE);

    /* Provide default values for $TERM and $PATH if they are not set. */
    if (!ISSET(didvar, DID_TERM))
	sudo_putenv("TERM=unknown", FALSE, FALSE);
    if (!ISSET(didvar, DID_PATH))
	sudo_setenv("PATH", _PATH_STDPATH, FALSE);

    /* Set PS1 if SUDO_PS1 is set. */
    if (ps1 != NULL)
	sudo_putenv(ps1, TRUE, TRUE);

    /* Add the SUDO_COMMAND envariable (cmnd + args). */
    if (user_args) {
	easprintf(&cp, "%s %s", user_cmnd, user_args);
	sudo_setenv("SUDO_COMMAND", cp, TRUE);
	efree(cp);
    } else {
	sudo_setenv("SUDO_COMMAND", user_cmnd, TRUE);
    }

    /* Add the SUDO_USER, SUDO_UID, SUDO_GID environment variables. */
    sudo_setenv("SUDO_USER", user_name, TRUE);
    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_uid);
    sudo_setenv("SUDO_UID", idbuf, TRUE);
    snprintf(idbuf, sizeof(idbuf), "%u", (unsigned int) user_gid);
    sudo_setenv("SUDO_GID", idbuf, TRUE);

    /* Free old environment. */
    efree(old_envp);
}
예제 #4
0
파일: check.c 프로젝트: mer-tools/sudo
/*
 * Returns true if the user successfully authenticates, false if not
 * or -1 on error.
 */
int
check_user(int validated, int mode)
{
    struct passwd *auth_pw;
    char *timestampdir = NULL;
    char *timestampfile = NULL;
    char *prompt;
    struct stat sb;
    int status, rval = true;
    debug_decl(check_user, SUDO_DEBUG_AUTH)

    /*
     * Init authentication system regardless of whether we need a password.
     * Required for proper PAM session support.
     */
    auth_pw = get_authpw();
    if (sudo_auth_init(auth_pw) == -1) {
	rval = -1;
	goto done;
    }

    /*
     * Don't prompt for the root passwd or if the user is exempt.
     * If the user is not changing uid/gid, no need for a password.
     */
    if (!def_authenticate || user_uid == 0 || user_is_exempt())
	goto done;
    if (user_uid == runas_pw->pw_uid &&
	(!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) {
#ifdef HAVE_SELINUX
	if (user_role == NULL && user_type == NULL)
#endif
#ifdef HAVE_PRIV_SET
	if (runas_privs == NULL && runas_limitprivs == NULL)
#endif
	    goto done;
    }

    /* Always need a password when -k was specified with the command. */
    if (ISSET(mode, MODE_IGNORE_TICKET))
	SET(validated, FLAG_CHECK_USER);

    /* Stash the tty's ctime for tty ticket comparison. */
    if (def_tty_tickets && user_ttypath && stat(user_ttypath, &sb) == 0) {
	tty_info.dev = sb.st_dev;
	tty_info.ino = sb.st_ino;
	tty_info.rdev = sb.st_rdev;
	if (tty_is_devpts(user_ttypath))
	    ctim_get(&sb, &tty_info.ctime);
    }

    if (build_timestamp(&timestampdir, &timestampfile) == -1) {
	rval = -1;
	goto done;
    }

    status = timestamp_status(timestampdir, timestampfile, user_name,
	TS_MAKE_DIRS);

    if (status != TS_CURRENT || ISSET(validated, FLAG_CHECK_USER)) {
	/* Bail out if we are non-interactive and a password is required */
	if (ISSET(mode, MODE_NONINTERACTIVE)) {
	    validated |= FLAG_NON_INTERACTIVE;
	    log_auth_failure(validated, 0);
	    rval = -1;
	    goto done;
	}

	/* XXX - should not lecture if askpass helper is being used. */
	lecture(status);

	/* Expand any escapes in the prompt. */
	prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
	    user_name, user_shost);

	rval = verify_user(auth_pw, prompt, validated);
    }
    /* Only update timestamp if user was validated. */
    if (rval == true && ISSET(validated, VALIDATE_OK) &&
	!ISSET(mode, MODE_IGNORE_TICKET) && status != TS_ERROR)
	update_timestamp(timestampdir, timestampfile);
    efree(timestampdir);
    efree(timestampfile);

done:
    sudo_auth_cleanup(auth_pw);
    sudo_pw_delref(auth_pw);

    debug_return_bool(rval);
}