From: Michael R. Mauger Date: Mon, 23 Dec 2019 04:56:05 +0000 (-0500) Subject: Added `comint-password-function' hook X-Git-Tag: emacs-27.0.90~306 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=3df7d06d4187d402e4df1177461862af638d96de;p=emacs.git 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. --- diff --git a/etc/NEWS b/etc/NEWS index 20288398bd3..2b0622e752f 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 4bb43670354..c06a63fbd24 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 213a5c7c9e4..c04134599f6 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: