9d1b3f
diff -up ./src/tgetpass.c.CVE-2019-18634 ./src/tgetpass.c
9d1b3f
--- ./src/tgetpass.c.CVE-2019-18634	2019-10-28 13:27:39.000000000 +0100
9d1b3f
+++ ./src/tgetpass.c	2020-02-05 14:08:27.516101197 +0100
9d1b3f
@@ -61,7 +61,7 @@ enum tgetpass_errval {
9d1b3f
 static volatile sig_atomic_t signo[NSIG];
9d1b3f
 
9d1b3f
 static void tgetpass_handler(int);
9d1b3f
-static char *getln(int, char *, size_t, int, enum tgetpass_errval *);
9d1b3f
+static char *getln(int, char *, size_t, bool, enum tgetpass_errval *);
9d1b3f
 static char *sudo_askpass(const char *, const char *);
9d1b3f
 
9d1b3f
 static int
9d1b3f
@@ -125,6 +125,7 @@ tgetpass(const char *prompt, int timeout
9d1b3f
     static char buf[SUDO_CONV_REPL_MAX + 1];
9d1b3f
     int i, input, output, save_errno, ttyfd;
9d1b3f
     bool need_restart, neednl = false;
9d1b3f
+    bool feedback = ISSET(flags, TGP_MASK);
9d1b3f
     enum tgetpass_errval errval;
9d1b3f
     debug_decl(tgetpass, SUDO_DEBUG_CONV)
9d1b3f
 
9d1b3f
@@ -180,7 +181,7 @@ restart:
9d1b3f
      */
9d1b3f
     if (!ISSET(flags, TGP_ECHO)) {
9d1b3f
 	for (;;) {
9d1b3f
-	    if (ISSET(flags, TGP_MASK))
9d1b3f
+	    if (feedback)
9d1b3f
 		neednl = sudo_term_cbreak(input);
9d1b3f
 	    else
9d1b3f
 		neednl = sudo_term_noecho(input);
9d1b3f
@@ -194,6 +195,9 @@ restart:
9d1b3f
 	    }
9d1b3f
 	}
9d1b3f
     }
9d1b3f
+    /* Only use feedback mode when we can disable echo. */
9d1b3f
+    if (!neednl)
9d1b3f
+	feedback = false;
9d1b3f
 
9d1b3f
     /*
9d1b3f
      * Catch signals that would otherwise cause the user to end
9d1b3f
@@ -224,7 +228,7 @@ restart:
9d1b3f
 
9d1b3f
     if (timeout > 0)
9d1b3f
 	alarm(timeout);
9d1b3f
-    pass = getln(input, buf, sizeof(buf), ISSET(flags, TGP_MASK), &errval);
9d1b3f
+    pass = getln(input, buf, sizeof(buf), feedback, &errval);
9d1b3f
     alarm(0);
9d1b3f
     save_errno = errno;
9d1b3f
 
9d1b3f
@@ -360,7 +364,7 @@ sudo_askpass(const char *askpass, const
9d1b3f
 extern int sudo_term_eof, sudo_term_erase, sudo_term_kill;
9d1b3f
 
9d1b3f
 static char *
9d1b3f
-getln(int fd, char *buf, size_t bufsiz, int feedback,
9d1b3f
+getln(int fd, char *buf, size_t bufsiz, bool feedback,
9d1b3f
     enum tgetpass_errval *errval)
9d1b3f
 {
9d1b3f
     size_t left = bufsiz;
9d1b3f
@@ -389,15 +393,15 @@ getln(int fd, char *buf, size_t bufsiz,
9d1b3f
 		while (cp > buf) {
9d1b3f
 		    if (write(fd, "\b \b", 3) == -1)
9d1b3f
 			break;
9d1b3f
-		    --cp;
9d1b3f
+		    cp--;
9d1b3f
 		}
9d1b3f
+		cp = buf;
9d1b3f
 		left = bufsiz;
9d1b3f
 		continue;
9d1b3f
 	    } else if (c == sudo_term_erase) {
9d1b3f
 		if (cp > buf) {
9d1b3f
-		    if (write(fd, "\b \b", 3) == -1)
9d1b3f
-			break;
9d1b3f
-		    --cp;
9d1b3f
+		    ignore_result(write(fd, "\b \b", 3));
9d1b3f
+		    cp--;
9d1b3f
 		    left++;
9d1b3f
 		}
9d1b3f
 		continue;