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

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