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.
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 */
const char *list_user);
int (*validate)(void);
void (*invalidate)(int remove);
+ int (*init_session)(struct passwd *pwd);
};
/* I/O plugin type and defines */
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);
(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);
}
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);
+ status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
+ }
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
return rval;
}
-int begin_session(struct passwd *pw)
+int auth_begin_session(struct passwd *pw)
{
sudo_auth *auth;
int status;
return TRUE;
}
-int end_session(void)
+int auth_end_session(void)
{
sudo_auth *auth;
int status;
/* 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
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;
}
sudoers_policy_check,
sudoers_policy_list,
sudoers_policy_validate,
- sudoers_policy_invalidate
+ sudoers_policy_invalidate,
+ sudoers_policy_init_session
};
struct io_plugin sudoers_io = {
/* 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 */
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. */
/*
* 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);
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");
}
#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;
}
/*