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, ...);
To use the c\bco\bon\bnv\bve\ber\brs\bsa\bat\bti\bio\bon\bn() 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 s\bsu\bud\bdo\bo will support. It is also useful as a maximum value
- for the m\bme\bem\bms\bse\bet\bt_\b_s\bs() 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 s\bsu\bud\bdo\bo process is
+ suspended and/or resumed during conversation input. The functions are
+ passed the signal that caused s\bsu\bud\bdo\bo to be suspended and the _\bc_\bl_\bo_\bs_\bu_\br_\be
+ 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 s\bsu\bud\bdo\bo will
+ support. It is also useful as a maximum value for the m\bme\bem\bms\bse\bet\bt_\b_s\bs()
+ function when clearing passwords filled in by the conversation function.
The p\bpr\bri\bin\bnt\btf\bf()-style function uses the same underlying mechanism as the
c\bco\bon\bnv\bve\ber\brs\bsa\bat\bti\bio\bon\bn() function but only supports SUDO_CONV_INFO_MSG and
Version 1.8 (sudo 1.8.15)
The _\bs_\bu_\bd_\bo_\be_\bd_\bi_\bt_\b__\bf_\bo_\bl_\bl_\bo_\bw entry was added to the command_info list.
+ The sudo _\bc_\bo_\bn_\bv_\be_\br_\bs_\ba_\bt_\bi_\bo_\bn 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.
+
S\bSE\bEE\bE A\bAL\bLS\bSO\bO
sudo.conf(4), sudoers(4), sudo(1m)
file distributed with s\bsu\bud\bdo\bo 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
.\" 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"
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
\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
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@),
.\" 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
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
.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
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@ ,
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);
__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))
#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))
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, ...);
/*
}
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 {
#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;
}
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;
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);
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;
}
}
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;
* 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++;
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);
}
}
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;
}
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 */
/* 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));
#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;
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;
}
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;
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);
*/
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;
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;
}
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;
}
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)
}
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;
* 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)) {
!!! 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;
}
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)
* 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;
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;
}
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;
}
}
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;
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. */
/*
- * 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
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);
#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 */
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;
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 {
" #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);
}
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));
}
/* 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);
*/
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;
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) {
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, ...)
{
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:
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:
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]);
/* 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 */
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[]);
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[]);
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, ...);
* 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;
*/
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;
}