Add open/close session to sudo auth, only used by PAM.

This allows us to open (and close) the PAM session from sudoers.
This commit is contained in:
Todd C. Miller
2010-05-26 17:57:47 -04:00
parent a0646aa4ad
commit 27be96c9cd
6 changed files with 94 additions and 87 deletions

View File

@@ -81,7 +81,7 @@ static int gotintr;
#define PAM_DATA_SILENT 0
#endif
static pam_handle_t *pamh; /* global due to pam_prep_user() */
static pam_handle_t *pamh;
int
pam_init(pw, promptp, auth)
@@ -189,7 +189,7 @@ pam_cleanup(pw, auth)
{
int *pam_status = (int *) auth->data;
/* If successful, we can't close the session until pam_prep_user() */
/* If successful, we can't close the session until pam_end_session() */
if (auth->status == AUTH_SUCCESS)
return(AUTH_SUCCESS);
@@ -198,10 +198,11 @@ pam_cleanup(pw, auth)
}
int
pam_prep_user(pw)
pam_begin_session(pw, auth)
struct passwd *pw;
sudo_auth *auth;
{
int eval;
int status;
if (pamh == NULL)
pam_init(pw, NULL, NULL);
@@ -229,17 +230,25 @@ pam_prep_user(pw)
* can at least cause pam_limits to be run by opening and then
* immediately closing the session.
*/
if ((eval = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
(void) pam_end(pamh, eval | PAM_DATA_SILENT);
return(AUTH_FAILURE);
}
status = pam_open_session(pamh, 0);
if (status != PAM_SUCCESS)
(void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
#endif
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
int
pam_end_session(auth)
sudo_auth *auth;
{
int status;
#ifndef NO_PAM_SESSION
(void) pam_close_session(pamh, 0);
#endif
if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) == PAM_SUCCESS)
return(AUTH_SUCCESS);
else
return(AUTH_FAILURE);
status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
return(status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE);
}
/*

View File

@@ -57,33 +57,37 @@ sudo_auth auth_switch[] = {
AUTH_STANDALONE
#else
# ifndef WITHOUT_PASSWD
AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL)
AUTH_ENTRY(0, "passwd", passwd_init, NULL, passwd_verify, NULL, NULL, NULL)
# endif
# if defined(HAVE_GETPRPWNAM) && !defined(WITHOUT_PASSWD)
AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL)
AUTH_ENTRY(0, "secureware", secureware_init, NULL, secureware_verify, NULL, NULL, NULL)
# endif
# ifdef HAVE_AFS
AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL)
AUTH_ENTRY(0, "afs", NULL, NULL, afs_verify, NULL, NULL, NULL)
# endif
# ifdef HAVE_DCE
AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL)
AUTH_ENTRY(0, "dce", NULL, NULL, dce_verify, NULL, NULL, NULL)
# endif
# ifdef HAVE_KERB4
AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL)
AUTH_ENTRY(0, "kerb4", kerb4_init, NULL, kerb4_verify, NULL, NULL, NULL)
# endif
# ifdef HAVE_KERB5
AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup)
AUTH_ENTRY(0, "kerb5", kerb5_init, NULL, kerb5_verify, kerb5_cleanup, NULL, NULL)
# endif
# ifdef HAVE_SKEY
AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL)
AUTH_ENTRY(0, "S/Key", NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
# endif
# ifdef HAVE_OPIE
AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL)
AUTH_ENTRY(0, "OPIE", NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
# endif
#endif /* AUTH_STANDALONE */
AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL)
AUTH_ENTRY(0, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
};
extern char **NewArgv; /* XXX - for auditing */
static void pass_warn(void);
int
verify_user(struct passwd *pw, char *prompt)
{
@@ -93,7 +97,6 @@ verify_user(struct passwd *pw, char *prompt)
char *p;
sudo_auth *auth;
sigaction_t sa, osa;
extern char **NewArgv; /* XXX */
/* Enable suspend during password entry. */
sigemptyset(&sa.sa_mask);
@@ -181,9 +184,7 @@ verify_user(struct passwd *pw, char *prompt)
if (p)
zero_bytes(p, strlen(p));
#endif
/* XXX - need way to know if askpass was used */
//if (!ISSET(tgetpass_flags, TGP_ASKPASS))
pass_warn();
pass_warn();
}
cleanup:
@@ -233,7 +234,40 @@ cleanup:
return rval;
}
void
int begin_session(struct passwd *pw)
{
sudo_auth *auth;
int status;
for (auth = auth_switch; auth->name; auth++) {
if (auth->begin_session && IS_CONFIGURED(auth)) {
status = (auth->begin_session)(pw, auth);
if (status == AUTH_FATAL) { /* XXX log */
audit_failure(NewArgv, "authentication failure");
return -1; /* assume error msg already printed */
}
}
}
return TRUE;
}
int end_session(void)
{
sudo_auth *auth;
int status;
for (auth = auth_switch; auth->name; auth++) {
if (auth->end_session && IS_CONFIGURED(auth)) {
status = (auth->end_session)(auth);
if (status == AUTH_FATAL) { /* XXX log */
return -1; /* assume error msg already printed */
}
}
}
return TRUE;
}
static void
pass_warn(void)
{
struct sudo_conv_message msg[2];

View File

@@ -32,6 +32,8 @@ typedef struct sudo_auth {
int (*setup)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
int (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth);
int (*cleanup)(struct passwd *pw, struct sudo_auth *auth);
int (*begin_session)(struct passwd *pw, struct sudo_auth *auth);
int (*end_session)(struct sudo_auth *auth);
} sudo_auth;
/* Values for sudo_auth.flags. */
@@ -58,6 +60,8 @@ int fwtk_cleanup(struct passwd *pw, sudo_auth *auth);
int pam_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int pam_cleanup(struct passwd *pw, sudo_auth *auth);
int pam_begin_session(struct passwd *pw, sudo_auth *auth);
int pam_end_session(sudo_auth *auth);
int sia_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int sia_cleanup(struct passwd *pw, sudo_auth *auth);
@@ -86,34 +90,34 @@ int securid_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int securid_verify(struct passwd *pw, char *pass, sudo_auth *auth);
/* Fields: need_root, name, init, setup, verify, cleanup */
#define AUTH_ENTRY(r, n, i, s, v, c) \
{ (r|FLAG_CONFIGURED), AUTH_FAILURE, n, NULL, i, s, v, c },
#define AUTH_ENTRY(r, n, i, s, v, c, b, e) \
{ (r|FLAG_CONFIGURED), AUTH_FAILURE, n, NULL, i, s, v, c , b, e },
/* Some methods cannots (or should not) interoperate with any others */
/* Some methods cannot (or should not) interoperate with any others */
#if defined(HAVE_PAM)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "pam", \
pam_init, NULL, pam_verify, pam_cleanup)
pam_init, NULL, pam_verify, pam_cleanup, pam_begin_session, pam_end_session)
#elif defined(HAVE_SECURID)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "SecurId", \
securid_init, securid_setup, securid_verify, NULL)
securid_init, securid_setup, securid_verify, NULL, NULL, NULL)
#elif defined(HAVE_SIA_SES_INIT)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "sia", \
NULL, sia_setup, sia_verify, sia_cleanup)
NULL, sia_setup, sia_verify, sia_cleanup, NULL, NULL)
#elif defined(HAVE_AIXAUTH)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "aixauth", \
NULL, NULL, aixauth_verify, aixauth_cleanup)
NULL, NULL, aixauth_verify, aixauth_cleanup, NULL, NULL)
#elif defined(HAVE_FWTK)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "fwtk", \
fwtk_init, NULL, fwtk_verify, fwtk_cleanup)
fwtk_init, NULL, fwtk_verify, fwtk_cleanup, NULL, NULL)
#elif defined(HAVE_BSD_AUTH_H)
# define AUTH_STANDALONE \
AUTH_ENTRY(0, "bsdauth", \
bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup)
bsdauth_init, NULL, bsdauth_verify, bsdauth_cleanup, NULL, NULL)
#endif
#endif /* SUDO_AUTH_H */

