Modify the authentication API such that the init and cleanup functions

are always called, regardless of whether or not we are going to
verify a password.  This is needed for proper PAM session support.
This commit is contained in:
Todd C. Miller
2011-09-27 13:18:46 -04:00
parent c21595044d
commit bceb5df158
15 changed files with 163 additions and 116 deletions

View File

@@ -12,7 +12,7 @@ typedef struct sudo_auth {
char *name; /* name of the method in string form */
void *data; /* method-specific data pointer */
int (*init)(struct passwd *pw, char **prompt, sudo_auth *auth);
int (*init)(struct passwd *pw, sudo_auth *auth);
int (*setup)(struct passwd *pw, char **prompt, sudo_auth *auth);
int (*verify)(struct passwd *pw, char *p, sudo_auth *auth);
int (*cleanup)(struct passwd *pw, sudo_auth *auth);
@@ -64,11 +64,10 @@ The member functions can return the following values:
The functions in the struct are as follows:
int init(struct passwd *pw, char **prompt, sudo_auth *auth)
int init(struct passwd *pw, sudo_auth *auth)
Function to do any one-time initialization for the auth
method. All of the "init" functions are run before anything
else. A pointer to the prompt string may be used to add
method-specific info to the prompt.
else.
int setup(struct passwd *pw, char **prompt, sudo_auth *auth)
Function to do method-specific setup. All the "setup"

View File

@@ -54,7 +54,7 @@
extern char *login_style; /* from sudo.c */
int
bsdauth_init(struct passwd *pw, char **promptp, sudo_auth *auth)
bsdauth_init(struct passwd *pw, sudo_auth *auth)
{
static auth_session_t *as;
extern login_cap_t *lc; /* from sudo.c */

View File

@@ -50,7 +50,7 @@
#include "sudo_auth.h"
int
fwtk_init(struct passwd *pw, char **promptp, sudo_auth *auth)
fwtk_init(struct passwd *pw, sudo_auth *auth)
{
static Cfg *confp; /* Configuration entry struct */
char resp[128]; /* Response from the server */

View File

@@ -48,7 +48,7 @@
#include "sudo_auth.h"
int
kerb4_init(struct passwd *pw, char **promptp, sudo_auth *auth)
kerb4_init(struct passwd *pw, sudo_auth *auth)
{
static char realm[REALM_SZ];

View File

@@ -88,14 +88,49 @@ krb5_get_init_creds_opt_free(krb5_get_init_creds_opt *opts)
#endif
int
kerb5_init(struct passwd *pw, char **promptp, sudo_auth *auth)
kerb5_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
{
static char *krb5_prompt;
if (krb5_prompt == NULL) {
krb5_context sudo_context;
krb5_principal princ;
char *pname;
krb5_error_code error;
sudo_context = ((sudo_krb5_datap) auth->data)->sudo_context;
princ = ((sudo_krb5_datap) auth->data)->princ;
/*
* Really, we need to tell the caller not to prompt for password. The
* API does not currently provide this unless the auth is standalone.
*/
if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
log_error(NO_EXIT|NO_MAIL,
_("%s: unable to unparse princ ('%s'): %s"), auth->name,
pw->pw_name, error_message(error));
return AUTH_FAILURE;
}
/* Only rewrite prompt if user didn't specify their own. */
/*if (!strcmp(prompt, PASSPROMPT)) { */
easprintf(&krb5_prompt, "Password for %s: ", pname);
/*}*/
free(pname);
}
*promptp = krb5_prompt;
return AUTH_SUCCESS;
}
int
kerb5_init(struct passwd *pw, sudo_auth *auth)
{
krb5_context sudo_context;
krb5_ccache ccache;
krb5_principal princ;
krb5_error_code error;
char cache_name[64];
char *pname;
auth->data = (void *) &sudo_krb5_data; /* Stash all our data here */
@@ -117,25 +152,6 @@ kerb5_init(struct passwd *pw, char **promptp, sudo_auth *auth)
}
princ = sudo_krb5_data.princ;
/*
* Really, we need to tell the caller not to prompt for password.
* The API does not currently provide this unless the auth is standalone.
*/
#if 1
if ((error = krb5_unparse_name(sudo_context, princ, &pname))) {
log_error(NO_EXIT|NO_MAIL,
_("%s: unable to unparse princ ('%s'): %s"), auth->name,
pw->pw_name, error_message(error));
return AUTH_FAILURE;
}
/* Only rewrite prompt if user didn't specify their own. */
/*if (!strcmp(prompt, PASSPROMPT)) { */
easprintf(promptp, "Password for %s: ", pname);
/*}*/
free(pname);
#endif
(void) snprintf(cache_name, sizeof(cache_name), "MEMORY:sudocc_%ld",
(long) getpid());
if ((error = krb5_cc_resolve(sudo_context, cache_name,

View File

@@ -80,7 +80,7 @@ static int gotintr;
static pam_handle_t *pamh;
int
pam_init(struct passwd *pw, char **promptp, sudo_auth *auth)
pam_init(struct passwd *pw, sudo_auth *auth)
{
static struct pam_conv pam_conv;
static int pam_status;
@@ -184,10 +184,11 @@ pam_cleanup(struct passwd *pw, sudo_auth *auth)
int *pam_status = (int *) auth->data;
/* If successful, we can't close the session until pam_end_session() */
if (auth->status == AUTH_SUCCESS)
if (*pam_status == AUTH_SUCCESS)
return AUTH_SUCCESS;
*pam_status = pam_end(pamh, *pam_status | PAM_DATA_SILENT);
pamh = NULL;
return *pam_status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
}
@@ -209,10 +210,6 @@ pam_begin_session(struct passwd *pw, sudo_auth *auth)
goto done;
}
/* If the user did not have to authenticate there is no pam handle yet. */
if (pamh == NULL)
pam_init(pw, NULL, NULL);
/*
* Update PAM_USER to reference the user we are running the command
* as, as opposed to the user we authenticated as.
@@ -246,22 +243,19 @@ pam_end_session(struct passwd *pw, sudo_auth *auth)
{
int status = PAM_SUCCESS;
if (pamh != NULL) {
#ifndef NO_PAM_SESSION
/* If the user did not have to authenticate there is no pam handle yet. */
if (pamh == NULL)
pam_init(pw, NULL, NULL);
/*
* Update PAM_USER to reference the user we are running the command
* as to match the call to pam_open_session().
*/
(void) pam_set_item(pamh, PAM_USER, pw->pw_name);
(void) pam_close_session(pamh, PAM_SILENT);
#endif
if (pamh != NULL)
status = pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT);
pamh = NULL;
}
return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE;
}

View File

@@ -49,7 +49,7 @@
#define HAS_AGEINFO(p, l) (l == 18 && p[DESLEN] == ',')
int
passwd_init(struct passwd *pw, char **promptp, sudo_auth *auth)
passwd_init(struct passwd *pw, sudo_auth *auth)
{
#ifdef HAVE_SKEYACCESS
if (skeyaccess(pw, user_tty, NULL, NULL) == 0)

View File

@@ -53,7 +53,7 @@
#include "sudo_auth.h"
int
secureware_init(struct passwd *pw, char **promptp, sudo_auth *auth)
secureware_init(struct passwd *pw, sudo_auth *auth)
{
#ifdef __alpha
extern int crypt_type;

View File

@@ -56,7 +56,7 @@
union config_record configure;
int
securid_init(struct passwd *pw, char **promptp, sudo_auth *auth)
securid_init(struct passwd *pw, sudo_auth *auth)
{
static struct SD_CLIENT sd_dat; /* SecurID data block */

View File

@@ -59,7 +59,6 @@
* securid_init - Initialises communications with ACE server
* Arguments in:
* pw - UNUSED
* promptp - UNUSED
* auth - sudo authentication structure
*
* Results out:
@@ -68,7 +67,7 @@
* success.
*/
int
securid_init(struct passwd *pw, char **promptp, sudo_auth *auth)
securid_init(struct passwd *pw, sudo_auth *auth)
{
static SDI_HANDLE sd_dat; /* SecurID handle */

View File

@@ -86,7 +86,7 @@ static sudo_auth auth_switch[] = {
AUTH_ENTRY("kerb4", 0, kerb4_init, NULL, kerb4_verify, NULL, NULL, NULL)
#endif
#ifdef HAVE_KERB5
AUTH_ENTRY("kerb5", 0, kerb5_init, NULL, kerb5_verify, kerb5_cleanup, NULL, NULL)
AUTH_ENTRY("kerb5", 0, kerb5_init, kerb5_setup, kerb5_verify, kerb5_cleanup, NULL, NULL)
#endif
#ifdef HAVE_SKEY
AUTH_ENTRY("S/Key", 0, NULL, rfc1938_setup, rfc1938_verify, NULL, NULL, NULL)
@@ -97,35 +97,19 @@ static sudo_auth auth_switch[] = {
AUTH_ENTRY(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
};
static int standalone;
extern char **NewArgv; /* XXX - for auditing */
static void pass_warn(void);
int
verify_user(struct passwd *pw, char *prompt)
sudo_auth_init(struct passwd *pw)
{
int counter = def_passwd_tries + 1;
int success = AUTH_FAILURE;
int flags, status, standalone, rval;
char *p;
sudo_auth *auth;
sigaction_t sa, osa;
/* Enable suspend during password entry. */
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
(void) sigaction(SIGTSTP, &sa, &osa);
/* Make sure we have at least one auth method. */
if (auth_switch[0].name == NULL) {
audit_failure(NewArgv, "no authentication methods");
log_error(0,
_("There are no authentication methods compiled into sudo! "
"If you want to turn off authentication, use the "
"--disable-authentication configure option."));
return -1;
}
if (auth_switch[0].name == NULL)
return AUTH_SUCCESS;
/* Make sure we haven't mixed standalone and shared auth methods. */
standalone = IS_STANDALONE(&auth_switch[0]);
@@ -146,10 +130,12 @@ verify_user(struct passwd *pw, char *prompt)
if (NEEDS_USER(auth))
set_perms(PERM_USER);
status = (auth->init)(pw, &prompt, auth);
if (status == AUTH_FAILURE)
switch ((auth->init)(pw, auth)) {
case AUTH_FAILURE:
SET(auth->flags, FLAG_DISABLED);
else if (status == AUTH_FATAL) { /* XXX log */
break;
case AUTH_FATAL:
/* XXX log */
audit_failure(NewArgv, "authentication failure");
return -1; /* assume error msg already printed */
}
@@ -158,6 +144,59 @@ verify_user(struct passwd *pw, char *prompt)
restore_perms();
}
}
return AUTH_SUCCESS;
}
int
sudo_auth_cleanup(struct passwd *pw)
{
sudo_auth *auth;
/* Call cleanup routines. */
for (auth = auth_switch; auth->name; auth++) {
if (auth->cleanup && !IS_DISABLED(auth)) {
if (NEEDS_USER(auth))
set_perms(PERM_USER);
if ((auth->cleanup)(pw, auth) == AUTH_FATAL) {
/* XXX log */
audit_failure(NewArgv, "authentication failure");
return -1; /* assume error msg already printed */
}
if (NEEDS_USER(auth))
restore_perms();
}
}
return AUTH_SUCCESS;
}
int
verify_user(struct passwd *pw, char *prompt)
{
int counter = def_passwd_tries + 1;
int success = AUTH_FAILURE;
int flags, status, rval;
char *p;
sudo_auth *auth;
sigaction_t sa, osa;
/* Enable suspend during password entry. */
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL;
(void) sigaction(SIGTSTP, &sa, &osa);
/* Make sure we have at least one auth method. */
/* XXX - check FLAG_DISABLED too */
if (auth_switch[0].name == NULL) {
audit_failure(NewArgv, "no authentication methods");
log_error(0,
_("There are no authentication methods compiled into sudo! "
"If you want to turn off authentication, use the "
"--disable-authentication configure option."));
return -1;
}
while (--counter) {
/* Do any per-method setup and unconfigure the method if needed */
@@ -203,31 +242,14 @@ verify_user(struct passwd *pw, char *prompt)
restore_perms();
if (auth->status != AUTH_FAILURE)
goto cleanup;
goto done;
}
if (!standalone)
zero_bytes(p, strlen(p));
pass_warn();
}
cleanup:
/* Call cleanup routines. */
for (auth = auth_switch; auth->name; auth++) {
if (auth->cleanup && !IS_DISABLED(auth)) {
if (NEEDS_USER(auth))
set_perms(PERM_USER);
status = (auth->cleanup)(pw, auth);
if (status == AUTH_FATAL) { /* XXX log */
audit_failure(NewArgv, "authentication failure");
return -1; /* assume error msg already printed */
}
if (NEEDS_USER(auth))
restore_perms();
}
}
done:
switch (success) {
case AUTH_SUCCESS:
(void) sigaction(SIGTSTP, &osa, NULL);
@@ -257,7 +279,8 @@ cleanup:
return rval;
}
int auth_begin_session(struct passwd *pw)
int
sudo_auth_begin_session(struct passwd *pw)
{
sudo_auth *auth;
int status;
@@ -274,7 +297,8 @@ int auth_begin_session(struct passwd *pw)
return TRUE;
}
int auth_end_session(struct passwd *pw)
int
sudo_auth_end_session(struct passwd *pw)
{
sudo_auth *auth;
int status;

View File

@@ -28,7 +28,7 @@ typedef struct sudo_auth {
int status; /* status from verify routine */
char *name; /* name of the method as a string */
void *data; /* method-specific data pointer */
int (*init)(struct passwd *pw, char **prompt, struct sudo_auth *auth);
int (*init)(struct passwd *pw, struct sudo_auth *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);
@@ -55,10 +55,10 @@ char *auth_getpass(const char *prompt, int timeout, int type);
extern sudo_conv_t sudo_conv;
/* Prototypes for standalone methods */
int fwtk_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int fwtk_init(struct passwd *pw, sudo_auth *auth);
int fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int fwtk_cleanup(struct passwd *pw, sudo_auth *auth);
int pam_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int pam_init(struct passwd *pw, 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);
@@ -68,27 +68,28 @@ int sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int sia_cleanup(struct passwd *pw, sudo_auth *auth);
int aixauth_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int aixauth_cleanup(struct passwd *pw, sudo_auth *auth);
int bsdauth_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int bsdauth_init(struct passwd *pw, sudo_auth *auth);
int bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int bsdauth_cleanup(struct passwd *pw, sudo_auth *auth);
/* Prototypes for normal methods */
int passwd_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int passwd_init(struct passwd *pw, sudo_auth *auth);
int passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int passwd_cleanup(struct passwd *pw, sudo_auth *auth);
int secureware_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int secureware_init(struct passwd *pw, sudo_auth *auth);
int secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int secureware_cleanup(struct passwd *pw, sudo_auth *auth);
int rfc1938_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int afs_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int dce_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int kerb4_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int kerb4_init(struct passwd *pw, sudo_auth *auth);
int kerb4_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int kerb5_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int kerb5_init(struct passwd *pw, sudo_auth *auth);
int kerb5_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int kerb5_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int kerb5_cleanup(struct passwd *pw, sudo_auth *auth);
int securid_init(struct passwd *pw, char **prompt, sudo_auth *auth);
int securid_init(struct passwd *pw, sudo_auth *auth);
int securid_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int securid_verify(struct passwd *pw, char *pass, sudo_auth *auth);

View File

@@ -98,6 +98,7 @@ static struct passwd *get_authpw(void);
int
check_user(int validated, int mode)
{
struct passwd *auth_pw;
char *timestampdir = NULL;
char *timestampfile = NULL;
char *prompt;
@@ -113,6 +114,11 @@ check_user(int validated, int mode)
ctim_get(&sb, &tty_info.ctime);
}
/* Init authentication system regardless of whether we need a password. */
auth_pw = get_authpw();
sudo_auth_init(auth_pw);
pw_delref(auth_pw);
/* Always prompt for a password when -k was specified with the command. */
if (ISSET(mode, MODE_IGNORE_TICKET)) {
SET(validated, FLAG_CHECK_USER);
@@ -124,11 +130,13 @@ check_user(int validated, int mode)
if (user_uid == 0 || (user_uid == runas_pw->pw_uid &&
(!runas_gr || user_in_group(sudo_user.pw, runas_gr->gr_name))) ||
user_is_exempt())
return TRUE;
goto done;
}
if (build_timestamp(&timestampdir, &timestampfile) == -1)
return -1;
if (build_timestamp(&timestampdir, &timestampfile) == -1) {
rval = -1;
goto done;
}
status = timestamp_status(timestampdir, timestampfile, user_name,
TS_MAKE_DIRS);
@@ -139,7 +147,8 @@ check_user(int validated, int mode)
/* Bail out if we are non-interactive and a password is required */
if (ISSET(mode, MODE_NONINTERACTIVE)) {
warningx(_("sorry, a password is required to run %s"), getprogname());
return -1;
rval = -1;
goto done;
}
/* XXX - should not lecture if askpass helper is being used. */
@@ -160,6 +169,9 @@ check_user(int validated, int mode)
efree(timestampdir);
efree(timestampfile);
done:
sudo_auth_cleanup(auth_pw);
return rval;
}

View File

@@ -254,7 +254,7 @@ sudoers_policy_close(int exit_status, int error_code)
/* Close the session we opened in sudoers_policy_init_session(). */
if (ISSET(sudo_mode, MODE_RUN|MODE_EDIT))
(void)auth_end_session(runas_pw);
(void)sudo_auth_end_session(runas_pw);
/* Free remaining references to password and group entries. */
pw_delref(sudo_user.pw);
@@ -277,7 +277,7 @@ sudoers_policy_init_session(struct passwd *pwd)
return -1;
}
return auth_begin_session(pwd);
return sudo_auth_begin_session(pwd);
}
static int

View File

@@ -218,8 +218,10 @@ int user_is_exempt(void);
/* sudo_auth.c */
int verify_user(struct passwd *, char *);
int auth_begin_session(struct passwd *);
int auth_end_session();
int sudo_auth_begin_session(struct passwd *);
int sudo_auth_end_session(struct passwd *);
int sudo_auth_init(struct passwd *pw);
int sudo_auth_cleanup(struct passwd *pw);
/* parse.c */
int sudo_file_open(struct sudo_nss *);