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, ...); typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
/* Policy plugin type and defines */ /* Policy plugin type and defines */
struct passwd;
struct policy_plugin { struct policy_plugin {
#define SUDO_POLICY_PLUGIN 1 #define SUDO_POLICY_PLUGIN 1
unsigned int type; /* always SUDO_POLICY_PLUGIN */ unsigned int type; /* always SUDO_POLICY_PLUGIN */
@@ -68,6 +69,7 @@ struct policy_plugin {
const char *list_user); const char *list_user);
int (*validate)(void); int (*validate)(void);
void (*invalidate)(int remove); void (*invalidate)(int remove);
int (*init_session)(struct passwd *pwd);
}; };
/* I/O plugin type and defines */ /* I/O plugin type and defines */

View File

@@ -202,8 +202,22 @@ pam_begin_session(pw, auth)
struct passwd *pw; struct passwd *pw;
sudo_auth *auth; 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) if (pamh == NULL)
pam_init(pw, NULL, NULL); pam_init(pw, NULL, NULL);
@@ -224,16 +238,14 @@ pam_begin_session(pw, auth)
(void) pam_setcred(pamh, PAM_ESTABLISH_CRED); (void) pam_setcred(pamh, PAM_ESTABLISH_CRED);
#ifndef NO_PAM_SESSION #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); status = pam_open_session(pamh, 0);
if (status != PAM_SUCCESS) if (status != PAM_SUCCESS) {
(void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); (void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
pamh = NULL;
}
#endif #endif
done:
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
} }
@@ -241,13 +253,14 @@ int
pam_end_session(auth) pam_end_session(auth)
sudo_auth *auth; sudo_auth *auth;
{ {
int status; int status = PAM_SUCCESS;
if (pamh) {
#ifndef NO_PAM_SESSION #ifndef NO_PAM_SESSION
(void) pam_close_session(pamh, 0); (void) pam_close_session(pamh, PAM_SILENT);
#endif #endif
status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); }
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE); return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
} }

View File

@@ -234,7 +234,7 @@ cleanup:
return rval; return rval;
} }
int begin_session(struct passwd *pw) int auth_begin_session(struct passwd *pw)
{ {
sudo_auth *auth; sudo_auth *auth;
int status; int status;
@@ -251,7 +251,7 @@ int begin_session(struct passwd *pw)
return TRUE; return TRUE;
} }
int end_session(void) int auth_end_session(void)
{ {
sudo_auth *auth; sudo_auth *auth;
int status; 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. */ /* We do not currently log the exit status. */
if (error_code) if (error_code)
warningx("unable to execute %s: %s", safe_cmnd, strerror(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 static int
@@ -628,15 +641,6 @@ sudoers_policy_main(int argc, char * const argv[], int pwflag, char *env_add[],
restore_perms(); 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: done:
return rval; return rval;
} }
@@ -1438,7 +1442,8 @@ struct policy_plugin sudoers_policy = {
sudoers_policy_check, sudoers_policy_check,
sudoers_policy_list, sudoers_policy_list,
sudoers_policy_validate, sudoers_policy_validate,
sudoers_policy_invalidate sudoers_policy_invalidate,
sudoers_policy_init_session
}; };
struct io_plugin sudoers_io = { struct io_plugin sudoers_io = {

View File

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

View File

@@ -639,7 +639,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
close(sv[0]); close(sv[0]);
fcntl(sv[1], F_SETFD, FD_CLOEXEC); fcntl(sv[1], F_SETFD, FD_CLOEXEC);
/* XXX - defer call to exec_setup() until my_execve()? */ /* XXX - defer call to exec_setup() until my_execve()? */
if (exec_setup(details) == 0) { if (exec_setup(details) == TRUE) {
/* headed for execve() */ /* headed for execve() */
if (log_io) { if (log_io) {
/* Close the other end of the stdin/stdout/stderr pipes. */ /* 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() * Setup the execution environment immediately prior to the call to execve()
* Returns TRUE on success and FALSE on failure.
*/ */
int int
exec_setup(struct command_details *details) exec_setup(struct command_details *details)
{ {
int rval = FALSE;
struct passwd *pw; struct passwd *pw;
pw = getpwuid(details->euid); 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) { if (pw != NULL) {
#ifdef HAVE_GETUSERATTR #ifdef HAVE_GETUSERATTR
aix_setlimits(pw->pw_name); aix_setlimits(pw->pw_name);
@@ -732,15 +742,7 @@ exec_setup(struct command_details *details)
goto done; 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 #ifdef HAVE_SETRESUID
if (setresuid(details->uid, details->euid, details->euid) != 0) { if (setresuid(details->uid, details->euid, details->euid) != 0) {
warning("unable to change to runas uid"); warning("unable to change to runas uid");
@@ -758,10 +760,19 @@ exec_setup(struct command_details *details)
} }
#endif /* !HAVE_SETRESUID && !HAVE_SETREUID */ #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: done:
return errno; return rval;
} }
/* /*