Add a struct sudo_conv_callback that contains on_suspend and on_resume

function pointer args plus a closure pointer and at it to the
conversation function.
This commit is contained in:
Todd C. Miller
2015-09-07 06:06:08 -06:00
parent af47293800
commit 98a15d9879
28 changed files with 247 additions and 78 deletions

View File

@@ -1297,9 +1297,26 @@ DDEESSCCRRIIPPTTIIOONN
char *reply;
};
/* Conversation callback API version major/minor */
#define SUDO_CONV_CALLBACK_VERSION_MAJOR 1
#define SUDO_CONV_CALLBACK_VERSION_MINOR 0
#define SUDO_CONV_CALLBACK_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_CONV_CALLBACK_VERSION \
SUDO_CONV_CALLBACK_MKVERSION(SUDO_CONV_CALLBACK_VERSION_MAJOR, \
SUDO_CONV_CALLBACK_VERSION_MINOR)
typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
struct sudo_conv_callback {
unsigned int version;
void *closure;
sudo_conv_callback_fn_t on_suspend;
sudo_conv_callback_fn_t on_resume;
};
typedef int (*sudo_conv_t)(int num_msgs,
const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
struct sudo_conv_reply replies[],
struct sudo_conv_callback *callback);
typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
@@ -1309,13 +1326,21 @@ DDEESSCCRRIIPPTTIIOONN
To use the ccoonnvveerrssaattiioonn() function, the plugin must pass an array of
sudo_conv_message and sudo_conv_reply structures. There must be a struct
sudo_conv_message and struct sudo_conv_reply for each message in the
conversation. The plugin is responsible for freeing the reply buffer
located in each struct sudo_conv_reply, if it is not NULL.
SUDO_CONV_REPL_MAX represents the maximum length of the reply buffer (not
including the trailing NUL character). In practical terms, this is the
longest password ssuuddoo will support. It is also useful as a maximum value
for the mmeemmsseett__ss() function when clearing passwords filled in by the
conversation function.
conversation. The struct sudo_conv_callback pointer, if not NULL,
contains function pointers that are called when the ssuuddoo process is
suspended and/or resumed during conversation input. The functions are
passed the signal that caused ssuuddoo to be suspended and the _c_l_o_s_u_r_e
pointer. This allows the plugin to release resources such as locks that
should not be held indefinitely on suspend and reacquire them on resume.
Note that the functions are not actually invoked from within a signal
handler.
The plugin is responsible for freeing the reply buffer located in each
struct sudo_conv_reply, if it is not NULL. SUDO_CONV_REPL_MAX represents
the maximum length of the reply buffer (not including the trailing NUL
character). In practical terms, this is the longest password ssuuddoo will
support. It is also useful as a maximum value for the mmeemmsseett__ss()
function when clearing passwords filled in by the conversation function.
The pprriinnttff()-style function uses the same underlying mechanism as the
ccoonnvveerrssaattiioonn() function but only supports SUDO_CONV_INFO_MSG and
@@ -1490,6 +1515,12 @@ PPLLUUGGIINN AAPPII CCHHAANNGGEELLOOGG
Version 1.8 (sudo 1.8.15)
The _s_u_d_o_e_d_i_t___f_o_l_l_o_w entry was added to the command_info list.
The sudo _c_o_n_v_e_r_s_a_t_i_o_n function now takes a pointer to a struct
sudo_conv_callback as its fourth argument. The sudo_conv_t
definition has been updated to match. The plugin must specify that
it supports plugin API version 1.8 or higher to receive a
conversation function pointer that supports this argument.
SSEEEE AALLSSOO
sudo.conf(4), sudoers(4), sudo(1m)
@@ -1519,4 +1550,4 @@ DDIISSCCLLAAIIMMEERR
file distributed with ssuuddoo or http://www.sudo.ws/license.html for
complete details.
Sudo 1.8.15 August 6, 2015 Sudo 1.8.15
Sudo 1.8.15 September 2, 2015 Sudo 1.8.15

