Gnus development mailing list
 help / color / mirror / Atom feed
From: Jochen Hein <jochen@jochen.org>
To: Lars Ingebrigtsen <larsi@gnus.org>
Cc: Andreas Schwab <schwab@linux-m68k.org>,
	ding@gnus.org, Florian Weimer <fw@deneb.enyo.de>
Subject: [PATCH] GSSAPI authentication for nnimap
Date: Thu, 11 Feb 2016 20:51:15 +0100	[thread overview]
Message-ID: <834mdfdo0c.fsf_-_@echidna.jochen.org> (raw)
In-Reply-To: <87egcl795w.fsf@gnus.org> (Lars Ingebrigtsen's message of "Wed, 10 Feb 2016 10:31:39 +1100")


The following patches add GSSAPI support to nnimap.  I'll comment what I
did and why above each patch.  I'm currently cloning the emacs
repository and I hope to forward port the patches and add/adapt the
documentation accordingly.  This post is to gather feedback concerning
the design and the lisp code.  Do we need ChangeLog patches as well to
apply the patches to current emacs?  Right now I've not worked on
updates to the gnus manual.

The first patch is against gssapi.el from Ma Gnus v0.15, the latest gnus
release.  I've removed the options "--authentication-id" from gsasl and
"-u" from imtest invocations.  If somebody needs these, we could add the
user parameter back to open-gssapi-stream as an optional parameter.
That way open-network-stream could still call open-gssapi-stream without
changes, other users can pass a username.  I'm not sure if the username
is really neded - my usecase works fine without.

If we don't want to add an optional parameter or need to pass the
username from nnimap.el to network-stream.el and finally to gssapi.el,
we could add a property like :gssapi-user to the call to
open-network-stream and pass that to open-gssapi-stream.

The second change is removing the call to erase buffer.  That way the
function open-network-stream-gssapi in network-stream.el can fetch the
greeting and capabilities string from the buffer.

I currently know of one difference between gsasl and imtest: connections
with gsasl use TLS, imtest doesn't.  If we want that, we can add '-t ""'
to the imtest call according to the imtest manpage:

       -t keyfile
                     Enable TLS.  keyfile contains the TLS public and
                     private keys.  Specify "" to negotiate a TLS
                     encryption layer but not use TLS authentication.

Another option could be to handle STARTTLS in
network-stream-open-gssapi.  For my usecase I'll use gsasl, so I've not
added code for that.

Caveat: gsasl in Debian Jessie doesn't handle GSSAPI, so you need to
compile it yourself and make sure gssapi/krb5 is enabled:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=768352
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=776847

Both gsasl and imtest give no useful error message when the user doesn't
have a ticket or it is expired.  I've also not tried to handle that case
in my patches.  This may need further work.

diff --git a/lisp/gssapi.el b/lisp/gssapi.el
index 1f72805..08b2ec3 100644
--- a/lisp/gssapi.el
+++ b/lisp/gssapi.el
@@ -29,9 +29,8 @@
 
 (defcustom gssapi-program (list
 			   (concat "gsasl %s %p "
-				   "--mechanism GSSAPI "
-				   "--authentication-id %l")
-			   "imtest -m gssapi -u %l -p %p %s")
+				   "--mechanism GSSAPI ")
+			   "imtest -m gssapi -p %p %s")
   "List of strings containing commands for GSSAPI (krb5) authentication.
 %s is replaced with server hostname, %p with port to connect to,
 and %l with the user name.  The program should accept commands on
@@ -41,7 +40,7 @@ tried until a successful connection is made."
   :group 'network
   :type '(repeat string))
 
-(defun open-gssapi-stream (name buffer server port user)
+(defun open-gssapi-stream (name buffer server port)
   (let ((cmds gssapi-program)
 	cmd done)
     (with-current-buffer buffer
@@ -57,8 +56,7 @@ tried until a successful connection is made."
 			  cmd
 			  (format-spec-make
 			   ?s server
-			   ?p (number-to-string port)
-			   ?l user))))
+			   ?p (number-to-string port)))))
 	       response)
 	  (when process
 	    (while (and (memq (process-status process) '(open run))
@@ -92,7 +90,6 @@ tried until a successful connection is made."
 				  (setq response (match-string 1)))))
 	      (accept-process-output process 1)
 	      (sit-for 1))
