Blame SOURCES/cyrus-sasl-2.1.26-gss-spnego.patch

b9abc1
From 67ca66685e11acc0f69d5ff8013107d4b172e67f Mon Sep 17 00:00:00 2001
b9abc1
From: Simo Sorce <simo@redhat.com>
b9abc1
Date: Thu, 16 Feb 2017 15:25:56 -0500
b9abc1
Subject: [PATCH] Fix GSS-SPNEGO mechanism's incompatible behavior
b9abc1
b9abc1
The GSS-SPNEGO mechanism has been designed and introduced by Microsoft for use
b9abc1
by Active Directory clients. It allows to negotiate an underlying
b9abc1
Security Mechanism like Krb5 or NTLMSSP.
b9abc1
However, the implementaion in cyrus-sasl is broken and never correctly
b9abc1
interoperated with Microsoft servers or clients. This patch fixes the
b9abc1
compatibility issue which is caused by incorrectly trying to negotiate
b9abc1
SSF layers explicitly instead of using the flags negotiated by GSSAPI
b9abc1
as required by Microsoft's implementation.
b9abc1
b9abc1
Signed-off-by: Simo Sorce <simo@redhat.com>
b9abc1
---
b9abc1
 plugins/gssapi.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
b9abc1
 1 file changed, 64 insertions(+), 6 deletions(-)
b9abc1
b9abc1
diff --git a/plugins/gssapi.c b/plugins/gssapi.c
b9abc1
index bfc278d..010c236 100644
b9abc1
--- a/plugins/gssapi.c
b9abc1
+++ b/plugins/gssapi.c
b9abc1
@@ -648,10 +648,62 @@ static void gssapi_common_mech_free(void *global_context __attribute__((unused))
b9abc1
 #endif
b9abc1
 }
b9abc1
 
b9abc1
+/* The GSS-SPNEGO mechanism does not do SSF negotiation, instead it uses the
b9abc1
+ * flags negotiated by GSSAPI to determine If confidentiality or integrity are
b9abc1
+ * used. These flags are stored in text->qop transalated as layers by the
b9abc1
+ * caller */
b9abc1
+static int gssapi_spnego_ssf(context_t *text, const sasl_utils_t *utils,
b9abc1
+                             sasl_security_properties_t *props,
b9abc1
+                             sasl_out_params_t *oparams)
b9abc1
+{
b9abc1
+    OM_uint32 maj_stat = 0, min_stat = 0;
b9abc1
+    OM_uint32 max_input;
b9abc1
+
b9abc1
+    if (text->qop & LAYER_CONFIDENTIALITY) {
b9abc1
+        oparams->encode = &gssapi_privacy_encode;
b9abc1
+        oparams->decode = &gssapi_decode;
b9abc1
+        oparams->mech_ssf = K5_MAX_SSF;
b9abc1
+    } else if (text->qop & LAYER_INTEGRITY) {
b9abc1
+        oparams->encode = &gssapi_integrity_encode;
b9abc1
+        oparams->decode = &gssapi_decode;
b9abc1
+        oparams->mech_ssf = 1;
b9abc1
+    } else {
b9abc1
+        oparams->encode = NULL;
b9abc1
+        oparams->decode = NULL;
b9abc1
+        oparams->mech_ssf = 0;
b9abc1
+    }
b9abc1
+
b9abc1
+    if (oparams->mech_ssf) {
b9abc1
+        maj_stat = gss_wrap_size_limit(&min_stat,
b9abc1
+                                       text->gss_ctx,
b9abc1
+                                       1,
b9abc1
+                                       GSS_C_QOP_DEFAULT,
b9abc1
+                                       (OM_uint32)oparams->maxoutbuf,
b9abc1
+                                       &max_input);
b9abc1
+
b9abc1
+	if (max_input > oparams->maxoutbuf) {
b9abc1
+	    /* Heimdal appears to get this wrong */
b9abc1
+	    oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
b9abc1
+	} else {
b9abc1
+	    /* This code is actually correct */
b9abc1
+	    oparams->maxoutbuf = max_input;
b9abc1
+	}
b9abc1
+    }
b9abc1
+
b9abc1
+    text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
b9abc1
+
b9abc1
+    /* used by layers */
b9abc1
+    _plug_decode_init(&text->decode_context, text->utils,
b9abc1
+		      (props->maxbufsize > 0xFFFFFF) ? 0xFFFFFF :
b9abc1
+                      props->maxbufsize);
b9abc1
+
b9abc1
+    return SASL_OK;
b9abc1
+}
b9abc1
+
b9abc1
 /*****************************  Server Section  *****************************/
