From 98a15d9879455ae5fe91578b1465d3e5735f29fa Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Mon, 7 Sep 2015 06:06:08 -0600 Subject: [PATCH] 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. --- doc/sudo_plugin.cat | 49 +++++++++++++++++++++++++------ doc/sudo_plugin.man.in | 49 +++++++++++++++++++++++++++++-- doc/sudo_plugin.mdoc.in | 49 +++++++++++++++++++++++++++++-- include/sudo_fatal.h | 4 +-- include/sudo_plugin.h | 21 ++++++++++++- lib/util/fatal.c | 2 +- plugins/sudoers/auth/afs.c | 2 +- plugins/sudoers/auth/aix_auth.c | 6 ++-- plugins/sudoers/auth/bsdauth.c | 8 ++--- plugins/sudoers/auth/dce.c | 2 +- plugins/sudoers/auth/fwtk.c | 10 +++---- plugins/sudoers/auth/kerb5.c | 2 +- plugins/sudoers/auth/pam.c | 10 ++++--- plugins/sudoers/auth/passwd.c | 2 +- plugins/sudoers/auth/rfc1938.c | 2 +- plugins/sudoers/auth/secureware.c | 2 +- plugins/sudoers/auth/securid5.c | 6 ++-- plugins/sudoers/auth/sia.c | 2 +- plugins/sudoers/auth/sudo_auth.c | 12 ++++---- plugins/sudoers/auth/sudo_auth.h | 31 +++++++++---------- plugins/sudoers/check.c | 6 ++-- plugins/sudoers/sudo_nss.c | 2 +- plugins/sudoers/sudoers.h | 2 +- src/conversation.c | 11 +++++-- src/sudo.c | 6 ++-- src/sudo.h | 3 +- src/sudo_plugin_int.h | 11 +++++-- src/tgetpass.c | 13 +++++++- 28 files changed, 247 insertions(+), 78 deletions(-) diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index b8795efbc..daa3c6e86 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -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 diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 8987d7efb..d7a44136c 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -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@), diff --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in index 34549cc8f..b49699aad 100644 --- a/doc/sudo_plugin.mdoc.in +++ b/doc/sudo_plugin.mdoc.in @@ -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@ , diff --git a/include/sudo_fatal.h b/include/sudo_fatal.h index f38b56355..43a1ce02d 100644 --- a/include/sudo_fatal.h +++ b/include/sudo_fatal.h @@ -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)) diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index d2c65fcf1..b8fa44591 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -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, ...); /* diff --git a/lib/util/fatal.c b/lib/util/fatal.c index 295cfe3c1..f1b24ea84 100644 --- a/lib/util/fatal.c +++ b/lib/util/fatal.c @@ -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 { diff --git a/plugins/sudoers/auth/afs.c b/plugins/sudoers/auth/afs.c index 5693cb18b..de2235780 100644 --- a/plugins/sudoers/auth/afs.c +++ b/plugins/sudoers/auth/afs.c @@ -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; diff --git a/plugins/sudoers/auth/aix_auth.c b/plugins/sudoers/auth/aix_auth.c index 66a0b23e1..4bc3ae5e2 100644 --- a/plugins/sudoers/auth/aix_auth.c +++ b/plugins/sudoers/auth/aix_auth.c @@ -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; } diff --git a/plugins/sudoers/auth/bsdauth.c b/plugins/sudoers/auth/bsdauth.c index e01b6944a..18a25e32f 100644 --- a/plugins/sudoers/auth/bsdauth.c +++ b/plugins/sudoers/auth/bsdauth.c @@ -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); } } diff --git a/plugins/sudoers/auth/dce.c b/plugins/sudoers/auth/dce.c index e5966152e..262b4ef14 100644 --- a/plugins/sudoers/auth/dce.c +++ b/plugins/sudoers/auth/dce.c @@ -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; diff --git a/plugins/sudoers/auth/fwtk.c b/plugins/sudoers/auth/fwtk.c index 73094d6c2..e144d3cdf 100644 --- a/plugins/sudoers/auth/fwtk.c +++ b/plugins/sudoers/auth/fwtk.c @@ -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)); diff --git a/plugins/sudoers/auth/kerb5.c b/plugins/sudoers/auth/kerb5.c index 8c7aff6f8..ca31f99aa 100644 --- a/plugins/sudoers/auth/kerb5.c +++ b/plugins/sudoers/auth/kerb5.c @@ -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; diff --git a/plugins/sudoers/auth/pam.c b/plugins/sudoers/auth/pam.c index ccd0d1ebc..4c85ebb6a 100644 --- a/plugins/sudoers/auth/pam.c +++ b/plugins/sudoers/auth/pam.c @@ -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; diff --git a/plugins/sudoers/auth/passwd.c b/plugins/sudoers/auth/passwd.c index 9173ff35a..7318f09d3 100644 --- a/plugins/sudoers/auth/passwd.c +++ b/plugins/sudoers/auth/passwd.c @@ -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; diff --git a/plugins/sudoers/auth/rfc1938.c b/plugins/sudoers/auth/rfc1938.c index cf2e37eda..e1474c6ef 100644 --- a/plugins/sudoers/auth/rfc1938.c +++ b/plugins/sudoers/auth/rfc1938.c @@ -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) diff --git a/plugins/sudoers/auth/secureware.c b/plugins/sudoers/auth/secureware.c index a44a3cb0d..1e349a902 100644 --- a/plugins/sudoers/auth/secureware.c +++ b/plugins/sudoers/auth/secureware.c @@ -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; diff --git a/plugins/sudoers/auth/securid5.c b/plugins/sudoers/auth/securid5.c index 7274de0fe..41eec085f 100644 --- a/plugins/sudoers/auth/securid5.c +++ b/plugins/sudoers/auth/securid5.c @@ -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; diff --git a/plugins/sudoers/auth/sia.c b/plugins/sudoers/auth/sia.c index b6c757f4a..a7d262c18 100644 --- a/plugins/sudoers/auth/sia.c +++ b/plugins/sudoers/auth/sia.c @@ -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) diff --git a/plugins/sudoers/auth/sudo_auth.c b/plugins/sudoers/auth/sudo_auth.c index 9b86f3855..eeba9bdfc 100644 --- a/plugins/sudoers/auth/sudo_auth.c +++ b/plugins/sudoers/auth/sudo_auth.c @@ -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. */ diff --git a/plugins/sudoers/auth/sudo_auth.h b/plugins/sudoers/auth/sudo_auth.h index e2e48b404..1e12f8607 100644 --- a/plugins/sudoers/auth/sudo_auth.h +++ b/plugins/sudoers/auth/sudo_auth.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2005, 2007-2012 Todd C. Miller + * Copyright (c) 1999-2005, 2007-2015 Todd C. Miller * * 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 */ diff --git a/plugins/sudoers/check.c b/plugins/sudoers/check.c index f29b103e3..6dbddabd1 100644 --- a/plugins/sudoers/check.c +++ b/plugins/sudoers/check.c @@ -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); } diff --git a/plugins/sudoers/sudo_nss.c b/plugins/sudoers/sudo_nss.c index 4f7f27aec..77e095f42 100644 --- a/plugins/sudoers/sudo_nss.c +++ b/plugins/sudoers/sudo_nss.c @@ -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)); } diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 3100cd3f2..c76b9f489 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -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); diff --git a/src/conversation.c b/src/conversation.c index cb752b883..df5d8f0ac 100644 --- a/src/conversation.c +++ b/src/conversation.c @@ -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, ...) { diff --git a/src/sudo.c b/src/sudo.c index bfda114e1..060c4fba4 100644 --- a/src/sudo.c +++ b/src/sudo.c @@ -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: diff --git a/src/sudo.h b/src/sudo.h index 4536845c6..c1692d7be 100644 --- a/src/sudo.h +++ b/src/sudo.h @@ -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]); diff --git a/src/sudo_plugin_int.h b/src/sudo_plugin_int.h index ea2199826..3bc627330 100644 --- a/src/sudo_plugin_int.h +++ b/src/sudo_plugin_int.h @@ -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, ...); diff --git a/src/tgetpass.c b/src/tgetpass.c index 4786996ab..07be9ea98 100644 --- a/src/tgetpass.c +++ b/src/tgetpass.c @@ -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; } -- 2.40.0