PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/old-archive/packages/pgp-el/ancillary/passwd.el

https://github.com/emacsmirror/ohio-archive
Emacs Lisp | 336 lines | 255 code | 42 blank | 39 comment | 8 complexity | 5bc940c5b7431ff3cba5e32ac6fd21ab MD5 | raw file
  1. ;;; passwd.el --- Prompting for passwords semi-securely
  2. ;; Copyright (C) 1994 Free Software Foundation, Inc.
  3. ;; Author: Jamie Zawinski <jwz@lucid.com>
  4. ;; This file is part of GNU Emacs.
  5. ;; GNU Emacs is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation; either version 2, or (at your option)
  8. ;; any later version.
  9. ;; GNU Emacs is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs; see the file COPYING. If not, write to
  15. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ;;; Change Log:
  17. ;;
  18. ;; Sun Jun 12 04:19:30 1994 by sandy on ibm550.sissa.it
  19. ;; Added support for password histories and (provide 'passwd)
  20. ;;; Code:
  21. (provide 'passwd)
  22. (defvar passwd-echo ?.
  23. "*The character which should be echoed when typing a password,
  24. or nil, meaning echo nothing.")
  25. (defun passwd-make-keymap ()
  26. (let ((i 0)
  27. (s (make-string 1 0))
  28. map)
  29. (if (fboundp 'set-keymap-parent)
  30. (set-keymap-parent (setq map (make-keymap)) minibuffer-local-map)
  31. ;; v18/FSFmacs compatibility
  32. (setq map (copy-keymap minibuffer-local-map)))
  33. (if (fboundp 'set-keymap-name)
  34. (set-keymap-name map 'read-passwd-map))
  35. (while (< i 127)
  36. (aset s 0 i)
  37. (define-key map s 'self-insert-command)
  38. (setq i (1+ i)))
  39. map))
  40. (defvar read-passwd-map
  41. (let ((map (passwd-make-keymap)))
  42. (define-key map "\b" 'delete-backward-char)
  43. (define-key map "\C-g" 'keyboard-quit)
  44. (define-key map "\r" 'exit-minibuffer)
  45. (define-key map "\n" 'exit-minibuffer)
  46. (define-key map "\C-u" 'passwd-erase-buffer)
  47. (define-key map "\C-q" 'quoted-insert)
  48. (define-key map "\177" 'delete-backward-char)
  49. (define-key map "\e"
  50. (let ((emap (passwd-make-keymap)))
  51. (define-key emap "n" 'passwd-next-history-element)
  52. (define-key emap "p" 'passwd-previous-history-element)
  53. (define-key emap "\b" 'backward-kill-word)
  54. emap))
  55. map)
  56. "Keymap used for reading passwords in the minibuffer.
  57. The \"bindings\" in this map are not real commands; only a limited
  58. number of commands are understood. The important bindings are:
  59. \\<read-passwd-map>
  60. \\[passwd-erase-buffer] Erase all input.
  61. \\[quoted-insert] Insert the next character literally.
  62. \\[delete-backward-char] Delete the previous character.
  63. \\[exit-minibuffer] Accept what you have typed.
  64. \\[keyboard-quit] Abort the command.
  65. All other characters insert themselves (but do not echo.)")
  66. ;;; internal variables
  67. (defvar passwd-history nil)
  68. (defvar passwd-history-posn 0)
  69. (defconst passwd-emacs-flavour
  70. ;; Be careful about match data, because ange-ftp and efs may prompt for
  71. ;; passwords from filter functions.
  72. (let ((md (match-data)))
  73. (unwind-protect
  74. (cond
  75. ((string-match "Lucid" emacs-version)
  76. 'lucid)
  77. ((string-match "^19" emacs-version)
  78. 'fsf)
  79. (t 18))
  80. (store-match-data md))))
  81. ;;;###autoload
  82. (defun read-passwd (prompt &optional confirm default)
  83. "Prompts for a password in the minibuffer, and returns it as a string.
  84. If PROMPT may be a prompt string or an alist of elements
  85. '\(prompt . default\).
  86. If optional arg CONFIRM is true, then ask the user to type the password
  87. again to confirm that they typed it correctly.
  88. If optional arg DEFAULT is provided, then it is a string to insert as
  89. the default choice (it is not, of course, displayed.)
  90. If running under X, the keyboard will be grabbed (with XGrabKeyboard())
  91. to reduce the possibility that evesdropping is occuring.
  92. When reading a password, all keys self-insert, except for:
  93. \\<read-passwd-map>
  94. \\[read-passwd-erase-line] Erase the entire line.
  95. \\[quoted-insert] Insert the next character literally.
  96. \\[delete-backward-char] Delete the previous character.
  97. \\[exit-minibuffer] Accept what you have typed.
  98. \\[keyboard-quit] Abort the command.
  99. The returned value is always a newly-created string. No additional copies
  100. of the password remain after this function has returned.
  101. NOTE: unless great care is taken, the typed password will exist in plaintext
  102. form in the running image for an arbitrarily long time. Priveleged users may
  103. be able to extract it from memory. If emacs crashes, it may appear in the
  104. resultant core file.
  105. Some steps you can take to prevent the password from being copied around:
  106. - as soon as you are done with the returned string, destroy it with
  107. (fillarray string 0). The same goes for any default passwords
  108. or password histories.
  109. - do not copy the string, as with concat or substring - if you do, be
  110. sure to keep track of and destroy all copies.
  111. - do not insert the password into a buffer - if you do, be sure to
  112. overwrite the buffer text before killing it, as with the functions
  113. `passwd-erase-buffer' or `passwd-kill-buffer'. Note that deleting
  114. the text from the buffer does NOT necessarily remove the text from
  115. memory.
  116. - be careful of the undo history - if you insert the password into a
  117. buffer which has undo recording turned on, the password will be
  118. copied onto the undo list, and thus recoverable.
  119. - do not pass it as an argument to a shell command - anyone will be
  120. able to see it if they run `ps' at the right time.
  121. Note that the password will be temporarily recoverable with the `view-lossage'
  122. command. This data will not be overwritten until another hundred or so
  123. characters are typed. There's not currently a way around this."
  124. (save-excursion
  125. (let ((input (get-buffer-create " *password*"))
  126. (passwd-history-posn 0)
  127. passwd-history)
  128. (if (listp prompt)
  129. (setq passwd-history prompt
  130. default (cdr (car passwd-history))))
  131. (set-buffer input)
  132. (buffer-disable-undo input)
  133. (use-local-map read-passwd-map)
  134. (unwind-protect
  135. (progn
  136. (passwd-grab-keyboard)
  137. (read-passwd-1 input prompt nil default)
  138. (set-buffer input)
  139. (if (not confirm)
  140. (buffer-string)
  141. (let ((ok nil)
  142. passwd)
  143. (while (not ok)
  144. (set-buffer input)
  145. (setq passwd (buffer-string))
  146. (read-passwd-1 input prompt "[Retype to confirm]")
  147. (if (passwd-compare-string-to-buffer passwd input)
  148. (setq ok t)
  149. (fillarray passwd 0)
  150. (setq passwd nil)
  151. (beep)
  152. (read-passwd-1 input prompt "[Mismatch. Start over]")
  153. ))
  154. passwd)))
  155. ;; protected
  156. (passwd-ungrab-keyboard)
  157. (passwd-kill-buffer input)
  158. (if (eq passwd-emacs-flavour 18)
  159. (message "")
  160. (message nil))
  161. ))))
  162. (defun read-passwd-1 (buffer prompt &optional prompt2 default)
  163. (set-buffer buffer)
  164. (passwd-erase-buffer)
  165. (if default (insert default))
  166. (catch 'exit ; exit-minibuffer throws here
  167. (while t
  168. (set-buffer buffer)
  169. (let* ((minibuffer-completion-table nil)
  170. (cursor-in-echo-area t)
  171. (echo-keystrokes 0)
  172. (key (passwd-read-key-sequence
  173. (concat (if (listp prompt)
  174. (car (nth passwd-history-posn passwd-history))
  175. prompt)
  176. prompt2
  177. (if passwd-echo
  178. (make-string (buffer-size) passwd-echo)))))
  179. (binding (key-binding key)))
  180. (setq prompt2 nil)
  181. (set-buffer buffer) ; just in case...
  182. (if (eq passwd-emacs-flavour 'lucid)
  183. ;; XEmacs
  184. (setq last-command-event (aref key (1- (length key)))
  185. last-command-char (event-to-character last-command-event))
  186. ;; GNU Emacs compatibility
  187. (setq last-command-char (aref key (1- (length key)))))
  188. (setq this-command binding)
  189. (condition-case c
  190. (command-execute binding)
  191. (error
  192. (beep)
  193. (if (fboundp 'display-error)
  194. ;; XEmacs
  195. (display-error c t)
  196. ;; GNU Emacs
  197. (message (concat (or (get (car-safe c) 'error-message) "???")
  198. (if (cdr-safe c) ": ")
  199. (mapconcat
  200. (function (lambda (x) (format "%s" x)))
  201. (cdr-safe c) ", "))))
  202. (sit-for 2)))
  203. ))))
  204. (defun passwd-previous-history-element (n)
  205. (interactive "p")
  206. (or passwd-history
  207. (error "Password history is empty."))
  208. (let ((l (length passwd-history)))
  209. (setq passwd-history-posn
  210. (% (+ n passwd-history-posn) l))
  211. (if (< passwd-history-posn 0)
  212. (setq passwd-history-posn (+ passwd-history-posn l))))
  213. (let ((obuff (current-buffer))) ; want to move point in passwd buffer
  214. (unwind-protect
  215. (progn
  216. (set-buffer " *password*")
  217. (passwd-erase-buffer)
  218. (insert (cdr (nth passwd-history-posn passwd-history))))
  219. (set-buffer obuff))))
  220. (defun passwd-next-history-element (n)
  221. (interactive "p")
  222. (passwd-previous-history-element (- n)))
  223. (defun passwd-erase-buffer ()
  224. ;; First erase the buffer, which will simply enlarge the gap.
  225. ;; Then insert null characters until the gap is filled with them
  226. ;; to prevent the old text from being visible in core files or kmem.
  227. ;; (Actually use 3x the size of the buffer just to be safe - a longer
  228. ;; passwd might have been typed and backspaced over.)
  229. (interactive)
  230. (widen)
  231. (let ((s (* (buffer-size) 3)))
  232. (erase-buffer)
  233. (while (> s 0)
  234. (insert ?\000)
  235. (setq s (1- s)))
  236. (erase-buffer)))
  237. (defun passwd-kill-buffer (buffer)
  238. (save-excursion
  239. (set-buffer buffer)
  240. (buffer-disable-undo buffer)
  241. (passwd-erase-buffer)
  242. (set-buffer-modified-p nil))
  243. (kill-buffer buffer))
  244. (defun passwd-compare-string-to-buffer (string buffer)
  245. ;; same as (equal string (buffer-string)) but with no dangerous consing.
  246. (save-excursion
  247. (set-buffer buffer)
  248. (goto-char (point-min))
  249. (let ((L (length string))
  250. (i 0))
  251. (if (/= L (- (point-max) (point-min)))
  252. nil
  253. (while (not (eobp))
  254. (if (/= (following-char) (aref string i))
  255. (goto-char (point-max))
  256. (setq i (1+ i))
  257. (forward-char)))
  258. (= (point) (+ i (point-min)))))))
  259. (defun passwd-grab-keyboard ()
  260. (cond ((not (and (fboundp 'x-grab-keyboard) ; lemacs 19.10+
  261. (eq 'x (live-screen-p (selected-screen)))))
  262. nil)
  263. ((x-grab-keyboard)
  264. t)
  265. (t
  266. (message "Unable to grab keyboard - waiting a second...")
  267. (sleep-for 1)
  268. (cond ((x-grab-keyboard)
  269. (message "Keyboard grabbed on second try.")
  270. t)
  271. (t
  272. (beep)
  273. (message "WARNING: keyboard is insecure (unable to grab!)")
  274. (sleep-for 3)
  275. nil)))))
  276. (defun passwd-ungrab-keyboard ()
  277. (if (and (fboundp 'x-ungrab-keyboard) ; lemacs 19.10+
  278. (eq 'x (live-screen-p (selected-screen))))
  279. (x-ungrab-keyboard)))
  280. ;; v18 compatibility
  281. (or (fboundp 'buffer-disable-undo)
  282. (fset 'buffer-disable-undo 'buffer-flush-undo))
  283. ;; read-key-sequence echoes the key sequence in Emacs 18.
  284. (if (eq passwd-emacs-flavour 18)
  285. (defun passwd-read-key-sequence (prompt)
  286. (let ((inhibit-quit t)
  287. str)
  288. (while (or (null str) (keymapp (key-binding str)))
  289. (message prompt)
  290. (setq str (concat str (char-to-string (read-char)))))
  291. (setq quit-flag nil)
  292. str))
  293. (fset 'passwd-read-key-sequence 'read-key-sequence))
  294. ;;; passwd.el ends here