diff -up ./src/tgetpass.c.bla ./src/tgetpass.c --- ./src/tgetpass.c.bla 2018-08-18 16:10:15.000000000 +0200 +++ ./src/tgetpass.c 2020-02-05 17:15:16.216904891 +0100 @@ -44,11 +44,18 @@ #include "sudo.h" #include "sudo_plugin.h" +enum tgetpass_errval { + TGP_ERRVAL_NOERROR, + TGP_ERRVAL_TIMEOUT, + TGP_ERRVAL_NOPASSWORD, + TGP_ERRVAL_READERROR +}; + static volatile sig_atomic_t signo[NSIG]; static bool tty_present(void); static void tgetpass_handler(int); -static char *getln(int, char *, size_t, int); +static char *getln(int, char *, size_t, int, enum tgetpass_errval *); static char *sudo_askpass(const char *, const char *); static int @@ -77,6 +84,27 @@ suspend(int signo, struct sudo_conv_call debug_return_int(ret); } +static void +tgetpass_display_error(enum tgetpass_errval errval) +{ + debug_decl(tgetpass_display_error, SUDO_DEBUG_CONV) + + switch (errval) { + case TGP_ERRVAL_NOERROR: + break; + case TGP_ERRVAL_TIMEOUT: + sudo_warnx(U_("timed out reading password")); + break; + case TGP_ERRVAL_NOPASSWORD: + sudo_warnx(U_("no password was provided")); + break; + case TGP_ERRVAL_READERROR: + sudo_warn(U_("unable to read password")); + break; + } + debug_return; +} + /* * Like getpass(3) but with timeout and echo flags. */ @@ -90,6 +118,7 @@ tgetpass(const char *prompt, int timeout static const char *askpass; static char buf[SUDO_CONV_REPL_MAX + 1]; int i, input, output, save_errno, neednl = 0, need_restart; + enum tgetpass_errval errval; debug_decl(tgetpass, SUDO_DEBUG_CONV) (void) fflush(stdout); @@ -175,7 +204,7 @@ restart: if (timeout > 0) alarm(timeout); - pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK)); + pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval); alarm(0); save_errno = errno; @@ -183,6 +212,7 @@ restart: if (write(output, "\n", 1) == -1) goto restore; } + tgetpass_display_error(errval); restore: /* Restore old signal handlers. */ @@ -210,6 +240,8 @@ restore: for (i = 0; i < NSIG; i++) { if (signo[i]) { switch (i) { + case SIGALRM: + break; case SIGTSTP: case SIGTTIN: case SIGTTOU: @@ -239,6 +271,7 @@ sudo_askpass(const char *askpass, const { static char buf[SUDO_CONV_REPL_MAX + 1], *pass; struct sigaction sa, savechld; + enum tgetpass_errval errval; int pfd[2], status; pid_t child; debug_decl(sudo_askpass, SUDO_DEBUG_CONV) @@ -281,9 +314,11 @@ sudo_askpass(const char *askpass, const /* Get response from child (askpass). */ (void) close(pfd[1]); - pass = getln(pfd[0], buf, sizeof(buf), 0); + pass = getln(pfd[0], buf, sizeof(buf), 0, &errval); (void) close(pfd[0]); + tgetpass_display_error(errval); + /* Wait for child to exit. */ for (;;) { pid_t rv = waitpid(child, &status, 0); @@ -305,7 +340,8 @@ sudo_askpass(const char *askpass, const extern int sudo_term_erase, sudo_term_kill; static char * -getln(int fd, char *buf, size_t bufsiz, int feedback) +getln(int fd, char *buf, size_t bufsiz, int feedback, + enum tgetpass_errval *errval) { size_t left = bufsiz; ssize_t nr = -1; @@ -313,7 +349,10 @@ getln(int fd, char *buf, size_t bufsiz, char c = '\0'; debug_decl(getln, SUDO_DEBUG_CONV) + *errval = TGP_ERRVAL_NOERROR; + if (left == 0) { + *errval = TGP_ERRVAL_READERROR; errno = EINVAL; debug_return_str(NULL); /* sanity */ } @@ -354,14 +393,27 @@ getln(int fd, char *buf, size_t bufsiz, } } - debug_return_str_masked(nr == 1 ? buf : NULL); + if (nr != 1) { + if (nr == 0) { + *errval = TGP_ERRVAL_NOPASSWORD; + } else if (nr == -1) { + if (errno == EINTR) { + if (signo[SIGALRM] == 1) + *errval = TGP_ERRVAL_TIMEOUT; + } else { + *errval = TGP_ERRVAL_READERROR; + } + } + debug_return_str(NULL); + } + + debug_return_str_masked(buf); } static void tgetpass_handler(int s) { - if (s != SIGALRM) - signo[s] = 1; + signo[s] = 1; } static bool