dovecot-2.1: auth: GSSAPI RFC compliancy fixes.

dovecot at dovecot.org dovecot at dovecot.org
Tue Jul 17 16:20:36 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.1/rev/ced6a796f56d
changeset: 14625:ced6a796f56d
user:      Timo Sirainen <tss at iki.fi>
date:      Tue Jul 17 16:17:40 2012 +0300
description:
auth: GSSAPI RFC compliancy fixes.
Patch by Ben Morrow:

The first problem is that, because of the way the client invokes
libsasl, it sends a GSSAPI request which does not ask for mutual
authentication. This means that on the server gss_accept_sec_context
returns GSS_S_COMPLETE with a zero-length output token. Dovecot
currently sends this to the client as a zero-length continuation
response, but this is incorrect according to RFC 4752: what it ought to
do instead is proceed straight to the security layer negotiations, and
send a gss_wrap packet.

The second is that Cyrus sends an empty authz identity; that is, the
security layer negotiation packet, when gss_unwrapped, is exactly 4
bytes long. Dovecot objects to this, but in RFC 4422 this is explicitly
allowed, and means the authz identity is identical to the authn
identity.

diffstat:

 src/auth/mech-gssapi.c |  58 +++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 46 insertions(+), 12 deletions(-)

diffs (96 lines):

diff -r 56ef4e70b1a9 -r ced6a796f56d src/auth/mech-gssapi.c
--- a/src/auth/mech-gssapi.c	Tue Jul 17 15:44:36 2012 +0300
+++ b/src/auth/mech-gssapi.c	Tue Jul 17 16:17:40 2012 +0300
@@ -78,6 +78,9 @@
 static gss_OID_desc mech_gssapi_krb5_oid =
 	{ 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
 
+static int
+mech_gssapi_wrap(struct gssapi_auth_request *request, gss_buffer_desc inbuf);
+
 static void mech_gssapi_log_error(struct auth_request *request,
 				  OM_uint32 status_value, int status_type,
 				  const char *description)
@@ -214,6 +217,21 @@
 	return name;
 }
 
+static gss_name_t
+duplicate_name(struct auth_request *request, gss_name_t old)
+{
+	OM_uint32 major_status, minor_status;
+	gss_name_t new;
+
+	major_status = gss_duplicate_name(&minor_status, old, &new);
+	if (GSS_ERROR(major_status)) {
+		mech_gssapi_log_error(request, major_status, GSS_C_GSS_CODE,
+				      "gss_duplicate_name");
+		return GSS_C_NO_NAME;
+	}
+	return new;
+}
+
 static bool data_has_nuls(const void *data, unsigned int len)
 {
 	const unsigned char *c = data;
@@ -328,9 +346,15 @@
 	}
 
 	if (ret == 0) {
-		auth_request_handler_reply_continue(auth_request,
-						    output_token.value,
-						    output_token.length);
+		if (output_token.length > 0) {
+			auth_request_handler_reply_continue(auth_request,
+							    output_token.value,
+							    output_token.length);
+		} else {
+			/* If there is no output token, go straight to wrap,
+			   which is expecting an empty input token. */
+			ret = mech_gssapi_wrap(request, output_token);
+		}
 	}
 	(void)gss_release_buffer(&minor_status, &output_token);
 	return ret;
@@ -510,22 +534,32 @@
 
 	/* outbuf[0] contains bitmask for selected security layer,
 	   outbuf[1..3] contains maximum output_message size */
-	if (outbuf.length <= 4) {
+	if (outbuf.length < 4) {
 		auth_request_log_error(auth_request, "gssapi",
 				       "Invalid response length");
 		return -1;
 	}
-	name = (unsigned char *)outbuf.value + 4;
-	name_len = outbuf.length - 4;
 
-	if (data_has_nuls(name, name_len)) {
-		auth_request_log_info(auth_request, "gssapi",
-				      "authz_name has NULs");
-		return -1;
+	if (outbuf.length > 4) {
+		name = (unsigned char *)outbuf.value + 4;
+		name_len = outbuf.length - 4;
+
+		if (data_has_nuls(name, name_len)) {
+			auth_request_log_info(auth_request, "gssapi",
+					      "authz_name has NULs");
+			return -1;
+		}
+
+		login_user = p_strndup(auth_request->pool, name, name_len);
+		request->authz_name = import_name(auth_request, name, name_len);
+	} else {
+		request->authz_name = duplicate_name(auth_request,
+						     request->authn_name);
+		if (get_display_name(auth_request, request->authz_name,
+				     NULL, &login_user) < 0)
+			return -1;
 	}
 
-	login_user = p_strndup(auth_request->pool, name, name_len);
-	request->authz_name = import_name(auth_request, name, name_len);
 	if (request->authz_name == GSS_C_NO_NAME) {
 		auth_request_log_info(auth_request, "gssapi", "no authz_name");
 		return -1;


More information about the dovecot-cvs mailing list