Block SIGINT and SIGQUIT while verifying passwords so that
authentication modules that use sleep() are not interrupted. If the user interrupted authentication, exit the loop.
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif /* HAVE_UNISTD_H */
|
#endif /* HAVE_UNISTD_H */
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <siad.h>
|
#include <siad.h>
|
||||||
|
|
||||||
#include "sudoers.h"
|
#include "sudoers.h"
|
||||||
@@ -62,6 +63,8 @@ static int
|
|||||||
sudo_collect(int timeout, int rendition, uchar_t *title, int nprompts,
|
sudo_collect(int timeout, int rendition, uchar_t *title, int nprompts,
|
||||||
prompt_t *prompts)
|
prompt_t *prompts)
|
||||||
{
|
{
|
||||||
|
int rval;
|
||||||
|
sigset_t mask, omask;
|
||||||
debug_decl(sudo_collect, SUDO_DEBUG_AUTH)
|
debug_decl(sudo_collect, SUDO_DEBUG_AUTH)
|
||||||
|
|
||||||
switch (rendition) {
|
switch (rendition) {
|
||||||
@@ -82,7 +85,18 @@ sudo_collect(int timeout, int rendition, uchar_t *title, int nprompts,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_return_int(sia_collect_trm(timeout, rendition, title, nprompts, prompts));
|
/* Unblock SIGINT and SIGQUIT during password entry. */
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGQUIT);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &mask, &omask);
|
||||||
|
|
||||||
|
rval = sia_collect_trm(timeout, rendition, title, nprompts, prompts);
|
||||||
|
|
||||||
|
/* Restore previous signal mask. */
|
||||||
|
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
|
||||||
|
debug_return_int(rval);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -118,7 +132,7 @@ sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
|
|||||||
|
|
||||||
def_prompt = prompt; /* for sudo_collect */
|
def_prompt = prompt; /* for sudo_collect */
|
||||||
|
|
||||||
/* XXX - need a way to detect user hitting return or EOF at prompt */
|
/* XXX - need a way to detect user hitting ^C or EOF at prompt */
|
||||||
if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
|
if (sia_ses_reauthent(sudo_collect, siah) == SIASUCCESS)
|
||||||
debug_return_int(AUTH_SUCCESS);
|
debug_return_int(AUTH_SUCCESS);
|
||||||
else
|
else
|
||||||
|
@@ -174,6 +174,15 @@ pass_warn(void)
|
|||||||
debug_return;
|
debug_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
user_interrupted(void)
|
||||||
|
{
|
||||||
|
sigset_t mask;
|
||||||
|
|
||||||
|
return (sigpending(&mask) == 0 &&
|
||||||
|
(sigismember(&mask, SIGINT) || sigismember(&mask, SIGQUIT)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify the specified user.
|
* Verify the specified user.
|
||||||
* Returns true if verified, false if not or -1 on error.
|
* Returns true if verified, false if not or -1 on error.
|
||||||
@@ -186,15 +195,10 @@ verify_user(struct passwd *pw, char *prompt, int validated)
|
|||||||
int status, rval;
|
int status, rval;
|
||||||
char *p;
|
char *p;
|
||||||
sudo_auth *auth;
|
sudo_auth *auth;
|
||||||
sigaction_t sa, osa;
|
sigset_t mask, omask;
|
||||||
|
sigaction_t sa, saved_sigtstp;
|
||||||
debug_decl(verify_user, SUDO_DEBUG_AUTH)
|
debug_decl(verify_user, SUDO_DEBUG_AUTH)
|
||||||
|
|
||||||
/* 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. */
|
/* Make sure we have at least one auth method. */
|
||||||
if (auth_switch[0].name == NULL) {
|
if (auth_switch[0].name == NULL) {
|
||||||
audit_failure(NewArgc, NewArgv, N_("no authentication methods"));
|
audit_failure(NewArgc, NewArgv, N_("no authentication methods"));
|
||||||
@@ -205,9 +209,33 @@ verify_user(struct passwd *pw, char *prompt, int validated)
|
|||||||
debug_return_int(-1);
|
debug_return_int(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable suspend during password entry. */
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sa.sa_handler = SIG_DFL;
|
||||||
|
(void) sigaction(SIGTSTP, &sa, &saved_sigtstp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We treat authentication as a critical section and block
|
||||||
|
* keyboard-generated signals such as SIGINT and SIGQUIT
|
||||||
|
* which might otherwise interrupt a sleep(3).
|
||||||
|
* They are temporarily unblocked by auth_getpass().
|
||||||
|
*/
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGQUIT);
|
||||||
|
(void) sigprocmask(SIG_BLOCK, &mask, &omask);
|
||||||
|
|
||||||
while (--counter) {
|
while (--counter) {
|
||||||
int num_methods = 0;
|
int num_methods = 0;
|
||||||
|
|
||||||
|
/* If user attempted to interrupt password verify, quit now. */
|
||||||
|
if (user_interrupted())
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (counter != def_passwd_tries)
|
||||||
|
pass_warn();
|
||||||
|
|
||||||
/* Do any per-method setup and unconfigure the method if needed */
|
/* Do any per-method setup and unconfigure the method if needed */
|
||||||
for (auth = auth_switch; auth->name; auth++) {
|
for (auth = auth_switch; auth->name; auth++) {
|
||||||
if (IS_DISABLED(auth))
|
if (IS_DISABLED(auth))
|
||||||
@@ -217,7 +245,7 @@ verify_user(struct passwd *pw, char *prompt, int validated)
|
|||||||
status = (auth->setup)(pw, &prompt, auth);
|
status = (auth->setup)(pw, &prompt, auth);
|
||||||
if (status == AUTH_FAILURE)
|
if (status == AUTH_FAILURE)
|
||||||
SET(auth->flags, FLAG_DISABLED);
|
SET(auth->flags, FLAG_DISABLED);
|
||||||
else if (status == AUTH_FATAL)
|
else if (status == AUTH_FATAL || user_interrupted())
|
||||||
goto done; /* assume error msg already printed */
|
goto done; /* assume error msg already printed */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,18 +272,23 @@ verify_user(struct passwd *pw, char *prompt, int validated)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
success = auth->status = (auth->verify)(pw, p, auth);
|
success = auth->status = (auth->verify)(pw, p, auth);
|
||||||
if (auth->status != AUTH_FAILURE)
|
if (success != AUTH_FAILURE)
|
||||||
goto done;
|
break;
|
||||||
}
|
}
|
||||||
if (!standalone)
|
if (!standalone)
|
||||||
memset_s(p, SUDO_CONV_REPL_MAX, 0, strlen(p));
|
memset_s(p, SUDO_CONV_REPL_MAX, 0, strlen(p));
|
||||||
pass_warn();
|
|
||||||
|
if (success != AUTH_FAILURE)
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
/* Restore signal handlers and signal mask. */
|
||||||
|
(void) sigaction(SIGTSTP, &saved_sigtstp, NULL);
|
||||||
|
(void) sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
|
||||||
switch (success) {
|
switch (success) {
|
||||||
case AUTH_SUCCESS:
|
case AUTH_SUCCESS:
|
||||||
(void) sigaction(SIGTSTP, &osa, NULL);
|
|
||||||
rval = true;
|
rval = true;
|
||||||
break;
|
break;
|
||||||
case AUTH_INTR:
|
case AUTH_INTR:
|
||||||
@@ -338,6 +371,7 @@ auth_getpass(const char *prompt, int timeout, int type)
|
|||||||
{
|
{
|
||||||
struct sudo_conv_message msg;
|
struct sudo_conv_message msg;
|
||||||
struct sudo_conv_reply repl;
|
struct sudo_conv_reply repl;
|
||||||
|
sigset_t mask, omask;
|
||||||
debug_decl(auth_getpass, SUDO_DEBUG_AUTH)
|
debug_decl(auth_getpass, SUDO_DEBUG_AUTH)
|
||||||
|
|
||||||
/* Mask user input if pwfeedback set and echo is off. */
|
/* Mask user input if pwfeedback set and echo is off. */
|
||||||
@@ -348,7 +382,14 @@ auth_getpass(const char *prompt, int timeout, int type)
|
|||||||
if (def_visiblepw)
|
if (def_visiblepw)
|
||||||
type |= SUDO_CONV_PROMPT_ECHO_OK;
|
type |= SUDO_CONV_PROMPT_ECHO_OK;
|
||||||
|
|
||||||
/* Call conversation function */
|
/* Unblock SIGINT and SIGQUIT during password entry. */
|
||||||
|
/* XXX - do in tgetpass() itself instead? */
|
||||||
|
sigemptyset(&mask);
|
||||||
|
sigaddset(&mask, SIGINT);
|
||||||
|
sigaddset(&mask, SIGQUIT);
|
||||||
|
(void) sigprocmask(SIG_UNBLOCK, &mask, &omask);
|
||||||
|
|
||||||
|
/* Call conversation function. */
|
||||||
memset(&msg, 0, sizeof(msg));
|
memset(&msg, 0, sizeof(msg));
|
||||||
msg.msg_type = type;
|
msg.msg_type = type;
|
||||||
msg.timeout = def_passwd_timeout * 60;
|
msg.timeout = def_passwd_timeout * 60;
|
||||||
@@ -356,6 +397,10 @@ auth_getpass(const char *prompt, int timeout, int type)
|
|||||||
memset(&repl, 0, sizeof(repl));
|
memset(&repl, 0, sizeof(repl));
|
||||||
sudo_conv(1, &msg, &repl);
|
sudo_conv(1, &msg, &repl);
|
||||||
/* XXX - check for ENOTTY? */
|
/* XXX - check for ENOTTY? */
|
||||||
|
|
||||||
|
/* Restore previous signal mask. */
|
||||||
|
(void) sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||||
|
|
||||||
debug_return_str_masked(repl.reply);
|
debug_return_str_masked(repl.reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user