Add init_session function to struct policy_plugin that gets called

before the uid/gid/etc changes.  A struct passwd pointer is passed in,which may be NULL if the user does not exist in the passwd database.The sudoers module uses init_session to open the pam session as needed.
This commit is contained in:
Todd C. Miller
2010-05-27 14:46:39 -04:00
parent 27be96c9cd
commit 7e6d1d1f7d
7 changed files with 69 additions and 38 deletions

View File

@@ -52,6 +52,7 @@ typedef int (*sudo_conv_t)(int num_msgs, const struct sudo_conv_message msgs[],
typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
/* Policy plugin type and defines */
struct passwd;
struct policy_plugin {
#define SUDO_POLICY_PLUGIN 1
unsigned int type; /* always SUDO_POLICY_PLUGIN */
@@ -68,6 +69,7 @@ struct policy_plugin {
const char *list_user);
int (*validate)(void);
void (*invalidate)(int remove);
int (*init_session)(struct passwd *pwd);
};
/* I/O plugin type and defines */

View File

@@ -202,8 +202,22 @@ pam_begin_session(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
int status;
int status = PAM_SUCCESS;
/*
* If there is no valid user we cannot open a PAM session.
* This is not an error as sudo can run commands with arbitrary
* uids, it just means we are done from a session management standpoint.
*/
if (pw == NULL) {
if (pamh != NULL) {
(void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
pamh = NULL;
}
goto done;
}
/* If the user did not have to authenticate there is no pam handle yet. */
if (pamh == NULL)
pam_init(pw, NULL, NULL);
@@ -224,16 +238,14 @@ pam_begin_session(pw, auth)
(void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
#ifndef NO_PAM_SESSION
/*
* To fully utilize PAM sessions we would need to keep a
* sudo process around until the command exits. However, we
* can at least cause pam_limits to be run by opening and then
* immediately closing the session.
*/
status = pam_open_session(pamh, 0);
if (status != PAM_SUCCESS)
if (status != PAM_SUCCESS) {
(void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
pamh = NULL;
}
#endif
done:
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
@@ -241,13 +253,14 @@ int
pam_end_session(auth)
sudo_auth *auth;
{
int status;
int status = PAM_SUCCESS;
if (pamh) {
#ifndef NO_PAM_SESSION
(void) pam_close_session(pamh, 0);
(void) pam_close_session(pamh, PAM_SILENT);
#endif
status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
}
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}

View File

@@ -234,7 +234,7 @@ cleanup:
return rval;
}
int begin_session(struct passwd *pw)
int auth_begin_session(struct passwd *pw)
{
sudo_auth *auth;
int status;
@@ -251,7 +251,7 @@ int begin_session(struct passwd *pw)
return TRUE;
}
int end_session(void)
int auth_end_session(void)
{
sudo_auth *auth;
int status;

View File

@@ -276,7 +276,20 @@ sudoers_policy_close(int exit_status, int error_code)
/* We do not currently log the exit status. */
if (error_code)
warningx("unable to execute %s: %s", safe_cmnd, strerror(error_code));
end_session();
/* Close the session we opened in sudoers_policy_init_session(). */
if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
(void)auth_end_session();
}
/*
* The init_session function is called before executing the command
* and before uid/gid changes occur.
*/
static int
sudoers_policy_init_session(struct passwd *pwd)
{
return auth_begin_session(pwd);
}
static int
@@ -628,15 +641,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
restore_perms();
/*
* Ideally we would like to do session setup (currently only PAM)
* from inside sudo itself, but this should be close enough.
*/
if (ISSET(sudo_mode, MODE_RUN))
rval = begin_session(runas_pw);
if (ISSET(sudo_mode, MODE_EDIT))
rval = begin_session(sudo_user.pw);
done:
return rval;
}
@@ -1438,7 +1442,8 @@ struct policy_plugin sudoers_policy = {
sudoers_policy_check,
sudoers_policy_list,
sudoers_policy_validate,
sudoers_policy_invalidate
sudoers_policy_invalidate,
sudoers_policy_init_session
};
struct io_plugin sudoers_io = {

View File

@@ -210,8 +210,8 @@ int user_is_exempt(void);
/* sudo_auth.c */
int verify_user(struct passwd *, char *);
int begin_session(struct passwd *);
int end_session();
int auth_begin_session(struct passwd *);
int auth_end_session();
#ifdef HAVE_LDAP
/* ldap.c */

View File

@@ -639,7 +639,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
close(sv[0]);
fcntl(sv[1], F_SETFD, FD_CLOEXEC);
/* XXX - defer call to exec_setup() until my_execve()? */
if (exec_setup(details) == 0) {
if (exec_setup(details) == TRUE) {
/* headed for execve() */
if (log_io) {
/* Close the other end of the stdin/stdout/stderr pipes. */

View File

@@ -651,13 +651,23 @@ cleanup(int gotsignal)
/*
* Setup the execution environment immediately prior to the call to execve()
* Returns TRUE on success and FALSE on failure.
*/
int
exec_setup(struct command_details *details)
{
int rval = FALSE;
struct passwd *pw;
pw = getpwuid(details->euid);
/* Call policy plugin's session init before other setup occurs. */
if (policy_plugin.u.policy->init_session) {
/* The session init code is expected to print an error as needed. */
if (policy_plugin.u.policy->init_session(pw) != TRUE)
goto done;
}
if (pw != NULL) {
#ifdef HAVE_GETUSERATTR
aix_setlimits(pw->pw_name);
@@ -732,15 +742,7 @@ exec_setup(struct command_details *details)
goto done;
}
}
if (details->cwd) {
/* cwd is relative to the new root, if any */
if (chdir(details->cwd) != 0) {
warning("unable to change directory to %s", details->cwd);
goto done;
}
}
/* Must set uids last */
#ifdef HAVE_SETRESUID
if (setresuid(details->uid, details->euid, details->euid) != 0) {
warning("unable to change to runas uid");
@@ -758,10 +760,19 @@ exec_setup(struct command_details *details)
}
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */
errno = 0;
/* Set cwd after uid to avoid permissions problems. */
if (details->cwd) {
/* Note: cwd is relative to the new root, if any. */
if (chdir(details->cwd) != 0) {
warning("unable to change directory to %s", details->cwd);
goto done;
}
}
rval = TRUE;
done:
return errno;
return rval;
}
/*