View File

@@ -16,7 +16,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.TH "SUDO_PLUGIN" "5" "August 6, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.TH "SUDO_PLUGIN" "5" "September 2, 2015" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
.nh
.if n .ad l
.SH "NAME"
@@ -2293,9 +2293,26 @@ struct sudo_conv_reply {
char *reply;
};
/* Conversation callback API version major/minor */
#define SUDO_CONV_CALLBACK_VERSION_MAJOR 1
#define SUDO_CONV_CALLBACK_VERSION_MINOR 0
#define SUDO_CONV_CALLBACK_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_CONV_CALLBACK_VERSION \e
SUDO_CONV_CALLBACK_MKVERSION(SUDO_CONV_CALLBACK_VERSION_MAJOR, \e
SUDO_CONV_CALLBACK_VERSION_MINOR)
typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
struct sudo_conv_callback {
unsigned int version;
void *closure;
sudo_conv_callback_fn_t on_suspend;
sudo_conv_callback_fn_t on_resume;
};
typedef int (*sudo_conv_t)(int num_msgs,
const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
struct sudo_conv_reply replies[],
struct sudo_conv_callback *callback);
typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
.RE
@@ -2323,6 +2340,23 @@ and
\fRstruct sudo_conv_reply\fR
for
each message in the conversation.
The
\fRstruct sudo_conv_callback\fR
pointer, if not
\fRNULL\fR,
contains function pointers that are called when the
\fBsudo\fR
process is suspended and/or resumed during conversation input.
The functions are passed the signal that caused
\fBsudo\fR
to be suspended and the
\fIclosure\fR
pointer.
This allows the plugin to release resources such as locks that
should not be held indefinitely on suspend and reacquire them
on resume.
Note that the functions are not actually invoked from within a signal handler.
.PP
The plugin is responsible for freeing the reply buffer located in each
\fRstruct sudo_conv_reply\fR,
if it is not
@@ -2662,6 +2696,17 @@ The
entry was added to the
\fRcommand_info\fR
list.
.sp
The sudo
\fIconversation\fR
function now takes a pointer to a
\fRstruct sudo_conv_callback\fR
as its fourth argument.
The
\fRsudo_conv_t\fR
definition has been updated to match.
The plugin must specify that it supports plugin API version 1.8 or higher
to receive a conversation function pointer that supports this argument.
.SH "SEE ALSO"
sudo.conf(@mansectform@),
sudoers(@mansectform@),

View File

@@ -14,7 +14,7 @@
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd August 6, 2015
.Dd September 2, 2015
.Dt SUDO_PLUGIN @mansectform@
.Os Sudo @PACKAGE_VERSION@
.Sh NAME
@@ -1999,9 +1999,26 @@ struct sudo_conv_reply {
char *reply;
};
/* Conversation callback API version major/minor */
#define SUDO_CONV_CALLBACK_VERSION_MAJOR 1
#define SUDO_CONV_CALLBACK_VERSION_MINOR 0
#define SUDO_CONV_CALLBACK_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_CONV_CALLBACK_VERSION \e
SUDO_CONV_CALLBACK_MKVERSION(SUDO_CONV_CALLBACK_VERSION_MAJOR, \e
SUDO_CONV_CALLBACK_VERSION_MINOR)
typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
struct sudo_conv_callback {
unsigned int version;
void *closure;
sudo_conv_callback_fn_t on_suspend;
sudo_conv_callback_fn_t on_resume;
};
typedef int (*sudo_conv_t)(int num_msgs,
const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
struct sudo_conv_reply replies[],
struct sudo_conv_callback *callback);
typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
.Ed
@@ -2028,6 +2045,23 @@ and
.Li struct sudo_conv_reply
for
each message in the conversation.
The
.Li struct sudo_conv_callback
pointer, if not
.Dv NULL ,
contains function pointers that are called when the
.Nm sudo
process is suspended and/or resumed during conversation input.
The functions are passed the signal that caused
.Nm sudo
to be suspended and the
.Fa closure
pointer.
This allows the plugin to release resources such as locks that
should not be held indefinitely on suspend and reacquire them
on resume.
Note that the functions are not actually invoked from within a signal handler.
.Pp
The plugin is responsible for freeing the reply buffer located in each
.Li struct sudo_conv_reply ,
if it is not
@@ -2329,6 +2363,17 @@ The
entry was added to the
.Li command_info
list.
.Pp
The sudo
.Em conversation
function now takes a pointer to a
.Li struct sudo_conv_callback
as its fourth argument.
The
.Li sudo_conv_t
definition has been updated to match.
The plugin must specify that it supports plugin API version 1.8 or higher
to receive a conversation function pointer that supports this argument.
.El
.Sh SEE ALSO
.Xr sudo.conf @mansectform@ ,