View File

@@ -60,9 +60,6 @@
/*
* Prototypes
*/
#if 0
static void runas_setup(void);
#endif
static void runas_setgroups(void);
/*
@@ -969,51 +966,3 @@ runas_setgroups()
}
#endif /* HAVE_INITGROUPS */
#if 0
static void
runas_setup()
{
gid_t gid;
#ifdef HAVE_LOGIN_CAP_H
int flags;
extern login_cap_t *lc;
#endif
if (runas_pw->pw_name != NULL) {
gid = runas_gr ? runas_gr->gr_gid : runas_pw->pw_gid;
#ifdef HAVE_GETUSERATTR
aix_setlimits(runas_pw->pw_name);
#endif
#ifdef HAVE_PAM
/* XXX - move this */
pam_prep_user(runas_pw);
#endif /* HAVE_PAM */
#ifdef HAVE_LOGIN_CAP_H
if (def_use_loginclass) {
/*
* We only use setusercontext() to set the nice value and rlimits.
*/
flags = LOGIN_SETRESOURCES|LOGIN_SETPRIORITY;
if (setusercontext(lc, runas_pw, runas_pw->pw_uid, flags)) {
if (runas_pw->pw_uid != ROOT_UID)
error(1, "unable to set user context");
else
warning("unable to set user context");
}
}
#endif /* HAVE_LOGIN_CAP_H */
/*
* Initialize group vector
*/
runas_setgroups();
#ifdef HAVE_SETEUID
if (setegid(gid))
warning("cannot set egid to runas gid");
#endif
if (setgid(gid))
warning("cannot set gid to runas gid");
}
}
#endif

View File

@@ -276,6 +276,7 @@ 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();
}
static int
@@ -627,6 +628,15 @@ 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;
}

View File

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