From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Ted Zlatanov Newsgroups: gmane.emacs.devel Subject: netrc field encryption in auth-source (was: Opportunistic STARTTLS in smtpmail.el) Date: Fri, 10 Jun 2011 11:05:57 -0500 Organization: =?utf-8?B?0KLQtdC+0LTQvtGAINCX0LvQsNGC0LDQvdC+0LI=?= @ Cienfuegos Message-ID: <87lix9eknu.fsf_-_@lifelogs.com> References: <8762ptue8r.fsf@lifelogs.com> <87k4e8ucw3.fsf@lifelogs.com> <87liyofwxp.fsf@lifelogs.com> <874o5cfui5.fsf@lifelogs.com> <87liyndz5l.fsf@lifelogs.com> <8739jogwf9.fsf@lifelogs.com> Reply-To: emacs-devel@gnu.org NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: dough.gmane.org 1307722323 29189 80.91.229.12 (10 Jun 2011 16:12:03 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Fri, 10 Jun 2011 16:12:03 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Jun 10 18:11:59 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([140.186.70.17]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1QV4JS-0007uo-3B for ged-emacs-devel@m.gmane.org; Fri, 10 Jun 2011 18:11:58 +0200 Original-Received: from localhost ([::1]:59748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QV4JQ-0007UK-TO for ged-emacs-devel@m.gmane.org; Fri, 10 Jun 2011 12:11:57 -0400 Original-Received: from eggs.gnu.org ([140.186.70.92]:35931) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QV4Dw-0006CH-7Z for emacs-devel@gnu.org; Fri, 10 Jun 2011 12:06:20 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QV4Dr-0008HD-Dt for emacs-devel@gnu.org; Fri, 10 Jun 2011 12:06:15 -0400 Original-Received: from lo.gmane.org ([80.91.229.12]:59440) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QV4Dq-0008Gp-Nk for emacs-devel@gnu.org; Fri, 10 Jun 2011 12:06:11 -0400 Original-Received: from list by lo.gmane.org with local (Exim 4.69) (envelope-from ) id 1QV4Do-0005CK-AB for emacs-devel@gnu.org; Fri, 10 Jun 2011 18:06:08 +0200 Original-Received: from 38.98.147.130 ([38.98.147.130]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 10 Jun 2011 18:06:08 +0200 Original-Received: from tzz by 38.98.147.130 with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Fri, 10 Jun 2011 18:06:08 +0200 X-Injected-Via-Gmane: http://gmane.org/ Mail-Followup-To: emacs-devel@gnu.org Original-Lines: 162 Original-X-Complaints-To: usenet@dough.gmane.org X-Gmane-NNTP-Posting-Host: 38.98.147.130 X-Face: bd.DQ~'29fIs`T_%O%C\g%6jW)yi[zuz6; d4V0`@y-~$#3P_Ng{@m+e4o<4P'#(_GJQ%TT= D}[Ep*b!\e,fBZ'j_+#"Ps?s2!4H2-Y"sx" Mail-Copies-To: never User-Agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.50 (gnu/linux) Cancel-Lock: sha1:6fAoM4wsQVycc31Z1ut0MgH3NCI= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 3) X-Received-From: 80.91.229.12 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:140341 Archived-At: --=-=-= Content-Type: text/plain On Thu, 09 Jun 2011 20:02:02 +0200 Lars Magne Ingebrigtsen wrote: LMI> I'll do my best to implement the new smtpmail.el stuff on Wednesday, LMI> which looks like it's going to be free. Is there any possibility of LMI> getting the gpg: tokens done before that? :-) See the attached patch. I really hope the nasty code in there will inspire you or Daiki Ueno to tell me how to do it better. It depends on the EPA being active and tries to load it opportunistically. It also depends on symmetric encryption to be enabled. The GPG token decoder is activated if the secret matches "gpg:base64data=="; otherwise the secret lambda just returns the secret. So the token decoder does the following, given a filename and the decoded GPG token data: 1) make a .gpg temp stashfile associated with the original netrc filename 2) set the symmetric passphrase for that stashfile to something we `password-read' from the user, again associating the password with the original netrc filename. This is done with a nasty dynamic scope override of `epa-file-passphrase-alist'. 3) write the decoded GPG token into the stashfile outside of EPA 4) read the decrypted secret from the stashfile using EPA and set the secret lambda to return it from then on 5) clear out the token decoder lambda so there's no chance it will get called again Test it: put this in a netrc file machine supertest password gpg:jA0EAwMCdmeQLC3gFEpgyR3UxXKPoS5Yzzjl4+v/iaGPAVzwrIGOYVC+XCKcnA== and then do (let ((auth-sources '("your-netrc-file"))) (auth-source-forget-all-cached) (funcall (plist-get (nth 0 (auth-source-search :host "supertest")) :secret))) Let me know what you think. Ted --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=auth-source-gpg-tokens.patch diff --git a/lisp/auth-source.el b/lisp/auth-source.el index ce483e4..18eeb35 100644 --- a/lisp/auth-source.el +++ b/lisp/auth-source.el @@ -908,7 +908,7 @@ Note that the MAX parameter is used so we can exit the parse early." (null require) ;; every element of require is in the normalized list (let ((normalized (nth 0 (auth-source-netrc-normalize - (list alist))))) + (list alist) file)))) (loop for req in require always (plist-get normalized req))))) (decf max) @@ -944,7 +944,16 @@ Note that the MAX parameter is used so we can exit the parse early." (nreverse result)))))) -(defun auth-source-netrc-normalize (alist) +(defmacro with-auth-source-epa-overrides (&rest body) + `(let ((file-name-handler-alist + ',(remove epa-file-handler file-name-handler-alist)) + (find-file-hook + ',(remove 'epa-file-find-file-hook find-file-hook)) + (auto-mode-alist + ',(remove epa-file-auto-mode-alist-entry auto-mode-alist))) + ,@body)) + +(defun auth-source-netrc-normalize (alist filename) (mapcar (lambda (entry) (let (ret item) (while (setq item (pop entry)) @@ -960,13 +969,59 @@ Note that the MAX parameter is used so we can exit the parse early." ;; send back the secret in a function (lexical binding) (when (equal k "secret") - (setq v (lexical-let ((v v)) - (lambda () v)))) - + (setq v (lexical-let ((v v) + (filename filename) + (base (file-name-nondirectory + filename)) + (token-decoder nil) + (gpgdata nil) + (stash nil)) + (setq stash (concat base ".gpg")) + (when (string-match "gpg:\\(.+==\\)" v) + (require 'epa nil t) + (unless (featurep 'epa) + (error "EPA could not be loaded.")) + (setq gpgdata (base64-decode-string + (match-string 1 v))) + ;; it's a GPG token + (setq token-decoder + (lambda (gpgdata) +;;; FIXME: this relies on .gpg files being handled by EPA/EPG + (let* ((passkey (format "gpg:-%s" base)) + ;; temporarily disable EPA + (stashfile + (with-auth-source-epa-overrides + (make-temp-file "gpg-token" nil + stash))) + (epa-file-passphrase-alist + `((,stashfile + . ,(password-read + (format + "token pass for %s? " + filename) + passkey))))) + ;; temporarily disable EPA + (with-auth-source-epa-overrides + (write-region gpgdata + nil + stashfile)) + (setq + v + (with-temp-buffer + (insert-file-contents stashfile) + (buffer-substring-no-properties + (point-min) + (point-max)))) + ;; clear out the decoder at end + (setq token-decoder nil + gpgdata nil))))) + (lambda () + (when token-decoder + (funcall token-decoder gpgdata)) + v)))) (setq ret (plist-put ret (intern (concat ":" k)) - v)) - )) + v)))) ret)) alist)) @@ -992,7 +1047,8 @@ See `auth-source-search' for details on SPEC." :file (oref backend source) :host (or host t) :user (or user t) - :port (or port t))))) + :port (or port t)) + (oref backend source)))) ;; if we need to create an entry AND none were found to match (when (and create --=-=-=--