View File

@@ -121,6 +121,7 @@ typedef void (*sudo_fatal_callback_t)(void);
struct sudo_conv_message;
struct sudo_conv_reply;
struct sudo_conv_callback;
__dso_public int sudo_fatal_callback_deregister_v1(sudo_fatal_callback_t func);
__dso_public int sudo_fatal_callback_register_v1(sudo_fatal_callback_t func);
@@ -134,7 +135,7 @@ __dso_public void sudo_warn_nodebug_v1(const char *fmt, ...) __printf0like(1, 2)
__dso_public void sudo_warnx_nodebug_v1(const char *fmt, ...) __printflike(1, 2);
__dso_public void sudo_vwarn_nodebug_v1(const char *fmt, va_list ap) __printf0like(1, 0);
__dso_public void sudo_vwarnx_nodebug_v1(const char *fmt, va_list ap) __printflike(1, 0);
__dso_public void sudo_warn_set_conversation_v1(int (*conv)(int num_msgs, const struct sudo_conv_message *msgs, struct sudo_conv_reply *replies));
__dso_public void sudo_warn_set_conversation_v1(int (*conv)(int num_msgs, const struct sudo_conv_message *msgs, struct sudo_conv_reply *replies, struct sudo_conv_callback *callback));
#define sudo_fatal_callback_deregister(_a) sudo_fatal_callback_deregister_v1((_a))
#define sudo_fatal_callback_register(_a) sudo_fatal_callback_register_v1((_a))
@@ -148,7 +149,6 @@ __dso_public void sudo_warn_set_conversation_v1(int (*conv)(int num_msgs, const
#define sudo_vwarn_nodebug(_a, _b) sudo_vwarn_nodebug_v1((_a), (_b))
#define sudo_vwarnx_nodebug(_a, _b) sudo_vwarnx_nodebug_v1((_a), (_b))
#define sudo_warn_set_conversation(_a) sudo_warn_set_conversation_v1(_a)
#define sudo_warn_set_conversation(_a) sudo_warn_set_conversation_v1(_a)
#ifdef DEFAULT_TEXT_DOMAIN
# define sudo_warn_gettext(_a) sudo_warn_gettext_v1(DEFAULT_TEXT_DOMAIN, (_a))

View File

@@ -61,8 +61,27 @@ struct sudo_conv_reply {
char *reply;
};
/* Conversation callback API version major/minor */
#define SUDO_CONV_CALLBACK_VERSION_MAJOR 1
#define SUDO_CONV_CALLBACK_VERSION_MINOR 0
#define SUDO_CONV_CALLBACK_MKVERSION(x, y) ((x << 16) | y)
#define SUDO_CONV_CALLBACK_VERSION SUDO_CONV_CALLBACK_MKVERSION(SUDO_CONV_CALLBACK_VERSION_MAJOR, SUDO_CONV_CALLBACK_VERSION_MINOR)
/*
* Callback struct to be passed to the conversation function.
* Can be used to perform operations on suspend/resume such
* as dropping/acquiring locks.
*/
typedef int (*sudo_conv_callback_fn_t)(int signo, void *closure);
struct sudo_conv_callback {
unsigned int version;
void *closure;
sudo_conv_callback_fn_t on_suspend;
sudo_conv_callback_fn_t on_resume;
};
typedef int (*sudo_conv_t)(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);
typedef int (*sudo_printf_t)(int msg_type, const char *fmt, ...);
/*

View File

@@ -179,7 +179,7 @@ warning(int errnum, const char *fmt, va_list ap)
}
msgs[nmsgs].msg_type = SUDO_CONV_ERROR_MSG;
msgs[nmsgs++].msg = "\n";
sudo_warn_conversation(nmsgs, msgs, NULL);
sudo_warn_conversation(nmsgs, msgs, NULL, NULL);
if (buf != static_buf)
free(buf);
} else {

View File

@@ -42,7 +42,7 @@
#include "sudo_auth.h"
int
sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
struct ktc_encryptionKey afs_key;
struct ktc_token afs_token;

View File

@@ -128,7 +128,7 @@ sudo_aix_init(struct passwd *pw, sudo_auth *auth)
}
int
sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
{
char *pass, *message = NULL;
int result = 1, reenter = 0;
@@ -137,7 +137,7 @@ sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
do {
pass = auth_getpass(prompt, def_passwd_timeout * 60,
SUDO_CONV_PROMPT_ECHO_OFF);
SUDO_CONV_PROMPT_ECHO_OFF, callback);
if (pass == NULL)
break;
free(message);
@@ -157,7 +157,7 @@ sudo_aix_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
msg.msg_type = SUDO_CONV_ERROR_MSG;
msg.msg = message;
memset(&repl, 0, sizeof(repl));
sudo_conv(1, &msg, &repl);
sudo_conv(1, &msg, &repl, NULL);
}
rval = pass ? AUTH_FAILURE : AUTH_INTR;
}

View File

@@ -98,7 +98,7 @@ bsdauth_init(struct passwd *pw, sudo_auth *auth)
}
int
bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
{
char *pass;
char *s;
@@ -121,9 +121,9 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
* S/Key.
*/
if ((s = auth_challenge(as)) == NULL) {
pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback);
} else {
pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
pass = auth_getpass(prompt, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback);
if (pass && *pass == '\0') {
if ((prompt = strrchr(s, '\n')))
prompt++;
@@ -142,7 +142,7 @@ bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
debug_return_int(AUTH_FATAL);
}
pass = auth_getpass(prompt, def_passwd_timeout * 60,
SUDO_CONV_PROMPT_ECHO_ON);
SUDO_CONV_PROMPT_ECHO_ON, callback);
free(s);
}
}

