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.
This commit is contained in:
Michael R. Mauger 2019-12-22 23:56:05 -05:00
parent eea05713be
commit 3df7d06d41
3 changed files with 95 additions and 2 deletions

View file

@ -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

View file

@ -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)

View file

@ -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: