1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
| | ;;; term-utils.el --- Common code used by term.el and comint.el -*- lexical-binding: t; -*-
;; Copyright (C) 2018 Tino Calancha
;; Author: Tino Calancha <tino.calancha@gmail.com>
;; Keywords: processes, terminals
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; code:
\f
;; Retrieve the right defvar value according with the buffer mode.
(defmacro term-utils--defvar-value (suffix)
"Build a defvar with the `major-mode' and SUFFIX, return its value.
The buffer major mode must be `term-mode' or `comint-mode'."
(declare (debug (symbolp)) (indent 0))
`(symbol-value
(intern-soft
(format "%S%S" (if (derived-mode-p 'term-mode) 'term- 'comint-)
',suffix))))
;; AIX puts the name of the person being su'd to in front of the prompt.
;; kinit prints a prompt like `Password for devnull@GNU.ORG: '.
;; ksu prints a prompt like `Kerberos password for devnull/root@GNU.ORG: '.
;; ssh-add prints a prompt like `Enter passphrase: '.
;; plink prints a prompt like `Passphrase for key "root@GNU.ORG": '.
;; Ubuntu's sudo prompts like `[sudo] password for user:'
;; Some implementations of passwd use "Password (again)" as the 2nd prompt.
;; Something called "perforce" uses "Enter password:".
;; See M-x comint-testsuite--test-comint-password-prompt-regexp.
(defcustom term-utils-password-prompt-regexp
(concat
"\\(^ *\\|"
(regexp-opt
'("Enter" "enter" "Enter same" "enter same" "Enter the" "enter the"
"Old" "old" "New" "new" "'s" "login"
"Kerberos" "CVS" "UNIX" " SMB" "LDAP" "PEM" "SUDO"
"[sudo]" "Repeat" "Bad" "Retype")
t)
" +\\)"
"\\(?:" (regexp-opt password-word-equivalents) "\\|Response\\)"
"\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?"
;; "[[:alpha:]]" used to be "for", which fails to match non-English.
"\\(?: [[:alpha:]]+ .+\\)?[\\s ]*[::៖][\\s ]*\\'")
"Regexp matching prompts for passwords in the inferior process.
This is used by `term-utils-watch-for-password-prompt'."
:version "27.1"
:type 'regexp
:group 'term-utils)
(declare-function comint-snapshot-last-prompt "comint")
(defun term-utils-send-invisible (&optional prompt)
"Read a string without echoing with PROMPT.
Then send it to the process running in the current buffer.
The string is sent using `comint-input-sender' or `term-input-sender'
depending of the buffer mode.
Security bug: your string can still be temporarily recovered with
\\[view-lossage]; `clear-this-command-keys' can fix that."
(interactive "P") ; Defeat snooping via C-x ESC ESC
(let ((proc (get-buffer-process (current-buffer)))
(prefix
(if (eq (window-buffer) (current-buffer))
""
(format "(In buffer %s) "
(current-buffer)))))
(if proc
(let ((str (read-passwd (concat prefix
(or prompt "Non-echoed text: ")))))
(if (stringp str)
(let ((input-sender-fun (term-utils--defvar-value input-sender)))
(if (derived-mode-p 'comint-mode) (comint-snapshot-last-prompt))
(funcall input-sender-fun proc str))
(message "Warning: text will be echoed")))
(error "Buffer %s has no process" (current-buffer)))))
(defalias 'send-invisible 'term-utils-send-invisible)
(defvar term-raw-map) ; Defined in term.el
(defun term-utils-term-in-line-mode-p ()
"Return non-nil if the buffer is in `term-mode' and line submode."
(and (derived-mode-p 'term-mode) (eq (current-local-map) term-raw-map)))
(defun term-utils-watch-for-password-prompt (string)
"Prompt in the minibuffer for password and send without echoing.
This function uses `send-invisible' to read and send a password to the buffer's
process if STRING contains a password prompt defined by
`term-utils-password-prompt-regexp'.
This function could be in the lists `comint-output-filter-functions'
and `term-output-filter-functions'."
;; Do nothing if buffer is in term-mode with line submode
(unless (term-utils-term-in-line-mode-p)
(when (let ((case-fold-search t))
(string-match term-utils-password-prompt-regexp string))
(when (string-match "^[ \n\r\t\v\f\b\a]+" string)
(setq string (replace-match "" t t string)))
(term-utils-send-invisible string))))
(provide 'term-utils)
;;; term-utils.el ends here
|