sbonazzo / rpms / cyrus-sasl

Forked from rpms/cyrus-sasl 2 years ago
Clone

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

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