View File

@@ -59,7 +59,7 @@
static int check_dce_status(error_status_t, char *);
int
sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth)
sudo_dce_verify(struct passwd *pw, char *plain_pw, sudo_auth *auth, struct sudo_conv_callback *callback)
{
struct passwd temp_pw;
sec_passwd_rec_t password_rec;

View File

@@ -72,7 +72,7 @@ sudo_fwtk_init(struct passwd *pw, sudo_auth *auth)
}
int
sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
{
char *pass; /* Password from the user */
char buf[SUDO_CONV_REPL_MAX + 12]; /* General prupose buffer */
@@ -91,17 +91,17 @@ restart:
/* Get the password/response from the user. */
if (strncmp(resp, "challenge ", 10) == 0) {
(void) snprintf(buf, sizeof(buf), "%s\nResponse: ", &resp[10]);
pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
pass = auth_getpass(buf, def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback);
if (pass && *pass == '\0') {
pass = auth_getpass("Response [echo on]: ",
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON);
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_ON, callback);
}
} else if (strncmp(resp, "chalnecho ", 10) == 0) {
pass = auth_getpass(&resp[10], def_passwd_timeout * 60,
SUDO_CONV_PROMPT_ECHO_OFF);
SUDO_CONV_PROMPT_ECHO_OFF, callback);
} else if (strncmp(resp, "password", 8) == 0) {
pass = auth_getpass(prompt, def_passwd_timeout * 60,
SUDO_CONV_PROMPT_ECHO_OFF);
SUDO_CONV_PROMPT_ECHO_OFF, callback);
} else if (strncmp(resp, "display ", 8) == 0) {
fprintf(stderr, "%s\n", &resp[8]);
strlcpy(buf, "response dummy", sizeof(buf));

View File

@@ -180,7 +180,7 @@ done:
#ifdef HAVE_KRB5_VERIFY_USER
int
sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
krb5_context sudo_context;
krb5_principal princ;

View File

@@ -71,7 +71,8 @@
static int converse(int, PAM_CONST struct pam_message **,
struct pam_response **, void *);
static struct pam_conv pam_conv = { converse, NULL };
static struct sudo_conv_callback *conv_callback;
static struct pam_conv pam_conv = { converse, &conv_callback };
static char *def_prompt = PASSPROMPT;
static bool getpass_error;
static pam_handle_t *pamh;
@@ -137,7 +138,7 @@ sudo_pam_init(struct passwd *pw, sudo_auth *auth)
}
int
sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
{
const char *s;
int *pam_status = (int *) auth->data;
@@ -145,6 +146,7 @@ sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
def_prompt = prompt; /* for converse */
getpass_error = false; /* set by converse if user presses ^C */
conv_callback = callback; /* passed to conversation function */
/* PAM_SILENT prevents the authentication service from generating output. */
*pam_status = pam_authenticate(pamh, PAM_SILENT);
@@ -375,7 +377,7 @@ sudo_pam_end_session(struct passwd *pw, sudo_auth *auth)
*/
static int
converse(int num_msg, PAM_CONST struct pam_message **msg,
struct pam_response **response, void *appdata_ptr)
struct pam_response **response, void *callback)
{
struct pam_response *pr;
PAM_CONST struct pam_message *pm;
@@ -427,7 +429,7 @@ converse(int num_msg, PAM_CONST struct pam_message **msg,
prompt = pm->msg;
}
/* Read the password unless interrupted. */
pass = auth_getpass(prompt, def_passwd_timeout * 60, type);
pass = auth_getpass(prompt, def_passwd_timeout * 60, type, callback);
if (pass == NULL) {
/* Error (or ^C) reading password, don't try again. */
getpass_error = true;

View File

@@ -54,7 +54,7 @@ sudo_passwd_init(struct passwd *pw, sudo_auth *auth)
}
int
sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
char sav, *epass;
char *pw_epasswd = auth->data;

View File

@@ -124,7 +124,7 @@ sudo_rfc1938_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
}
int
sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
debug_decl(sudo_rfc1938_verify, SUDOERS_DEBUG_AUTH)

