Only update the time stamp entry after the approval function has succeeded.

Bug #910
This commit is contained in:
Todd C. Miller
2019-12-04 12:38:22 -07:00
parent 049bbbfae1
commit 4b6de608c2

View File

@@ -51,6 +51,7 @@ static bool display_lecture(int);
static struct passwd *get_authpw(int); static struct passwd *get_authpw(int);
struct getpass_closure { struct getpass_closure {
int tstat;
void *cookie; void *cookie;
struct passwd *auth_pw; struct passwd *auth_pw;
}; };
@@ -89,27 +90,20 @@ getpass_resume(int signo, void *vclosure)
* or -1 on fatal error. * or -1 on fatal error.
*/ */
static int static int
check_user_interactive(int validated, int mode, struct passwd *auth_pw) check_user_interactive(int validated, int mode, struct getpass_closure *closure)
{ {
struct sudo_conv_callback cb, *callback = NULL; struct sudo_conv_callback cb, *callback = NULL;
struct getpass_closure closure;
int status = TS_ERROR;
int ret = -1; int ret = -1;
char *prompt; char *prompt;
bool lectured; bool lectured;
debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH) debug_decl(check_user_interactive, SUDOERS_DEBUG_AUTH)
/* Setup closure for getpass_{suspend,resume} */
closure.auth_pw = auth_pw;
closure.cookie = NULL;
sudo_pw_addref(closure.auth_pw);
/* Open, lock and read time stamp file if we are using it. */ /* Open, lock and read time stamp file if we are using it. */
if (!ISSET(mode, MODE_IGNORE_TICKET)) { if (!ISSET(mode, MODE_IGNORE_TICKET)) {
/* Open time stamp file and check its status. */ /* Open time stamp file and check its status. */
closure.cookie = timestamp_open(user_name, user_sid); closure->cookie = timestamp_open(user_name, user_sid);
if (timestamp_lock(closure.cookie, closure.auth_pw)) if (timestamp_lock(closure->cookie, closure->auth_pw))
status = timestamp_status(closure.cookie, closure.auth_pw); closure->tstat = timestamp_status(closure->cookie, closure->auth_pw);
/* Construct callback for getpass function. */ /* Construct callback for getpass function. */
memset(&cb, 0, sizeof(cb)); memset(&cb, 0, sizeof(cb));
@@ -120,7 +114,7 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw)
callback = &cb; callback = &cb;
} }
switch (status) { switch (closure->tstat) {
case TS_FATAL: case TS_FATAL:
/* Fatal error (usually setuid failure), unsafe to proceed. */ /* Fatal error (usually setuid failure), unsafe to proceed. */
goto done; goto done;
@@ -144,32 +138,22 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw)
} }
/* XXX - should not lecture if askpass helper is being used. */ /* XXX - should not lecture if askpass helper is being used. */
lectured = display_lecture(status); lectured = display_lecture(closure->tstat);
/* Expand any escapes in the prompt. */ /* Expand any escapes in the prompt. */
prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt, prompt = expand_prompt(user_prompt ? user_prompt : def_passprompt,
closure.auth_pw->pw_name); closure->auth_pw->pw_name);
if (prompt == NULL) if (prompt == NULL)
goto done; goto done;
ret = verify_user(closure.auth_pw, prompt, validated, callback); ret = verify_user(closure->auth_pw, prompt, validated, callback);
if (ret == true && lectured) if (ret == true && lectured)
(void)set_lectured(); /* lecture error not fatal */ (void)set_lectured(); /* lecture error not fatal */
free(prompt); free(prompt);
break; break;
} }
/*
* Only update time stamp if user was validated.
* Failure to update the time stamp is not a fatal error.
*/
if (ret == true && ISSET(validated, VALIDATE_SUCCESS) && status != TS_ERROR)
(void)timestamp_update(closure.cookie, closure.auth_pw);
done: done:
if (closure.cookie != NULL)
timestamp_close(closure.cookie);
sudo_pw_delref(closure.auth_pw);
debug_return_int(ret); debug_return_int(ret);
} }
@@ -180,7 +164,7 @@ done:
int int
check_user(int validated, int mode) check_user(int validated, int mode)
{ {
struct passwd *auth_pw; struct getpass_closure closure = { TS_ERROR };
int ret = -1; int ret = -1;
bool exempt = false; bool exempt = false;
debug_decl(check_user, SUDOERS_DEBUG_AUTH) debug_decl(check_user, SUDOERS_DEBUG_AUTH)
@@ -189,9 +173,9 @@ check_user(int validated, int mode)
* Init authentication system regardless of whether we need a password. * Init authentication system regardless of whether we need a password.
* Required for proper PAM session support. * Required for proper PAM session support.
*/ */
if ((auth_pw = get_authpw(mode)) == NULL) if ((closure.auth_pw = get_authpw(mode)) == NULL)
goto done; goto done;
if (sudo_auth_init(auth_pw) == -1) if (sudo_auth_init(closure.auth_pw) == -1)
goto done; goto done;
/* /*
@@ -222,15 +206,26 @@ check_user(int validated, int mode)
} }
} }
ret = check_user_interactive(validated, mode, auth_pw); ret = check_user_interactive(validated, mode, &closure);
done: done:
if (ret == true) { if (ret == true) {
/* The approval function may disallow a user post-authentication. */ /* The approval function may disallow a user post-authentication. */
ret = sudo_auth_approval(auth_pw, validated, exempt); ret = sudo_auth_approval(closure.auth_pw, validated, exempt);
/*
* Only update time stamp if user validated and was approved.
* Failure to update the time stamp is not a fatal error.
*/
if (ret == true && closure.tstat != TS_ERROR) {
if (ISSET(validated, VALIDATE_SUCCESS))
(void)timestamp_update(closure.cookie, closure.auth_pw);
}
} }
sudo_auth_cleanup(auth_pw); timestamp_close(closure.cookie);
sudo_pw_delref(auth_pw); sudo_auth_cleanup(closure.auth_pw);
if (closure.auth_pw != NULL)
sudo_pw_delref(closure.auth_pw);
debug_return_int(ret); debug_return_int(ret);
} }