emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 3df7d06: Added `comint-password-function' hook


From: Michael Mauger
Subject: master 3df7d06: Added `comint-password-function' hook
Date: Mon, 23 Dec 2019 00:06:16 -0500 (EST)

branch: master
commit 3df7d06d4187d402e4df1177461862af638d96de
Author: Michael R. Mauger <address@hidden>
Commit: Michael R. Mauger <address@hidden>

    Added `comint-password-function' hook
    
    * etc/NEWS:
    * lisp/comint.el (comint-password-function): New variable.
      (comint-send-invisible): Use it.
    * test/lisp/comint-tests.el (comint-test-no-password-function,
      comint-test-password-function-with-value,
      comint-test-password-function-with-nil): Test new variable.
---
 etc/NEWS                  | 13 +++++++++
 lisp/comint.el            | 16 +++++++++--
 test/lisp/comint-tests.el | 68 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 2028839..2b0622e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1131,6 +1131,19 @@ end.
 *** 'comint-run' can now accept a list of switches to pass to the program.
 'C-u M-x comint-run' will prompt for the switches interactively.
 
+*** Abnormal hook `comint-password-function' has been added.
+This hook permits a derived mode to supply a password for the
+underlying command interpreter without prompting the user.  For
+example, in sql-mode, the password for connecting to the database may
+be stored in the connection wallet and may be passed on the command
+line to start the SQL interpreter.  This is a potential security flaw
+that could expose user's database passwords on the command line
+through the use of a process list (Bug#8427).  With this hook, it is
+possible to not pass the password on the command line and wait for the
+program to prompt for the password.  When it does so, the password cam
+be supplied to the SQL interpreter without involving the user just as
+if it had been supplied on the command line.
+
 ** SQL
 
 *** SQL Indent Minor Mode
diff --git a/lisp/comint.el b/lisp/comint.el
index 4bb4367..c06a63f 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -2356,6 +2356,13 @@ a buffer local variable."
 ;; saved -- typically passwords to ftp, telnet, or somesuch.
 ;; Just enter m-x comint-send-invisible and type in your line.
 
+(defvar comint-password-function nil
+  "Abnormal hook run when prompted for a password.
+This function gets one argument, a string containing the prompt.
+It may return a string containing the password, or nil if normal
+password prompting should occur.")
+(make-variable-buffer-local 'comint-password-function)
+
 (defun comint-send-invisible (&optional prompt)
   "Read a string without echoing.
 Then send it to the process running in the current buffer.
@@ -2370,8 +2377,13 @@ Security bug: your string can still be temporarily 
recovered with
           (format "(In buffer %s) "
                   (current-buffer)))))
     (if proc
-       (let ((str (read-passwd (concat prefix
-                                       (or prompt "Non-echoed text: ")))))
+       (let ((prefix-prompt (concat prefix
+                                    (or prompt "Non-echoed text: ")))
+             str)
+         (when comint-password-function
+           (setq str (funcall comint-password-function prefix-prompt)))
+         (unless str
+           (setq str (read-passwd prefix-prompt)))
          (if (stringp str)
              (progn
                (comint-snapshot-last-prompt)
diff --git a/test/lisp/comint-tests.el b/test/lisp/comint-tests.el
index 213a5c7..c041345 100644
--- a/test/lisp/comint-tests.el
+++ b/test/lisp/comint-tests.el
@@ -52,6 +52,74 @@
   (dolist (str comint-testsuite-password-strings)
     (should (string-match comint-password-prompt-regexp str))))
 
+(ert-deftest comint-test-no-password-function ()
+  "Test that `comint-password-function' not being set does not
+alter normal password flow."
+  (cl-letf
+      (((symbol-function 'read-passwd)
+        (lambda (_prompt &optional _confirm _default)
+          "PaSsWoRd123")))
+    (let ((cat (executable-find "cat")))
+      (when cat
+        (with-temp-buffer
+          (make-comint-in-buffer "test-comint-password" (current-buffer) cat)
+          (let ((proc (get-buffer-process (current-buffer))))
+            (comint-send-string proc "Password: ")
+            (accept-process-output proc 0 1 t)
+            (comint-send-eof)
+            (accept-process-output proc 0 1 t)
+            (should (string-equal (buffer-substring-no-properties (point-min) 
(point-max))
+                                  "Password: PaSsWoRd123\n"))
+            (when (process-live-p proc)
+              (kill-process proc))
+            (accept-process-output proc 0 1 t)))))))
+
+(ert-deftest comint-test-password-function-with-value ()
+  "Test that `comint-password-function' alters normal password
+flow.  Hook function returns alternative password."
+  (cl-letf
+      (((symbol-function 'read-passwd)
+        (lambda (_prompt &optional _confirm _default)
+          "PaSsWoRd123")))
+    (let ((cat (executable-find "cat"))
+          (comint-password-function (lambda (_prompt) "MaGiC-PaSsWoRd789")))
+      (when cat
+        (with-temp-buffer
+          (make-comint-in-buffer "test-comint-password" (current-buffer) cat)
+          (let ((proc (get-buffer-process (current-buffer))))
+            (comint-send-string proc "Password: ")
+            (accept-process-output proc 0 1 t)
+            (comint-send-eof)
+            (accept-process-output proc 0 1 t)
+            (should (string-equal (buffer-substring-no-properties (point-min) 
(point-max))
+                                  "Password: MaGiC-PaSsWoRd789\n"))
+            (when (process-live-p proc)
+              (kill-process proc))
+            (accept-process-output proc 0 1 t)))))))
+
+(ert-deftest comint-test-password-function-with-nil ()
+  "Test that `comint-password-function' does not alter the normal
+password flow if it returns a nil value."
+  (cl-letf
+      (((symbol-function 'read-passwd)
+        (lambda (_prompt &optional _confirm _default)
+          "PaSsWoRd456")))
+    (let ((cat (executable-find "cat"))
+          (comint-password-function (lambda (_prompt) nil)))
+      (when cat
+        (with-temp-buffer
+          (make-comint-in-buffer "test-comint-password" (current-buffer) cat)
+          (let ((proc (get-buffer-process (current-buffer))))
+            (comint-send-string proc "Password: ")
+            (accept-process-output proc 0 1 t)
+            (comint-send-eof)
+            (accept-process-output proc 0 1 t)
+            (should (string-equal (buffer-substring-no-properties (point-min) 
(point-max))
+                                  "Password: PaSsWoRd456\n"))
+            (when (process-live-p proc)
+              (kill-process proc))
+            (accept-process-output proc 0 1 t)))))))
+
 ;; Local Variables:
 ;; no-byte-compile: t
 ;; End:



reply via email to

[Prev in Thread] Current Thread [Next in Thread]