View File

@@ -65,7 +65,7 @@ sudo_secureware_init(struct passwd *pw, sudo_auth *auth)
}
int
sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
char *pw_epasswd = auth->data;
char *epass = NULL;

View File

@@ -139,14 +139,14 @@ sudo_securid_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
* incorrect authentication, fatal on errors
*/
int
sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth)
sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback)
{
SDI_HANDLE *sd = (SDI_HANDLE *) auth->data;
int rval;
debug_decl(sudo_securid_verify, SUDOERS_DEBUG_AUTH)
pass = auth_getpass("Enter your PASSCODE: ",
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback);
/* Have ACE verify password */
switch (SD_Check(*sd, pass, pw->pw_name)) {
@@ -181,7 +181,7 @@ sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth)
!!! ATTENTION !!!\n\
Wait for the token code to change, \n\
then enter the new token code.\n", \
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF);
def_passwd_timeout * 60, SUDO_CONV_PROMPT_ECHO_OFF, callback);
if (SD_Next(*sd, pass) == ACM_OK) {
rval = AUTH_SUCCESS;

View File

@@ -126,7 +126,7 @@ sudo_sia_setup(struct passwd *pw, char **promptp, sudo_auth *auth)
}
int
sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth)
sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback)
{
SIAENTITY *siah = (SIAENTITY *) auth->data;
debug_decl(sudo_sia_verify, SUDOERS_DEBUG_AUTH)

View File

@@ -209,7 +209,8 @@ user_interrupted(void)
* Returns true if verified, false if not or -1 on error.
*/
int
verify_user(struct passwd *pw, char *prompt, int validated)
verify_user(struct passwd *pw, char *prompt, int validated,
struct sudo_conv_callback *callback)
{
unsigned int ntries;
int rval, status, success = AUTH_FAILURE;
@@ -281,7 +282,7 @@ verify_user(struct passwd *pw, char *prompt, int validated)
p = prompt;
} else {
p = auth_getpass(prompt, def_passwd_timeout * 60,
SUDO_CONV_PROMPT_ECHO_OFF);
SUDO_CONV_PROMPT_ECHO_OFF, callback);
if (p == NULL)
break;
}
@@ -291,7 +292,7 @@ verify_user(struct passwd *pw, char *prompt, int validated)
if (IS_DISABLED(auth))
continue;
success = auth->status = (auth->verify)(pw, p, auth);
success = auth->status = (auth->verify)(pw, p, auth, callback);
if (success != AUTH_FAILURE)
break;
}
@@ -387,7 +388,8 @@ sudo_auth_end_session(struct passwd *pw)
}
char *
auth_getpass(const char *prompt, int timeout, int type)
auth_getpass(const char *prompt, int timeout, int type,
struct sudo_conv_callback *callback)
{
struct sudo_conv_message msg;
struct sudo_conv_reply repl;
@@ -415,7 +417,7 @@ auth_getpass(const char *prompt, int timeout, int type)
msg.timeout = def_passwd_timeout * 60;
msg.msg = prompt;
memset(&repl, 0, sizeof(repl));
sudo_conv(1, &msg, &repl);
sudo_conv(1, &msg, &repl, callback);
/* XXX - check for ENOTTY? */
/* Restore previous signal mask. */

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999-2005, 2007-2012 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 1999-2005, 2007-2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -30,7 +30,7 @@ typedef struct sudo_auth {
void *data; /* method-specific data pointer */
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 (*verify)(struct passwd *pw, char *p, struct sudo_auth *auth, struct sudo_conv_callback *callback);
int (*cleanup)(struct passwd *pw, struct sudo_auth *auth);
int (*begin_session)(struct passwd *pw, char **user_env[], struct sudo_auth *auth);
int (*end_session)(struct passwd *pw, struct sudo_auth *auth);
@@ -47,47 +47,48 @@ typedef struct sudo_auth {
#define IS_ONEANDONLY(x) ((x)->flags & FLAG_ONEANDONLY)
/* Like tgetpass() but uses conversation function */
char *auth_getpass(const char *prompt, int timeout, int type);
char *auth_getpass(const char *prompt, int timeout, int type,
struct sudo_conv_callback *callback);
/* Pointer to conversation function to use with auth_getpass(). */
extern sudo_conv_t sudo_conv;
/* Prototypes for standalone methods */
int bsdauth_init(struct passwd *pw, sudo_auth *auth);
int bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int bsdauth_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback);
int bsdauth_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_aix_init(struct passwd *pw, sudo_auth *auth);
int sudo_aix_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_aix_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_aix_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_fwtk_init(struct passwd *pw, sudo_auth *auth);
int sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int sudo_fwtk_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_fwtk_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_pam_init(struct passwd *pw, sudo_auth *auth);
int sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int sudo_pam_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_pam_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_pam_begin_session(struct passwd *pw, char **user_env[], sudo_auth *auth);
int sudo_pam_end_session(struct passwd *pw, sudo_auth *auth);
int sudo_securid_init(struct passwd *pw, sudo_auth *auth);
int sudo_securid_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_securid_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_sia_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth);
int sudo_sia_verify(struct passwd *pw, char *prompt, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_sia_cleanup(struct passwd *pw, sudo_auth *auth);
/* Prototypes for normal methods */
int sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_dce_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_afs_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_dce_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_krb5_init(struct passwd *pw, sudo_auth *auth);
int sudo_krb5_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_krb5_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_krb5_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_passwd_init(struct passwd *pw, sudo_auth *auth);
int sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_passwd_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_passwd_cleanup(struct passwd *pw, sudo_auth *auth);
int sudo_rfc1938_setup(struct passwd *pw, char **prompt, sudo_auth *auth);
int sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_rfc1938_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_secureware_init(struct passwd *pw, sudo_auth *auth);
int sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth);
int sudo_secureware_verify(struct passwd *pw, char *pass, sudo_auth *auth, struct sudo_conv_callback *callback);
int sudo_secureware_cleanup(struct passwd *pw, sudo_auth *auth);
/* Fields: name, flags, init, setup, verify, cleanup, begin_sess, end_sess */

View File

@@ -96,7 +96,7 @@ check_user_interactive(int validated, int mode, struct passwd *auth_pw)
if (prompt == NULL)
goto done;
rval = verify_user(auth_pw, prompt, validated);
rval = verify_user(auth_pw, prompt, validated, NULL); /* XXX */
if (rval == true && lectured) {
if (set_lectured() == -1)
rval = -1;
@@ -192,7 +192,7 @@ display_lecture(int status)
buf[nread] = '\0';
msg.msg_type = SUDO_CONV_ERROR_MSG;
msg.msg = buf;
sudo_conv(1, &msg, &repl);
sudo_conv(1, &msg, &repl, NULL);
}
fclose(fp);
} else {
@@ -203,7 +203,7 @@ display_lecture(int status)
" #1) Respect the privacy of others.\n"
" #2) Think before you type.\n"
" #3) With great power comes great responsibility.\n\n");
sudo_conv(1, &msg, &repl);
sudo_conv(1, &msg, &repl, NULL);
}
debug_return_bool(true);
}

