aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaiki Ueno2015-08-18 11:55:26 +0900
committerDaiki Ueno2015-08-18 11:55:26 +0900
commite086e55a664ec27fbca7b3231c4b32cb78a89337 (patch)
tree09a3caab25e4a6c8eb9bc9aa93fa00112f799807
parent3a23c477d90ce7401c24de8610be7d1340cd8ee3 (diff)
downloademacs-e086e55a664ec27fbca7b3231c4b32cb78a89337.tar.gz
emacs-e086e55a664ec27fbca7b3231c4b32cb78a89337.zip
pinentry.el: Support external passphrase cache
* lisp/net/pinentry.el (pinentry-use-secrets): New user option. (pinentry--allow-external-password-cache): New local variable. (pinentry--key-info): New local variable. (secrets-enabled, secrets-search-items, secrets-get-secret): Declare. (pinentry--send-passphrase): New function, split from `pinentry--process-filter'. (pinentry--process-filter): Use secrets.el to retrieve passphrase from login keyring.
-rw-r--r--lisp/net/pinentry.el151
1 files changed, 105 insertions, 46 deletions
diff --git a/lisp/net/pinentry.el b/lisp/net/pinentry.el
index 13a15c964ab..aee86473e10 100644
--- a/lisp/net/pinentry.el
+++ b/lisp/net/pinentry.el
@@ -63,6 +63,11 @@
63 :type 'integer 63 :type 'integer
64 :group 'pinentry) 64 :group 'pinentry)
65 65
66(defcustom pinentry-use-secrets nil
67 "If non-nil, use secrets.el to store passwords in login keyring."
68 :type 'boolean
69 :group 'pinentry)
70
66(defvar pinentry--server-process nil) 71(defvar pinentry--server-process nil)
67(defvar pinentry--connection-process-list nil) 72(defvar pinentry--connection-process-list nil)
68 73
@@ -70,6 +75,10 @@
70(put 'pinentry-read-point 'permanent-local t) 75(put 'pinentry-read-point 'permanent-local t)
71(defvar pinentry--read-point nil) 76(defvar pinentry--read-point nil)
72(put 'pinentry--read-point 'permanent-local t) 77(put 'pinentry--read-point 'permanent-local t)
78(defvar pinentry--allow-external-password-cache nil)
79(put 'pinentry--allow-external-password-cache 'permanent-local t)
80(defvar pinentry--key-info nil)
81(put 'pinentry--key-info 'permanent-local t)
73 82
74(defvar pinentry--prompt-buffer nil) 83(defvar pinentry--prompt-buffer nil)
75 84
@@ -143,6 +152,10 @@ If local sockets are not supported, this is nil.")
143 (concat prompt (substring short-prompt -2)) 152 (concat prompt (substring short-prompt -2))
144 query-args))) 153 query-args)))
145 154
155(defvar secrets-enabled)
156(declare-function secrets-search-items "secrets" (collection &rest attributes))
157(declare-function secrets-get-secret "secrets" (collection item))
158
146;;;###autoload 159;;;###autoload
147(defun pinentry-start () 160(defun pinentry-start ()
148 "Start a Pinentry service. 161 "Start a Pinentry service.
@@ -277,6 +290,23 @@ Assuan protocol."
277(defun pinentry--send-error (process error) 290(defun pinentry--send-error (process error)
278 (process-send-string process (format "ERR %d %s\n" (car error) (cdr error)))) 291 (process-send-string process (format "ERR %d %s\n" (car error) (cdr error))))
279 292
293(defun pinentry--send-passphrase (process passphrase)
294 (let (escaped-passphrase encoded-passphrase)
295 (unwind-protect
296 (condition-case nil
297 (progn
298 (setq escaped-passphrase (pinentry--escape-string passphrase))
299 (setq encoded-passphrase (encode-coding-string escaped-passphrase
300 'utf-8))
301 (pinentry--send-data process encoded-passphrase)
302 (process-send-string process "OK\n"))
303 (error
304 (pinentry--send-error process pinentry--error-cancelled)))
305 (if escaped-passphrase
306 (clear-string escaped-passphrase))
307 (if encoded-passphrase
308 (clear-string encoded-passphrase)))))
309
280(defun pinentry--process-filter (process input) 310(defun pinentry--process-filter (process input)
281 (unless (buffer-live-p (process-buffer process)) 311 (unless (buffer-live-p (process-buffer process))
282 (let ((buffer (generate-new-buffer " *pinentry*"))) 312 (let ((buffer (generate-new-buffer " *pinentry*")))
@@ -286,7 +316,9 @@ Assuan protocol."
286 (set-buffer-multibyte nil)) 316 (set-buffer-multibyte nil))
287 (make-local-variable 'pinentry--read-point) 317 (make-local-variable 'pinentry--read-point)
288 (setq pinentry--read-point (point-min)) 318 (setq pinentry--read-point (point-min))
289 (make-local-variable 'pinentry--labels)))) 319 (make-local-variable 'pinentry--labels)
320 (make-local-variable 'pinentry--allow-external-password-cache)
321 (make-local-variable 'pinentry--key-info))))
290 (with-current-buffer (process-buffer process) 322 (with-current-buffer (process-buffer process)
291 (save-excursion 323 (save-excursion
292 (goto-char (point-max)) 324 (goto-char (point-max))
@@ -311,52 +343,79 @@ Assuan protocol."
311 ("NOP" 343 ("NOP"
312 (ignore-errors 344 (ignore-errors
313 (process-send-string process "OK\n"))) 345 (process-send-string process "OK\n")))
346 ("OPTION"
347 (if (and pinentry-use-secrets
348 (require 'secrets)
349 secrets-enabled
350 (equal string "allow-external-password-cache"))
351 (setq pinentry--allow-external-password-cache t))
352 (ignore-errors
353 (process-send-string process "OK\n")))
354 ("SETKEYINFO"
355 (setq pinentry--key-info string)
356 (ignore-errors
357 (process-send-string process "OK\n")))
314 ("GETPIN" 358 ("GETPIN"
315 (let ((prompt 359 (let (passphrase-sent)
316 (or (cdr (assq 'desc pinentry--labels)) 360 (when (and pinentry--allow-external-password-cache
317 (cdr (assq 'prompt pinentry--labels)) 361 pinentry--key-info)
318 "")) 362 (let ((items
319 (confirm (not (null (assq 'repeat pinentry--labels)))) 363 (secrets-search-items "login"
320 entry) 364 :keygrip pinentry--key-info)))
321 (if (setq entry (assq 'error pinentry--labels)) 365 (if items
322 (setq prompt (concat "Error: " 366 (let (passphrase)
323 (propertize 367 (unwind-protect
324 (copy-sequence (cdr entry)) 368 (progn
325 'face 'error) 369 (setq passphrase (secrets-get-secret
326 "\n" 370 "login"
327 prompt))) 371 (car items)))
328 (if (setq entry (assq 'title pinentry--labels)) 372 (ignore-errors
329 (setq prompt (format "[%s] %s" 373 (process-send-string
330 (cdr entry) prompt))) 374 process
331 (let (passphrase escaped-passphrase encoded-passphrase) 375 "S PASSWORD_FROM_CACHE\n")
332 (unwind-protect 376 (pinentry--send-passphrase
333 (condition-case nil 377 process passphrase)
334 (progn 378 (setq passphrase-sent t)))
335 (setq passphrase 379 (if passphrase
336 (pinentry--prompt prompt "Password: " 380 (clear-string passphrase)))))))
337 #'read-passwd confirm)) 381 (unless passphrase-sent
338 (setq escaped-passphrase 382 (let ((prompt
339 (pinentry--escape-string 383 (or (cdr (assq 'desc pinentry--labels))
340 passphrase)) 384 (cdr (assq 'prompt pinentry--labels))
341 (setq encoded-passphrase (encode-coding-string 385 ""))
342 escaped-passphrase 386 (confirm
343 'utf-8)) 387 (not (null (assq 'repeat pinentry--labels))))
344 (ignore-errors 388 entry)
345 (pinentry--send-data 389 (if (setq entry (assq 'error pinentry--labels))
346 process encoded-passphrase) 390 (setq prompt (concat "Error: "
347 (process-send-string process "OK\n"))) 391 (propertize
348 (error 392 (copy-sequence (cdr entry))
349 (ignore-errors 393 'face 'error)
350 (pinentry--send-error 394 "\n"
351 process 395 prompt)))
352 pinentry--error-cancelled)))) 396 (if (setq entry (assq 'title pinentry--labels))
353 (if passphrase 397 (setq prompt (format "[%s] %s"
354 (clear-string passphrase)) 398 (cdr entry) prompt)))
355 (if escaped-passphrase 399 (let (passphrase)
356 (clear-string escaped-passphrase)) 400 (unwind-protect
357 (if encoded-passphrase 401 (condition-case nil
358 (clear-string encoded-passphrase)))) 402 (progn
359 (setq pinentry--labels nil))) 403 (setq passphrase
404 (pinentry--prompt prompt "Password: "
405 #'read-passwd
406 confirm))
407 (ignore-errors
408 (pinentry--send-passphrase process
409 passphrase)
410 (process-send-string process "OK\n")))
411 (error
412 (ignore-errors
413 (pinentry--send-error
414 process
415 pinentry--error-cancelled))))
416 (if passphrase
417 (clear-string passphrase))))
418 (setq pinentry--labels nil)))))
360 ("CONFIRM" 419 ("CONFIRM"
361 (let ((prompt 420 (let ((prompt
362 (or (cdr (assq 'desc pinentry--labels)) 421 (or (cdr (assq 'desc pinentry--labels))