b9abc1
 
b9abc1
 static int 
b9abc1
-gssapi_server_mech_new(void *glob_context __attribute__((unused)), 
b9abc1
+gssapi_server_mech_new(void *glob_context,
b9abc1
 		       sasl_server_params_t *params,
b9abc1
 		       const char *challenge __attribute__((unused)), 
b9abc1
 		       unsigned challen __attribute__((unused)),
b9abc1
@@ -673,6 +725,7 @@ gssapi_server_mech_new(void *glob_context __attribute__((unused)),
b9abc1
     text->state = SASL_GSSAPI_STATE_AUTHNEG;
b9abc1
     
b9abc1
     text->http_mode = (params->flags & SASL_NEED_HTTP);
b9abc1
+    text->mech_type = (gss_OID) glob_context;
b9abc1
 
b9abc1
     *conn_context = text;
b9abc1
     
b9abc1
@@ -686,7 +739,7 @@ gssapi_server_mech_authneg(context_t *text,
b9abc1
 			   unsigned clientinlen,
b9abc1
 			   const char **serverout,
b9abc1
 			   unsigned *serveroutlen,
b9abc1
-			   sasl_out_params_t *oparams __attribute__((unused)))
b9abc1
+			   sasl_out_params_t *oparams)
b9abc1
 {
b9abc1
     gss_buffer_t input_token, output_token;
b9abc1
     gss_buffer_desc real_input_token, real_output_token;
b9abc1
@@ -965,8 +1018,9 @@ gssapi_server_mech_authneg(context_t *text,
b9abc1
 	/* HTTP doesn't do any ssf negotiation */
b9abc1
 	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
b9abc1
 	ret = SASL_OK;
b9abc1
-    }
b9abc1
-    else {
b9abc1
+    } else if (text->mech_type && text->mech_type == &gss_spnego_oid) {
b9abc1
+        ret = gssapi_spnego_ssf(text, params->utils, &params->props, oparams);
b9abc1
+    } else {
b9abc1
 	/* Switch to ssf negotiation */
b9abc1
 	text->state = SASL_GSSAPI_STATE_SSFCAP;
b9abc1
 	ret = SASL_CONTINUE;
b9abc1
@@ -1391,7 +1445,7 @@ static sasl_server_plug_t gssapi_server_plugins[] =
b9abc1
 	| SASL_FEAT_ALLOWS_PROXY
b9abc1
 	| SASL_FEAT_DONTUSE_USERPASSWD
b9abc1
 	| SASL_FEAT_SUPPORTS_HTTP,	/* features */
b9abc1
-	NULL,				/* glob_context */
b9abc1
+	&gss_spnego_oid,		/* glob_context */
b9abc1
 	&gssapi_server_mech_new,	/* mech_new */
b9abc1
 	&gssapi_server_mech_step,	/* mech_step */
b9abc1
 	&gssapi_common_mech_dispose,	/* mech_dispose */
b9abc1
@@ -1769,7 +1823,11 @@ static int gssapi_client_mech_step(void *conn_context,
b9abc1
 		text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
b9abc1
 		oparams->doneflag = 1;
b9abc1
 		return SASL_OK;
b9abc1
-	    }
b9abc1
+	    } else if (text->mech_type && text->mech_type == &gss_spnego_oid) {
b9abc1
+		oparams->doneflag = 1;
b9abc1
+                return gssapi_spnego_ssf(text, params->utils, &params->props,
b9abc1
+                                         oparams);
b9abc1
+            }
b9abc1
 
b9abc1
 	    /* Switch to ssf negotiation */
b9abc1
 	    text->state = SASL_GSSAPI_STATE_SSFCAP;
b9abc1