View File

@@ -261,7 +261,7 @@ output(const char *buf)
msg.msg_type = SUDO_CONV_INFO_MSG;
msg.msg = buf;
memset(&repl, 0, sizeof(repl));
if (sudo_conv(1, &msg, &repl) == -1)
if (sudo_conv(1, &msg, &repl, NULL) == -1)
debug_return_int(0);
debug_return_int(strlen(buf));
}

View File

@@ -243,7 +243,7 @@ int set_lectured(void);
/* sudo_auth.c */
bool sudo_auth_needs_end_session(void);
int verify_user(struct passwd *pw, char *prompt, int validated);
int verify_user(struct passwd *pw, char *prompt, int validated, struct sudo_conv_callback *callback);
int sudo_auth_begin_session(struct passwd *pw, char **user_env[]);
int sudo_auth_end_session(struct passwd *pw);
int sudo_auth_init(struct passwd *pw);

View File

@@ -43,7 +43,7 @@ extern int tgetpass_flags; /* XXX */
*/
int
sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[])
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
{
struct sudo_conv_reply *repl;
const struct sudo_conv_message *msg;
@@ -65,7 +65,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
if (ISSET(msg->msg_type, SUDO_CONV_PROMPT_ECHO_OK))
SET(flags, TGP_NOECHO_TRY);
/* Read the password unless interrupted. */
pass = tgetpass(msg->msg, msg->timeout, flags);
pass = tgetpass(msg->msg, msg->timeout, flags, callback);
if (pass == NULL)
goto err;
if ((repl->reply = strdup(pass)) == NULL) {
@@ -103,6 +103,13 @@ err:
return -1;
}
int
sudo_conversation_1_7(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[])
{
return sudo_conversation(num_msgs, msgs, replies, NULL);
}
int
sudo_conversation_printf(int msg_type, const char *fmt, ...)
{

View File

@@ -1187,7 +1187,7 @@ policy_open(struct plugin_container *plugin, struct sudo_settings *settings,
case SUDO_API_MKVERSION(1, 0):
case SUDO_API_MKVERSION(1, 1):
rval = plugin->u.policy_1_0->open(plugin->u.io_1_0->version,
sudo_conversation, sudo_conversation_printf, plugin_settings,
sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
user_info, user_env);
break;
default:
@@ -1346,12 +1346,12 @@ iolog_open(struct plugin_container *plugin, struct sudo_settings *settings,
switch (plugin->u.generic->version) {
case SUDO_API_MKVERSION(1, 0):
rval = plugin->u.io_1_0->open(plugin->u.io_1_0->version,
sudo_conversation, sudo_conversation_printf, plugin_settings,
sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
user_info, argc, argv, user_env);
break;
case SUDO_API_MKVERSION(1, 1):
rval = plugin->u.io_1_1->open(plugin->u.io_1_1->version,
sudo_conversation, sudo_conversation_printf, plugin_settings,
sudo_conversation_1_7, sudo_conversation_printf, plugin_settings,
user_info, command_info, argc, argv, user_env);
break;
default:

View File

@@ -183,7 +183,8 @@ struct timeval;
void cleanup(int);
/* tgetpass.c */
char *tgetpass(const char *, int, int);
char *tgetpass(const char *prompt, int timeout, int flags,
struct sudo_conv_callback *callback);
/* exec.c */
int pipe_nonblock(int fds[2]);

View File

@@ -26,13 +26,16 @@ struct generic_plugin {
/* the rest depends on the type... */
};
typedef int (*sudo_conv_1_7_t)(int num_msgs,
const struct sudo_conv_message msgs[], struct sudo_conv_reply replies[]);
/*
* Backwards-compatible structures for API bumps.
*/
struct policy_plugin_1_0 {
unsigned int type;
unsigned int version;
int (*open)(unsigned int version, sudo_conv_t conversation,
int (*open)(unsigned int version, sudo_conv_1_7_t conversation,
sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], char * const user_env[]);
void (*close)(int exit_status, int error); /* wait status or error */
@@ -49,7 +52,7 @@ struct policy_plugin_1_0 {
struct io_plugin_1_0 {
unsigned int type;
unsigned int version;
int (*open)(unsigned int version, sudo_conv_t conversation,
int (*open)(unsigned int version, sudo_conv_1_7_t conversation,
sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], int argc, char * const argv[],
char * const user_env[]);
@@ -64,7 +67,7 @@ struct io_plugin_1_0 {
struct io_plugin_1_1 {
unsigned int type;
unsigned int version;
int (*open)(unsigned int version, sudo_conv_t conversation,
int (*open)(unsigned int version, sudo_conv_1_7_t conversation,
sudo_printf_t sudo_printf, char * const settings[],
char * const user_info[], char * const command_info[],
int argc, char * const argv[], char * const user_env[]);
@@ -103,6 +106,8 @@ extern struct plugin_container policy_plugin;
extern struct plugin_container_list io_plugins;
int sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[], struct sudo_conv_callback *callback);
int sudo_conversation_1_7(int num_msgs, const struct sudo_conv_message msgs[],
struct sudo_conv_reply replies[]);
int sudo_conversation_printf(int msg_type, const char *fmt, ...);

View File

@@ -55,7 +55,8 @@ static char *sudo_askpass(const char *, const char *);
* Like getpass(3) but with timeout and echo flags.
*/
char *
tgetpass(const char *prompt, int timeout, int flags)
tgetpass(const char *prompt, int timeout, int flags,
struct sudo_conv_callback *callback)
{
sigaction_t sa, savealrm, saveint, savehup, savequit, saveterm;
sigaction_t savetstp, savettin, savettou, savepipe;
@@ -173,11 +174,21 @@ restore:
*/
for (i = 0; i < NSIG; i++) {
if (signo[i]) {
switch (i) {
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
if (callback != NULL && callback->on_suspend != NULL)
callback->on_suspend(i, callback->closure);
break;
}
kill(getpid(), i);
switch (i) {
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
if (callback != NULL && callback->on_resume != NULL)
callback->on_resume(i, callback->closure);
need_restart = 1;
break;
}