From 6eadaddc9924fa0e0f8af53cc4ed9df34d5e4def Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Wed, 13 Jun 2018 11:19:33 -0600 Subject: [PATCH] Add SUDO_CONV_PREFER_TTY flag for conversation function to tell sudo to try writing to /dev/tty first. Can be used in conjunction with SUDO_CONV_INFO_MSG and SUDO_CONV_ERROR_MSG. --- doc/sudo_plugin.cat | 46 +++++++++++++++++++++++++++- doc/sudo_plugin.man.in | 68 ++++++++++++++++++++++++++++++++++++++++- doc/sudo_plugin.mdoc.in | 65 ++++++++++++++++++++++++++++++++++++++- include/sudo_plugin.h | 1 + src/conversation.c | 27 +++++++++++----- 5 files changed, 196 insertions(+), 11 deletions(-) diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat index aab7b6bb7..ad1ff85d7 100644 --- a/doc/sudo_plugin.cat +++ b/doc/sudo_plugin.cat @@ -1336,6 +1336,7 @@ DDEESSCCRRIIPPTTIIOONN #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ + #define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */ int msg_type; int timeout; const char *msg; @@ -1382,6 +1383,49 @@ DDEESSCCRRIIPPTTIIOONN them when the process is resumed. Note that the functions are not actually invoked from within a signal handler. + The _m_s_g___t_y_p_e must be set to one of the following values: + + SUDO_CONV_PROMPT_ECHO_OFF + Prompt the user for input with echo disabled; this is generally + used for passwords. The reply will be stored in the _r_e_p_l_i_e_s array. + + SUDO_CONV_PROMPT_ECHO_ON + Prompt the user for input with echo enabled. The reply will be + stored in the _r_e_p_l_i_e_s array. + + SUDO_CONV_ERROR_MSG + Display an error message. The message is written to the standard + error unless the SUDO_CONV_PREFER_TTY flag is set, in which case it + is written to the user's terminal if possible. + + SUDO_CONV_INFO_MSG + Display a message. The message is written to the standard output + unless the SUDO_CONV_PREFER_TTY flag is set, in which case it is + written to the user's terminal if possible. + + SUDO_CONV_PROMPT_MASK + Prompt the user for input but echo an asterisk character for each + character read. The reply will be stored in the _r_e_p_l_i_e_s This can + be used to provide visual feedback to the user while reading + sensitive information that should not be displayed. + + In addition to the above values, the following flag bits may also be set: + + SUDO_CONV_PROMPT_ECHO_OK + Allow input to be read when echo cannot be disabled when the + message type is SUDO_CONV_PROMPT_ECHO_OFF or SUDO_CONV_PROMPT_MASK. + By default, ssuuddoo will refuse to read input if the echo cannot be + disabled for those message types. + + SUDO_CONV_PREFER_TTY + When displaying a message via SUDO_CONV_ERROR_MSG or + SUDO_CONV_INFO_MSG, try to write the message to the user's + terminal. If the terminal is unavailable, the standard error or + standard output will be used, depending upon whether The user's + terminal is always used when possible for input, this flag is only + used for output. SUDO_CONV_ERROR_MSG or SUDO_CONV_INFO_MSG was + used. + 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 @@ -1604,4 +1648,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.23 March 21, 2018 Sudo 1.8.23 +Sudo 1.8.24 June 1, 2018 Sudo 1.8.24 diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in index 06f10409c..73419b558 100644 --- a/doc/sudo_plugin.man.in +++ b/doc/sudo_plugin.man.in @@ -15,7 +15,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.TH "SUDO_PLUGIN" "5" "March 21, 2018" "Sudo @PACKAGE_VERSION@" "File Formats Manual" +.TH "SUDO_PLUGIN" "5" "June 1, 2018" "Sudo @PACKAGE_VERSION@" "File Formats Manual" .nh .if n .ad l .SH "NAME" @@ -2354,6 +2354,7 @@ struct sudo_conv_message { #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ +#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */ int msg_type; int timeout; const char *msg; @@ -2436,6 +2437,71 @@ that should not be held indefinitely while suspended and then reacquire them when the process is resumed. Note that the functions are not actually invoked from within a signal handler. .PP +The +\fImsg_type\fR +must be set to one of the following values: +.TP 6n +SUDO_CONV_PROMPT_ECHO_OFF +Prompt the user for input with echo disabled; +this is generally used for passwords. +The reply will be stored in the +\fIreplies\fR +array. +.TP 6n +SUDO_CONV_PROMPT_ECHO_ON +Prompt the user for input with echo enabled. +The reply will be stored in the +\fIreplies\fR +array. +.TP 6n +SUDO_CONV_ERROR_MSG +Display an error message. +The message is written to the standard error unless the +\fRSUDO_CONV_PREFER_TTY\fR +flag is set, in which case it is written to the user's terminal if possible. +.TP 6n +SUDO_CONV_INFO_MSG +Display a message. +The message is written to the standard output unless the +\fRSUDO_CONV_PREFER_TTY\fR +flag is set, in which case it is written to the user's terminal if possible. +.TP 6n +SUDO_CONV_PROMPT_MASK +Prompt the user for input but echo an asterisk character for each +character read. +The reply will be stored in the +\fIreplies\fR +This can be used to provide visual feedback to the user while reading +sensitive information that should not be displayed. +.PP +In addition to the above values, the following flag bits may also be set: +.TP 6n +SUDO_CONV_PROMPT_ECHO_OK +Allow input to be read when echo cannot be disabled +when the message type is +\fRSUDO_CONV_PROMPT_ECHO_OFF\fR +or +\fRSUDO_CONV_PROMPT_MASK\fR. +By default, +\fBsudo\fR +will refuse to read input if the echo cannot be disabled for those +message types. +.TP 6n +SUDO_CONV_PREFER_TTY +When displaying a message via +\fRSUDO_CONV_ERROR_MSG\fR +or +\fRSUDO_CONV_INFO_MSG\fR, +try to write the message to the user's terminal. +If the terminal is unavailable, the standard error or standard output +will be used, depending upon whether +The user's terminal is always used when possible for input, +this flag is only used for output. +\fRSUDO_CONV_ERROR_MSG\fR +or +\fRSUDO_CONV_INFO_MSG\fR +was used. +.PP The plugin is responsible for freeing the reply buffer located in each \fRstruct sudo_conv_reply\fR, if it is not diff --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in index d38bbd092..5150e23c1 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 March 21, 2018 +.Dd June 1, 2018 .Dt SUDO_PLUGIN @mansectform@ .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -2048,6 +2048,7 @@ struct sudo_conv_message { #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ +#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */ int msg_type; int timeout; const char *msg; @@ -2126,6 +2127,68 @@ that should not be held indefinitely while suspended and then reacquire them when the process is resumed. Note that the functions are not actually invoked from within a signal handler. .Pp +The +.Em msg_type +must be set to one of the following values: +.Bl -tag -width 4n +.It SUDO_CONV_PROMPT_ECHO_OFF +Prompt the user for input with echo disabled; +this is generally used for passwords. +The reply will be stored in the +.Em replies +array. +.It SUDO_CONV_PROMPT_ECHO_ON +Prompt the user for input with echo enabled. +The reply will be stored in the +.Em replies +array. +.It SUDO_CONV_ERROR_MSG +Display an error message. +The message is written to the standard error unless the +.Dv SUDO_CONV_PREFER_TTY +flag is set, in which case it is written to the user's terminal if possible. +.It SUDO_CONV_INFO_MSG +Display a message. +The message is written to the standard output unless the +.Dv SUDO_CONV_PREFER_TTY +flag is set, in which case it is written to the user's terminal if possible. +.It SUDO_CONV_PROMPT_MASK +Prompt the user for input but echo an asterisk character for each +character read. +The reply will be stored in the +.Em replies +This can be used to provide visual feedback to the user while reading +sensitive information that should not be displayed. +.El +.Pp +In addition to the above values, the following flag bits may also be set: +.Bl -tag -width 4n +.It SUDO_CONV_PROMPT_ECHO_OK +Allow input to be read when echo cannot be disabled +when the message type is +.Dv SUDO_CONV_PROMPT_ECHO_OFF +or +.Dv SUDO_CONV_PROMPT_MASK . +By default, +.Nm sudo +will refuse to read input if the echo cannot be disabled for those +message types. +.It SUDO_CONV_PREFER_TTY +When displaying a message via +.Dv SUDO_CONV_ERROR_MSG +or +.Dv SUDO_CONV_INFO_MSG , +try to write the message to the user's terminal. +If the terminal is unavailable, the standard error or standard output +will be used, depending upon whether +The user's terminal is always used when possible for input, +this flag is only used for output. +.Dv SUDO_CONV_ERROR_MSG +or +.Dv SUDO_CONV_INFO_MSG +was used. +.El +.Pp The plugin is responsible for freeing the reply buffer located in each .Li struct sudo_conv_reply , if it is not diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h index efe82df66..bd22076ea 100644 --- a/include/sudo_plugin.h +++ b/include/sudo_plugin.h @@ -41,6 +41,7 @@ struct sudo_conv_message { #define SUDO_CONV_INFO_MSG 0x0004 /* informational message */ #define SUDO_CONV_PROMPT_MASK 0x0005 /* mask user input */ #define SUDO_CONV_PROMPT_ECHO_OK 0x1000 /* flag: allow echo if no tty */ +#define SUDO_CONV_PREFER_TTY 0x2000 /* flag: use tty if possible */ int msg_type; int timeout; const char *msg; diff --git a/src/conversation.c b/src/conversation.c index 7c7b3c3ad..a7b5091bf 100644 --- a/src/conversation.c +++ b/src/conversation.c @@ -29,8 +29,9 @@ #ifdef HAVE_STRINGS_H # include #endif /* HAVE_STRINGS_H */ -#include #include +#include +#include #include "sudo.h" #include "sudo_plugin.h" @@ -46,7 +47,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], struct sudo_conv_reply replies[], struct sudo_conv_callback *callback) { char *pass; - int n; + int fd, n; const int conv_debug_instance = sudo_debug_get_active_instance(); sudo_debug_set_active_instance(sudo_debug_instance); @@ -54,6 +55,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], for (n = 0; n < num_msgs; n++) { const struct sudo_conv_message *msg = &msgs[n]; int flags = tgetpass_flags; + FILE *fp = stdout; switch (msg->msg_type & 0xff) { case SUDO_CONV_PROMPT_ECHO_ON: @@ -77,13 +79,22 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[], } memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass)); break; - case SUDO_CONV_INFO_MSG: - if (msg->msg != NULL && fputs(msg->msg, stdout) == EOF) - goto err; - break; case SUDO_CONV_ERROR_MSG: - if (msg->msg != NULL && fputs(msg->msg, stderr) == EOF) - goto err; + fp = stderr; + /* FALLTHROUGH */ + case SUDO_CONV_INFO_MSG: + if (msg->msg != NULL) { + if (ISSET(msg->msg_type, SUDO_CONV_PREFER_TTY)) { + /* Try writing to /dev/tty first. */ + if ((fd = open(_PATH_TTY, O_WRONLY)) != -1) { + if (write(fd, msg->msg, strlen(msg->msg)) != -1) + break; + close(fd); + } + } + if (fputs(msg->msg, fp) == EOF) + goto err; + } break; default: goto err; -- 2.40.0