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