Subject: Re: bug#30190: 27.0.50; term run in line mode shows user passwords

From: Noam Postavsky <[email-masked]>
Date: Wed, 18 Jul 2018 07:56:44 -0400

Stefan Monnier <[email-masked]> writes:

> unconditionally call *-watch-for-password-prompt right at the place
> where you added the "run-hook" (actually, only one of the two places),

Here is a modified version of Tino's patch which uses comint.el and does
the above.  Another difference is that we call
term-watch-for-password-prompt on the decoded-substring (I believe
that's required to match localized non-ASCII prompts correctly).

I wasn't able to reproduce the problems described in #74 with any
version of the patch (maybe it's dependent on timing?), so I'm not sure
how much of a concern that is.

>From 5e8f7abce1b1dd9796e5baab57dc6215850b3416 Mon Sep 17 00:00:00 2001
From: Tino Calancha <[email-masked]>
Date: Thu, 15 Feb 2018 09:09:50 +0900
Subject: [PATCH v3] Prevent line-mode term from showing user passwords

For buffers whose mode derive from comint-mode, the user password is
read from the minibuffer and it's hidden.  A buffer in term-mode and
line submode, instead shows the passwords.  Make buffers in line
term-mode to hide passwords too (Bug#30190).

* lisp/term.el (term-send-invisible): Prefer the more robust
`read-passwd' instead of `term-read-noecho'.
(term-watch-for-password-prompt): New function.
(term-emulate-terminal): Call it each time we receive non-escape
sequence output.

Co-authored-by: Noam Postavsky <[email-masked]>
---
 lisp/term.el | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/lisp/term.el b/lisp/term.el
index b7f5b0e7f2..f7cd7dcd6a 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -347,6 +347,7 @@ term-protocol-version
 (eval-when-compile (require 'cl-lib))
 (require 'ring)
 (require 'ehelp)
+(require 'comint) ; Password regexp.
 
 (declare-function ring-empty-p "ring" (ring))
 (declare-function ring-ref "ring" (ring index))
@@ -2288,7 +2289,8 @@ term-send-invisible
 \\[view-lossage]."
   (interactive "P") ; Defeat snooping via C-x esc
   (when (not (stringp str))
-    (setq str (term-read-noecho "Non-echoed text: " t)))
+    (let ((read-hide-char ?*))
+      (setq str (read-passwd "Non-echoed text: "))))
   (when (not proc)
     (setq proc (get-buffer-process (current-buffer))))
   (if (not proc) (error "Current buffer has no process")
@@ -2297,6 +2299,17 @@ term-send-invisible
     (term-send-string proc str)
     (term-send-string proc "\n")))
 
+;; TODO: Maybe combine this with `comint-watch-for-password-prompt'.
+(defun term-watch-for-password-prompt (string)
+  "Prompt in the minibuffer for password and send without echoing.
+This function uses `term-send-invisible' to read and send a password to the buffer's
+process if STRING contains a password prompt defined by
+`comint-password-prompt-regexp'."
+  (when (term-in-line-mode)
+    (when (let ((case-fold-search t))
+	    (string-match comint-password-prompt-regexp string))
+      (term-send-invisible (read-passwd string)))))
+
 
 ;;; Low-level process communication
 
@@ -3152,6 +3165,9 @@ term-emulate-terminal
 	  (term-handle-deferred-scroll))
 
 	(set-marker (process-mark proc) (point))
+        (when (stringp decoded-substring)
+          (term-watch-for-password-prompt (prog1 decoded-substring
+                                            (setq decoded-substring nil))))
 	(when save-point
 	  (goto-char save-point)
 	  (set-marker save-point nil))
-- 
2.11.0