/*
- * Copyright (c) 1996, 1998-2005, 2007-2016
+ * Copyright (c) 1996, 1998-2005, 2007-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
#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
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.
*/
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);
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;
if (write(output, "\n", 1) == -1)
goto restore;
}
+ tgetpass_display_error(errval);
restore:
/* Restore old signal handlers. */
for (i = 0; i < NSIG; i++) {
if (signo[i]) {
switch (i) {
+ case SIGALRM:
+ break;
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
{
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)
/* 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);
extern int sudo_term_eof, 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;
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 */
}
}
}
- 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