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

5a6b4e
From 862b60c249c8a51095315062b22c0702a6500d80 Mon Sep 17 00:00:00 2001
5a6b4e
From: Simo Sorce <simo@redhat.com>
5a6b4e
Date: Tue, 11 Apr 2017 18:31:46 -0400
5a6b4e
Subject: [PATCH 1/3] Drop unused parameter from gssapi_spnego_ssf()
5a6b4e
5a6b4e
Signed-off-by: Simo Sorce <simo@redhat.com>
5a6b4e
---
5a6b4e
 plugins/gssapi.c | 7 +++----
5a6b4e
 1 file changed, 3 insertions(+), 4 deletions(-)
5a6b4e
5a6b4e
diff --git a/plugins/gssapi.c b/plugins/gssapi.c
5a6b4e
index 010c236d..3050962e 100644
5a6b4e
--- a/plugins/gssapi.c
5a6b4e
+++ b/plugins/gssapi.c
5a6b4e
@@ -652,7 +652,7 @@ static void gssapi_common_mech_free(void *global_context __attribute__((unused))
5a6b4e
  * flags negotiated by GSSAPI to determine If confidentiality or integrity are
5a6b4e
  * used. These flags are stored in text->qop transalated as layers by the
5a6b4e
  * caller */
5a6b4e
-static int gssapi_spnego_ssf(context_t *text, const sasl_utils_t *utils,
5a6b4e
+static int gssapi_spnego_ssf(context_t *text,
5a6b4e
                              sasl_security_properties_t *props,
5a6b4e
                              sasl_out_params_t *oparams)
5a6b4e
 {
5a6b4e
@@ -1019,7 +1019,7 @@ gssapi_server_mech_authneg(context_t *text,
5a6b4e
 	text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
5a6b4e
 	ret = SASL_OK;
5a6b4e
     } else if (text->mech_type && text->mech_type == &gss_spnego_oid) {
5a6b4e
-        ret = gssapi_spnego_ssf(text, params->utils, &params->props, oparams);
5a6b4e
+        ret = gssapi_spnego_ssf(text, &params->props, oparams);
5a6b4e
     } else {
5a6b4e
 	/* Switch to ssf negotiation */
5a6b4e
 	text->state = SASL_GSSAPI_STATE_SSFCAP;
5a6b4e
@@ -1825,8 +1825,7 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
 		return SASL_OK;
5a6b4e
 	    } else if (text->mech_type && text->mech_type == &gss_spnego_oid) {
5a6b4e
 		oparams->doneflag = 1;
5a6b4e
-                return gssapi_spnego_ssf(text, params->utils, &params->props,
5a6b4e
-                                         oparams);
5a6b4e
+                return gssapi_spnego_ssf(text, &params->props, oparams);
5a6b4e
             }
5a6b4e
 
5a6b4e
 	    /* Switch to ssf negotiation */
5a6b4e
5a6b4e
From 72181257d77bda09afa7d0d640d322c4472f4833 Mon Sep 17 00:00:00 2001
5a6b4e
From: Simo Sorce <simo@redhat.com>
5a6b4e
Date: Mon, 10 Apr 2017 18:35:10 -0400
5a6b4e
Subject: [PATCH 2/3] Check return error from gss_wrap_size_limit()
5a6b4e
5a6b4e
The return error of this function is ignored and potentially
5a6b4e
uninitialized values returned by this function are used.
5a6b4e
5a6b4e
Fix this by moving the function into a proper helper as it is used in an
5a6b4e
identical way in 3 different places.
5a6b4e
5a6b4e
Signed-off-by: Simo Sorce <simo@redhat.com>
5a6b4e
---
5a6b4e
 plugins/gssapi.c | 104 +++++++++++++++++++++++++++----------------------------
5a6b4e
 1 file changed, 51 insertions(+), 53 deletions(-)
5a6b4e
5a6b4e
diff --git a/plugins/gssapi.c b/plugins/gssapi.c
5a6b4e
index 3050962e..348debe0 100644
5a6b4e
--- a/plugins/gssapi.c
5a6b4e
+++ b/plugins/gssapi.c
5a6b4e
@@ -648,6 +648,32 @@ static void gssapi_common_mech_free(void *global_context __attribute__((unused))
5a6b4e
 #endif
5a6b4e
 }
5a6b4e
 
5a6b4e
+static int gssapi_wrap_sizes(context_t *text, sasl_out_params_t *oparams)
5a6b4e
+{
5a6b4e
+    OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
+    OM_uint32 max_input = 0;
5a6b4e
+
5a6b4e
+    maj_stat = gss_wrap_size_limit(&min_stat,
5a6b4e
+                                   text->gss_ctx,
5a6b4e
+                                   1,
5a6b4e
+                                   GSS_C_QOP_DEFAULT,
5a6b4e
+                                   (OM_uint32)oparams->maxoutbuf,
5a6b4e
+                                   &max_input);
5a6b4e
+   if (maj_stat != GSS_S_COMPLETE) {
5a6b4e
+       return SASL_FAIL;
5a6b4e
+   }
5a6b4e
+
5a6b4e
+    if (max_input > oparams->maxoutbuf) {
5a6b4e
+        /* Heimdal appears to get this wrong */
5a6b4e
+        oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
5a6b4e
+    } else {
5a6b4e
+        /* This code is actually correct */
5a6b4e
+        oparams->maxoutbuf = max_input;
5a6b4e
+    }
5a6b4e
+
5a6b4e
+    return SASL_OK;
5a6b4e
+}
5a6b4e
+
5a6b4e
 /* The GSS-SPNEGO mechanism does not do SSF negotiation, instead it uses the
5a6b4e
  * flags negotiated by GSSAPI to determine If confidentiality or integrity are
5a6b4e
  * used. These flags are stored in text->qop transalated as layers by the
5a6b4e
@@ -656,8 +682,7 @@ static int gssapi_spnego_ssf(context_t *text,
5a6b4e
                              sasl_security_properties_t *props,
5a6b4e
                              sasl_out_params_t *oparams)
5a6b4e
 {
5a6b4e
-    OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
-    OM_uint32 max_input;
5a6b4e
+    int ret;
5a6b4e
 
5a6b4e
     if (text->qop & LAYER_CONFIDENTIALITY) {
5a6b4e
         oparams->encode = &gssapi_privacy_encode;
5a6b4e
@@ -674,20 +699,10 @@ static int gssapi_spnego_ssf(context_t *text,
5a6b4e
     }
5a6b4e
 
5a6b4e
     if (oparams->mech_ssf) {
5a6b4e
-        maj_stat = gss_wrap_size_limit(&min_stat,
5a6b4e
-                                       text->gss_ctx,
5a6b4e
-                                       1,
5a6b4e
-                                       GSS_C_QOP_DEFAULT,
5a6b4e
-                                       (OM_uint32)oparams->maxoutbuf,
5a6b4e
-                                       &max_input);
5a6b4e
-
5a6b4e
-	if (max_input > oparams->maxoutbuf) {
5a6b4e
-	    /* Heimdal appears to get this wrong */
5a6b4e
-	    oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
5a6b4e
-	} else {
5a6b4e
-	    /* This code is actually correct */
5a6b4e
-	    oparams->maxoutbuf = max_input;
5a6b4e
-	}
5a6b4e
+        ret = gssapi_wrap_sizes(text, oparams);
5a6b4e
+        if (ret != SASL_OK) {
5a6b4e
+            return ret;
5a6b4e
+        }
5a6b4e
     }
5a6b4e
 
5a6b4e
     text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
5a6b4e
@@ -1208,7 +1223,6 @@ gssapi_server_mech_ssfreq(context_t *text,
5a6b4e
     gss_buffer_t input_token, output_token;
5a6b4e
     gss_buffer_desc real_input_token, real_output_token;
5a6b4e
     OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
-    OM_uint32 max_input;
5a6b4e
     int layerchoice;
5a6b4e
 	
5a6b4e
     input_token = &real_input_token;
5a6b4e
@@ -1297,27 +1311,20 @@ gssapi_server_mech_ssfreq(context_t *text,
5a6b4e
 	(((unsigned char *) output_token->value)[2] << 8) |
5a6b4e
 	(((unsigned char *) output_token->value)[3] << 0);
5a6b4e
 
5a6b4e
-    if (oparams->mech_ssf) {
5a6b4e
-	maj_stat = gss_wrap_size_limit( &min_stat,
5a6b4e
-					text->gss_ctx,
5a6b4e
-					1,
5a6b4e
-					GSS_C_QOP_DEFAULT,
5a6b4e
-					(OM_uint32) oparams->maxoutbuf,
5a6b4e
-					&max_input);
5a6b4e
-
5a6b4e
-	if(max_input > oparams->maxoutbuf) {
5a6b4e
-	    /* Heimdal appears to get this wrong */
5a6b4e
-	    oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
5a6b4e
-	} else {
5a6b4e
-	    /* This code is actually correct */
5a6b4e
-	    oparams->maxoutbuf = max_input;
5a6b4e
-	}    
5a6b4e
-    }
5a6b4e
-	
5a6b4e
     GSS_LOCK_MUTEX_CTX(params->utils, text);
5a6b4e
     gss_release_buffer(&min_stat, output_token);
5a6b4e
     GSS_UNLOCK_MUTEX_CTX(params->utils, text);
5a6b4e
 
5a6b4e
+    if (oparams->mech_ssf) {
5a6b4e
+        int ret;
5a6b4e
+
5a6b4e
+        ret = gssapi_wrap_sizes(text, oparams);
5a6b4e
+        if (ret != SASL_OK) {
5a6b4e
+	    sasl_gss_free_context_contents(text);
5a6b4e
+            return ret;
5a6b4e
+        }
5a6b4e
+    }
5a6b4e
+
5a6b4e
     text->state = SASL_GSSAPI_STATE_AUTHENTICATED;
5a6b4e
 
5a6b4e
     /* used by layers */
5a6b4e
@@ -1569,7 +1576,6 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
     gss_buffer_t input_token, output_token;
5a6b4e
     gss_buffer_desc real_input_token, real_output_token;
5a6b4e
     OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
-    OM_uint32 max_input;
5a6b4e
     gss_buffer_desc name_token;
5a6b4e
     int ret;
5a6b4e
     OM_uint32 req_flags = 0, out_req_flags = 0;
5a6b4e
@@ -1952,27 +1958,19 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
             (((unsigned char *) output_token->value)[2] << 8) |
5a6b4e
             (((unsigned char *) output_token->value)[3] << 0);
5a6b4e
 
5a6b4e
-	if (oparams->mech_ssf) {
5a6b4e
-            maj_stat = gss_wrap_size_limit( &min_stat,
5a6b4e
-                                            text->gss_ctx,
5a6b4e
-                                            1,
5a6b4e
-                                            GSS_C_QOP_DEFAULT,
5a6b4e
-                                            (OM_uint32) oparams->maxoutbuf,
5a6b4e
-                                            &max_input);
5a6b4e
-
5a6b4e
-	    if (max_input > oparams->maxoutbuf) {
5a6b4e
-		/* Heimdal appears to get this wrong */
5a6b4e
-		oparams->maxoutbuf -= (max_input - oparams->maxoutbuf);
5a6b4e
-	    } else {
5a6b4e
-		/* This code is actually correct */
5a6b4e
-		oparams->maxoutbuf = max_input;
5a6b4e
-	    }
5a6b4e
-	}
5a6b4e
-	
5a6b4e
 	GSS_LOCK_MUTEX_CTX(params->utils, text);
5a6b4e
 	gss_release_buffer(&min_stat, output_token);
5a6b4e
 	GSS_UNLOCK_MUTEX_CTX(params->utils, text);
5a6b4e
-	
5a6b4e
+
5a6b4e
+	if (oparams->mech_ssf) {
5a6b4e
+            int ret;
5a6b4e
+
5a6b4e
+            ret = gssapi_wrap_sizes(text, oparams);
5a6b4e
+            if (ret != SASL_OK) {
5a6b4e
+	        sasl_gss_free_context_contents(text);
5a6b4e
+                return ret;
5a6b4e
+            }
5a6b4e
+	}
5a6b4e
 	/* oparams->user is always set, due to canon_user requirements.
5a6b4e
 	 * Make sure the client actually requested it though, by checking
5a6b4e
 	 * if our context was set.
5a6b4e
5a6b4e
From ff9f9caeb6db6d7513128fff9321f9bd445f58b7 Mon Sep 17 00:00:00 2001
5a6b4e
From: Simo Sorce <simo@redhat.com>
5a6b4e
Date: Mon, 10 Apr 2017 19:54:19 -0400
5a6b4e
Subject: [PATCH 3/3] Add support for retrieving the mech_ssf
5a6b4e
5a6b4e
In the latest MIT Kerberos implementation it is possible to extract
5a6b4e
the calculated SSF wich is based on the encryption type that has been
5a6b4e
used to establish the GSSAPI security context.
5a6b4e
5a6b4e
Use this method if available or fall back to the old "DES" value.
5a6b4e
5a6b4e
Signed-off-by: Simo Sorce <simo@redhat.com>
5a6b4e
---
5a6b4e
 cmulocal/sasl2.m4      |  20 +++++++++++
5a6b4e
 plugins/gssapi.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++------
5a6b4e
 2 files changed, 111 insertions(+), 11 deletions(-)
5a6b4e
5a6b4e
diff --git a/cmulocal/sasl2.m4 b/cmulocal/sasl2.m4
5a6b4e
index 66b291b0..686c4bc7 100644
5a6b4e
--- a/cmulocal/sasl2.m4
5a6b4e
+++ b/cmulocal/sasl2.m4
5a6b4e
@@ -290,6 +290,26 @@ if test "$gssapi" != no; then
5a6b4e
 
5a6b4e
   cmu_save_LIBS="$LIBS"
5a6b4e
   LIBS="$LIBS $GSSAPIBASE_LIBS"
5a6b4e
+  AC_CHECK_FUNCS(gss_inquire_sec_context_by_oid)
5a6b4e
+  if test "$ac_cv_func_gss_inquire_sec_context_by_oid" = no ; then
5a6b4e
+    if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
5a6b4e
+      AC_CHECK_DECL(gss_inquire_sec_context_by_oid,
5a6b4e
+                    [AC_DEFINE(HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID,1,
5a6b4e
+                               [Define if your GSSAPI implementation defines gss_inquire_sec_context_by_oid])],,
5a6b4e
+                    [
5a6b4e
+                    AC_INCLUDES_DEFAULT
5a6b4e
+                    #include <gssapi/gssapi_ext.h>
5a6b4e
+                    ])
5a6b4e
+    fi
5a6b4e
+  fi
5a6b4e
+  if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
5a6b4e
+    AC_EGREP_HEADER(GSS_C_SEC_CONTEXT_SASL_SSF, gssapi/gssapi_ext.h,
5a6b4e
+                    [AC_DEFINE(HAVE_GSS_C_SEC_CONTEXT_SASL_SSF,,
5a6b4e
+                               [Define if your GSSAPI implementation defines GSS_C_SEC_CONTEXT_SASL_SSF])])
5a6b4e
+  fi
5a6b4e
+  cmu_save_LIBS="$LIBS"
5a6b4e
+  LIBS="$LIBS $GSSAPIBASE_LIBS"
5a6b4e
+
5a6b4e
   AC_MSG_CHECKING([for SPNEGO support in GSSAPI libraries])
5a6b4e
   AC_TRY_RUN([
5a6b4e
 #ifdef HAVE_GSSAPI_H
5a6b4e
diff --git a/plugins/gssapi.c b/plugins/gssapi.c
5a6b4e
index 348debe0..5f554ce3 100644
5a6b4e
--- a/plugins/gssapi.c
5a6b4e
+++ b/plugins/gssapi.c
5a6b4e
@@ -51,6 +51,9 @@
5a6b4e
 #endif
5a6b4e
 
5a6b4e
 #include <gssapi/gssapi_krb5.h>
5a6b4e
+#ifdef HAVE_GSSAPI_GSSAPI_EXT_H
5a6b4e
+#include <gssapi/gssapi_ext.h>
5a6b4e
+#endif
5a6b4e
 
5a6b4e
 #ifdef WIN32
5a6b4e
 #  include <winsock2.h>
5a6b4e
@@ -98,18 +103,25 @@ extern gss_OID gss_nt_service_name;
5a6b4e
 /* Check if CyberSafe flag is defined */
5a6b4e
 #ifdef CSF_GSS_C_DES3_FLAG
5a6b4e
 #define K5_MAX_SSF	112
5a6b4e
+#define K5_MIN_SSF	112
5a6b4e
 #endif
5a6b4e
 
5a6b4e
 /* Heimdal and MIT use the following */
5a6b4e
 #ifdef GSS_KRB5_CONF_C_QOP_DES3_KD
5a6b4e
 #define K5_MAX_SSF	112
5a6b4e
+#define K5_MIN_SSF	112
5a6b4e
 #endif
5a6b4e
 
5a6b4e
 #endif
5a6b4e
 
5a6b4e
 #ifndef K5_MAX_SSF
5a6b4e
+/* All modern Kerberos implementations support AES */
5a6b4e
+#define K5_MAX_SSF	256
5a6b4e
+#endif
5a6b4e
+
5a6b4e
 /* All Kerberos implementations support DES */
5a6b4e
-#define K5_MAX_SSF	56
5a6b4e
+#ifndef K5_MIN_SSF
5a6b4e
+#define K5_MIN_SSF      56
5a6b4e
 #endif
5a6b4e
 
5a6b4e
 /* GSSAPI SASL Mechanism by Leif Johansson <leifj@matematik.su.se>
5a6b4e
@@ -674,6 +686,47 @@ static int gssapi_wrap_sizes(context_t *text, sasl_out_params_t *oparams)
5a6b4e
     return SASL_OK;
5a6b4e
 }
5a6b4e
 
5a6b4e
+#if !defined(HAVE_GSS_C_SEC_CONTEXT_SASL_SSF)
5a6b4e
+gss_OID_desc gss_sasl_ssf = {
5a6b4e
+    11, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x0f"
5a6b4e
+};
5a6b4e
+gss_OID GSS_C_SEC_CONTEXT_SASL_SSF = &gss_sasl_ssf;
5a6b4e
+#endif
5a6b4e
+
5a6b4e
+static int gssapi_get_ssf(context_t *text, sasl_ssf_t *mech_ssf)
5a6b4e
+{
5a6b4e
+#ifdef HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID
5a6b4e
+    OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
+    gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
5a6b4e
+    gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
5a6b4e
+    uint32_t ssf;
5a6b4e
+
5a6b4e
+    maj_stat = gss_inquire_sec_context_by_oid(&min_stat, text->gss_ctx,
5a6b4e
+                                              ssf_oid, &bufset);
5a6b4e
+    switch (maj_stat) {
5a6b4e
+    case GSS_S_UNAVAILABLE:
5a6b4e
+        /* Not supported by the library, fallback to default */
5a6b4e
+        goto fallback;
5a6b4e
+    case GSS_S_COMPLETE:
5a6b4e
+        if ((bufset->count != 1) || (bufset->elements[0].length != 4)) {
5a6b4e
+            /* Malformed bufset, fail */
5a6b4e
+            (void)gss_release_buffer_set(&min_stat, &bufset);
5a6b4e
+            return SASL_FAIL;
5a6b4e
+        }
5a6b4e
+        memcpy(&ssf, bufset->elements[0].value, 4);
5a6b4e
+        (void)gss_release_buffer_set(&min_stat, &bufset);
5a6b4e
+        *mech_ssf = ntohl(ssf);
5a6b4e
+        return SASL_OK;
5a6b4e
+    default:
5a6b4e
+        return SASL_FAIL;
5a6b4e
+    }
5a6b4e
+
5a6b4e
+fallback:
5a6b4e
+#endif
5a6b4e
+    *mech_ssf = K5_MIN_SSF;
5a6b4e
+    return SASL_OK;
5a6b4e
+}
5a6b4e
+
5a6b4e
 /* The GSS-SPNEGO mechanism does not do SSF negotiation, instead it uses the
5a6b4e
  * flags negotiated by GSSAPI to determine If confidentiality or integrity are
5a6b4e
  * used. These flags are stored in text->qop transalated as layers by the
5a6b4e
@@ -687,7 +740,10 @@ static int gssapi_spnego_ssf(context_t *text,
5a6b4e
     if (text->qop & LAYER_CONFIDENTIALITY) {
5a6b4e
         oparams->encode = &gssapi_privacy_encode;
5a6b4e
         oparams->decode = &gssapi_decode;
5a6b4e
-        oparams->mech_ssf = K5_MAX_SSF;
5a6b4e
+        ret = gssapi_get_ssf(text, &oparams->mech_ssf);
5a6b4e
+        if (ret != SASL_OK) {
5a6b4e
+            return ret;
5a6b4e
+        }
5a6b4e
     } else if (text->qop & LAYER_INTEGRITY) {
5a6b4e
         oparams->encode = &gssapi_integrity_encode;
5a6b4e
         oparams->decode = &gssapi_decode;
5a6b4e
@@ -1089,6 +1145,7 @@ gssapi_server_mech_ssfcap(context_t *text,
5a6b4e
     gss_buffer_desc real_input_token, real_output_token;
5a6b4e
     OM_uint32 maj_stat = 0, min_stat = 0;
5a6b4e
     unsigned char sasldata[4];
5a6b4e
+    sasl_ssf_t mech_ssf;
5a6b4e
     int ret;
5a6b4e
 
5a6b4e
     input_token = &real_input_token;
5a6b4e
@@ -1149,9 +1206,14 @@ gssapi_server_mech_ssfcap(context_t *text,
5a6b4e
 	params->props.maxbufsize) {
5a6b4e
 	sasldata[0] |= LAYER_INTEGRITY;
5a6b4e
     }
5a6b4e
+    ret = gssapi_get_ssf(text, &mech_ssf);
5a6b4e
+    if (ret != SASL_OK) {
5a6b4e
+	sasl_gss_free_context_contents(text);
5a6b4e
+        return ret;
5a6b4e
+    }
5a6b4e
     if ((text->qop & LAYER_CONFIDENTIALITY) &&
5a6b4e
-	text->requiressf <= K5_MAX_SSF &&
5a6b4e
-	text->limitssf >= K5_MAX_SSF &&
5a6b4e
+	text->requiressf <= mech_ssf &&
5a6b4e
+	text->limitssf >= mech_ssf &&
5a6b4e
 	params->props.maxbufsize) {
5a6b4e
 	sasldata[0] |= LAYER_CONFIDENTIALITY;
5a6b4e
     }
5a6b4e
@@ -1271,10 +1333,18 @@ gssapi_server_mech_ssfreq(context_t *text,
5a6b4e
 	} else if (/* For compatibility with broken clients setting both bits */
5a6b4e
 		   (layerchoice & (LAYER_CONFIDENTIALITY | LAYER_INTEGRITY)) &&
5a6b4e
 	       (text->qop & LAYER_CONFIDENTIALITY)) { /* privacy */
5a6b4e
+        int ret;
5a6b4e
 	oparams->encode = &gssapi_privacy_encode;
5a6b4e
 	oparams->decode = &gssapi_decode;
5a6b4e
-	/* FIX ME: Need to extract the proper value here */
5a6b4e
-	oparams->mech_ssf = K5_MAX_SSF;
5a6b4e
+
5a6b4e
+	ret = gssapi_get_ssf(text, &oparams->mech_ssf);
5a6b4e
+        if (ret != SASL_OK) {
5a6b4e
+	    GSS_LOCK_MUTEX_CTX(params->utils, text);
5a6b4e
+	    gss_release_buffer(&min_stat, output_token);
5a6b4e
+	    GSS_UNLOCK_MUTEX_CTX(params->utils, text);
5a6b4e
+	    sasl_gss_free_context_contents(text);
5a6b4e
+	    return ret;
5a6b4e
+	}
5a6b4e
     } else {
5a6b4e
 	/* not a supported encryption layer */
5a6b4e
 	SETERROR(text->utils,
5a6b4e
@@ -1845,6 +1915,8 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
 	unsigned int alen, external = params->external_ssf;
5a6b4e
 	sasl_ssf_t need, allowed;
5a6b4e
 	char serverhas, mychoice;
5a6b4e
+	sasl_ssf_t mech_ssf;
5a6b4e
+	int ret;
5a6b4e
 	
5a6b4e
 	real_input_token.value = (void *) serverin;
5a6b4e
 	real_input_token.length = serverinlen;
5a6b4e
@@ -1879,8 +1951,17 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
 	    return SASL_FAIL;
5a6b4e
 	}
5a6b4e
 
5a6b4e
+	ret = gssapi_get_ssf(text, &mech_ssf);
5a6b4e
+	if (ret != SASL_OK) {
5a6b4e
+	    GSS_LOCK_MUTEX_CTX(params->utils, text);
5a6b4e
+	    gss_release_buffer(&min_stat, output_token);
5a6b4e
+	    GSS_UNLOCK_MUTEX_CTX(params->utils, text);
5a6b4e
+	    sasl_gss_free_context_contents(text);
5a6b4e
+	    return SASL_FAIL;
5a6b4e
+	}
5a6b4e
+
5a6b4e
 	/* taken from kerberos.c */
5a6b4e
-	if (secprops->min_ssf > (K5_MAX_SSF + external)) {
5a6b4e
+	if (secprops->min_ssf > (mech_ssf + external)) {
5a6b4e
 	    return SASL_TOOWEAK;
5a6b4e
 	} else if (secprops->min_ssf > secprops->max_ssf) {
5a6b4e
 	    return SASL_BADPARAM;
5a6b4e
@@ -1904,8 +1985,8 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
 	
5a6b4e
 	/* use the strongest layer available */
5a6b4e
 	if ((text->qop & LAYER_CONFIDENTIALITY) &&
5a6b4e
-	    allowed >= K5_MAX_SSF &&
5a6b4e
-	    need <= K5_MAX_SSF &&
5a6b4e
+	    allowed >= mech_ssf &&
5a6b4e
+	    need <= mech_ssf &&
5a6b4e
 	    (serverhas & LAYER_CONFIDENTIALITY)) {
5a6b4e
 	    
5a6b4e
 	    const char *ad_compat;
5a6b4e
@@ -1913,8 +1994,7 @@ static int gssapi_client_mech_step(void *conn_context,
5a6b4e
 	    /* encryption */
5a6b4e
 	    oparams->encode = &gssapi_privacy_encode;
5a6b4e
 	    oparams->decode = &gssapi_decode;
5a6b4e
-	    /* FIX ME: Need to extract the proper value here */
5a6b4e
-	    oparams->mech_ssf = K5_MAX_SSF;
5a6b4e
+	    oparams->mech_ssf = mech_ssf;
5a6b4e
 	    mychoice = LAYER_CONFIDENTIALITY;
5a6b4e
 
5a6b4e
 	    if (serverhas & LAYER_INTEGRITY) {
5a6b4e
5a6b4e
5a6b4e
5a6b4e
diff -U3 cyrus-sasl-2.1.26.old/config.h.in cyrus-sasl-2.1.26/config.h.in
5a6b4e
--- cyrus-sasl-2.1.26.old/config.h.in   2012-11-06 20:20:59.000000000 +0100
5a6b4e
+++ cyrus-sasl-2.1.26/config.h.in       2017-09-21 10:33:36.225258244 +0200
5a6b4e
@@ -132,6 +135,9 @@
5a6b4e
 /* Define if your GSSAPI implementation defines GSS_C_NT_USER_NAME */
5a6b4e
 #undef HAVE_GSS_C_NT_USER_NAME
5a6b4e
 
5a6b4e
+/* Define if your GSSAPI implementation defines GSS_C_SEC_CONTEXT_SASL_SSF */
5a6b4e
+#undef HAVE_GSS_C_SEC_CONTEXT_SASL_SSF
5a6b4e
+
5a6b4e
 /* Define to 1 if you have the `gss_decapsulate_token' function. */
5a6b4e
 #undef HAVE_GSS_DECAPSULATE_TOKEN
5a6b4e
 
5a6b4e
@@ -141,6 +147,10 @@
5a6b4e
 /* Define to 1 if you have the `gss_get_name_attribute' function. */
5a6b4e
 #undef HAVE_GSS_GET_NAME_ATTRIBUTE
5a6b4e
 
5a6b4e
+/* Define if your GSSAPI implementation defines gss_inquire_sec_context_by_oid
5a6b4e
+   */
5a6b4e
+#undef HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID
5a6b4e
+
5a6b4e
 /* Define to 1 if you have the `gss_oid_equal' function. */
5a6b4e
 #undef HAVE_GSS_OID_EQUAL
5a6b4e
 
5a6b4e
diff -U3 cyrus-sasl-2.1.26.old/configure cyrus-sasl-2.1.26/configure
5a6b4e
--- cyrus-sasl-2.1.26.old/configure     2017-09-21 10:11:30.557021831 +0200
5a6b4e
+++ cyrus-sasl-2.1.26/configure 2017-09-21 10:33:40.389277838 +0200
5a6b4e
@@ -13984,6 +13984,50 @@
5a6b4e
 
5a6b4e
   LIBS="$cmu_save_LIBS"
5a6b4e
 
5a6b4e
+  cmu_save_LIBS="$LIBS"
5a6b4e
+  LIBS="$LIBS $GSSAPIBASE_LIBS"
5a6b4e
+  for ac_func in gss_inquire_sec_context_by_oid
5a6b4e
+do :
5a6b4e
+  ac_fn_c_check_func "$LINENO" "gss_inquire_sec_context_by_oid" "ac_cv_func_gss_inquire_sec_context_by_oid"
5a6b4e
+if test "x$ac_cv_func_gss_inquire_sec_context_by_oid" = xyes; then :
5a6b4e
+  cat >>confdefs.h <<_ACEOF
5a6b4e
+#define HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID 1
5a6b4e
+_ACEOF
5a6b4e
+
5a6b4e
+fi
5a6b4e
+done
5a6b4e
+
5a6b4e
+  if test "$ac_cv_func_gss_inquire_sec_context_by_oid" = no ; then
5a6b4e
+    if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
5a6b4e
+      ac_fn_c_check_decl "$LINENO" "gss_inquire_sec_context_by_oid" "ac_cv_have_decl_gss_inquire_sec_context_by_oid" "
5a6b4e
+                    $ac_includes_default
5a6b4e
+                    #include <gssapi/gssapi_ext.h>
5a6b4e
+
5a6b4e
+"
5a6b4e
+if test "x$ac_cv_have_decl_gss_inquire_sec_context_by_oid" = xyes; then :
5a6b4e
+
5a6b4e
+$as_echo "#define HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID 1" >>confdefs.h
5a6b4e
+
5a6b4e
+fi
5a6b4e
+
5a6b4e
+    fi
5a6b4e
+  fi
5a6b4e
+  if test "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"; then
5a6b4e
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
5a6b4e
+/* end confdefs.h.  */
5a6b4e
+#include <gssapi/gssapi_ext.h>
5a6b4e
+
5a6b4e
+_ACEOF
5a6b4e
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
5a6b4e
+  $EGREP "GSS_C_SEC_CONTEXT_SASL_SSF" >/dev/null 2>&1; then :
5a6b4e
+
5a6b4e
+$as_echo "#define HAVE_GSS_C_SEC_CONTEXT_SASL_SSF /**/" >>confdefs.h
5a6b4e
+
5a6b4e
+fi
5a6b4e
+rm -f conftest*
5a6b4e
+
5a6b4e
+  fi
5a6b4e
+
5a6b4e
   cmu_save_LIBS="$LIBS"
5a6b4e
   LIBS="$LIBS $GSSAPIBASE_LIBS"
5a6b4e
   { $as_echo "$as_me:$LINENO: checking for SPNEGO support in GSSAPI libraries" >&5