-	    (erase-buffer)
 	    (message "GSSAPI connection: %s" (or response "failed"))
 	    (if (and response (let ((case-fold-search nil))
 				(not (string-match "failed" response))))


The next patch is against network-stream.el from Emacs 24.4.1.
The first part adds 'gssapi as a valid stream type and calls
network-stream-open-gssapi.  The second part simply defines that
function, based on the other open-functions in network-stream.el.  No
special handling, no STARTTLS.  I've not checked the value of
capabilities that is returned, but further procession in nnimap.el
worked fine.

Most likely this patch needs forward porting to current emacs.

--- network-stream.el.orig	2016-02-11 17:26:06.000000000 +0100
+++ network-stream.el	2016-02-11 18:31:02.000000000 +0100
@@ -44,6 +44,7 @@
 
 (require 'tls)
 (require 'starttls)
+(require 'gssapi)
 (require 'auth-source)
 
 (autoload 'gnutls-negotiate "gnutls")
@@ -85,6 +86,7 @@
   `tls'      -- A TLS connection.
   `ssl'      -- Equivalent to `tls'.
   `shell'    -- A shell connection.
+  `gssapi'   -- a GSSAPI connection.
 
 :return-list specifies this function's return value.
   If omitted or nil, return a process object.  A non-nil means to
@@ -156,6 +158,7 @@
 			'network-stream-open-starttls)
 		       ((memq type '(tls ssl)) 'network-stream-open-tls)
 		       ((eq type 'shell) 'network-stream-open-shell)
+		       ((eq type 'gssapi) 'network-stream-open-gssapi)
 		       (t (error "Invalid connection type %s" type))))
 	    result)
 	(unwind-protect
@@ -172,6 +175,24 @@
 		  :error        (nth 4 result))
 	  (car result))))))
 
+(defun network-stream-open-gssapi (name buffer host service parameters)
+  (let* ((start (with-current-buffer buffer (point)))
+	 (capability-command  (plist-get parameters :capability-command))
+	 (eoc                 (plist-get parameters :end-of-command))
+	 (eo-capa             (or (plist-get parameters :end-of-capability)
+				  eoc))
+	 (stream (open-gssapi-stream name buffer host service))
+         (greeting (network-stream-get-response stream start eoc))
+         (capabilities (when capability-command
+			 (network-stream-command stream
+					       capability-command
+					       (or eo-capa eoc)))))
+	 ;; Return (STREAM GREETING CAPABILITIES RESULTING-TYPE)
+	 (list stream
+	       greeting
+	       capabilities
+	       'gssapi)))
+
 (defun network-stream-certificate (host service parameters)
   (let ((spec (plist-get :client-certificate parameters)))
     (cond


And finally we use the facilities in nnimap.el.  The patch again is
against Ma Gnus v0.15.  We add 'gssapi as a valid stream type, provide a
message when using GSSAPI similar to other stream types.

All the heavy lifting is done in network-stream.el, so only one small
change is needed: When using GSSAPI the connection is already
authenticated, so we don't need to provide any credentials.

diff --git a/lisp/nnimap.el b/lisp/nnimap.el
index 05251ed..2eca2b4 100644
--- a/lisp/nnimap.el
+++ b/lisp/nnimap.el
@@ -65,7 +65,7 @@ it will default to `imap'.")
 (defvoo nnimap-stream 'undecided
   "How nnimap talks to the IMAP server.
 The value should be either `undecided', `ssl' or `tls',
-`network', `starttls', `plain', or `shell'.
+`network', `starttls', `plain', `gssapi', or `shell'.
 
 If the value is `undecided', nnimap tries `ssl' first, then falls
 back on `network'.")
@@ -408,6 +408,10 @@ textual parts.")
 	      (nnheader-message 7 "Opening connection to %s via shell..."
 				nnimap-address)
 	      '("imap"))
+	     ((eq nnimap-stream 'gssapi)
+	      (nnheader-message 7 "Opening connection to %s via GSSAPI..."
+				nnimap-address)
+	      '(143))
 	     ((memq nnimap-stream '(ssl tls))
 	      (nnheader-message 7 "Opening connection to %s via tls..."
 				nnimap-address)
@@ -463,7 +467,9 @@ textual parts.")
 	    (setf (nnimap-capabilities nnimap-object)
 		  (mapcar #'upcase
 			  (split-string capabilities)))
-	    (unless (gnus-string-match-p "[*.] PREAUTH" greeting)
+	    (unless (or
+			(eq nnimap-stream 'gssapi)
+			(gnus-string-match-p "[*.] PREAUTH" greeting))
 	      (if (not (setq credentials
 			     (if (eq nnimap-authenticator 'anonymous)
 				 (list "anonymous"

Any comments?

Jochen

-- 
The only problem with troubleshooting is that the trouble shoots back.



  parent reply	other threads:[~2016-02-11 19:51 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-29 14:35 gssapi " Florian Weimer
2016-02-06  6:40 ` Lars Ingebrigtsen
2016-02-07 17:16   ` Jochen Hein
2016-02-08  5:23     ` Lars Ingebrigtsen
2016-02-08  9:51       ` Jochen Hein
2016-02-08 20:59       ` Jochen Hein
2016-02-08 21:51         ` Andreas Schwab
2016-02-08 23:21           ` Jochen Hein
2016-02-08 23:47             ` Andreas Schwab
2016-02-09  6:22               ` Jochen Hein
2016-02-09 20:05                 ` Jochen Hein
2016-02-09 23:31                   ` Lars Ingebrigtsen
2016-02-10  4:16                     ` Jochen Hein
2016-02-10  4:23                       ` Lars Ingebrigtsen
2016-02-10  4:30                       ` Lars Ingebrigtsen
2016-02-10  4:42                         ` Jochen Hein
2016-02-10  4:50                           ` Lars Ingebrigtsen
2016-02-10 21:37                     ` Jochen Hein
2016-02-11 19:51                     ` Jochen Hein [this message]
2016-02-13  6:50                       ` [PATCH] GSSAPI " Lars Ingebrigtsen
2016-02-13 10:30                         ` Jochen Hein
2016-02-14  2:25                           ` Lars Ingebrigtsen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=834mdfdo0c.fsf_-_@echidna.jochen.org \
    --to=jochen@jochen.org \
    --cc=ding@gnus.org \
    --cc=fw@deneb.enyo.de \
    --cc=larsi@gnus.org \
    --cc=schwab@linux-m68k.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).