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

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