Backport of part of Upstream PR#603 minimal part needed for interop From 0e722dd3266d5ebd0f889462cc23856fde3d21ed Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 19 Sep 2019 15:58:04 -0400 Subject: [PATCH] Add support for setting max ssf 0 to GSS-SPNEGO This is needed to interop with Windows within a TLS channel. Signed-off-by: Simo Sorce --- m4/sasl2.m4 | 13 +++++++++++++ plugins/gssapi.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/m4/sasl2.m4 b/m4/sasl2.m4 index 17f5d081..60306943 100644 --- a/m4/sasl2.m4 +++ b/m4/sasl2.m4 @@ -287,6 +287,19 @@ if test "$gssapi" != no; then AC_CHECK_FUNCS(gss_oid_equal) LIBS="$cmu_save_LIBS" + cmu_save_LIBS="$LIBS" + LIBS="$LIBS $GSSAPIBASE_LIBS" + if test "$ac_cv_header_gssapi_gssapi_krb5_h" = "yes"; then + AC_CHECK_DECL(GSS_KRB5_CRED_NO_CI_FLAGS_X, + [AC_DEFINE(HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X,1, + [Define if your GSSAPI implementation supports GSS_KRB5_CRED_NO_CI_FLAGS_X])],, + [ + AC_INCLUDES_DEFAULT + #include + ]) + fi + LIBS="$cmu_save_LIBS" + cmu_save_LIBS="$LIBS" LIBS="$LIBS $GSSAPIBASE_LIBS" AC_CHECK_FUNCS(gss_get_name_attribute) diff --git a/plugins/gssapi.c b/plugins/gssapi.c index 46de7d48..cca6cc0a 100644 --- a/plugins/gssapi.c +++ b/plugins/gssapi.c @@ -2123,7 +2123,50 @@ static int gssapi_client_mech_step(void *conn_context, /* We want to try for privacy */ req_flags |= GSS_C_CONF_FLAG; } - } +#ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X + /* The krb5 mechanism automatically adds INTEG and CONF flags even when + * not specified, this has the effect of rendering explicit requests + * of no confidentiality and integrity via setting maxssf 0 moot. + * However to interoperate with Windows machines it needs to be + * possible to unset these flags as Windows machines refuse to allow + * two layers (say TLS and GSSAPI) to both provide these services. + * So if we do not suppress these flags a SASL/GSS-SPNEGO negotiation + * over, say, LDAPS will fail against Windows Servers */ + } else if (params->props.max_ssf == 0) { + gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER; + if (client_creds == GSS_C_NO_CREDENTIAL) { + gss_OID_set_desc mechs = { 0 }; + gss_OID_set desired_mechs = GSS_C_NO_OID_SET; + if (text->mech_type != GSS_C_NO_OID) { + mechs.count = 1; + mechs.elements = text->mech_type; + desired_mechs = &mechs; + } + + maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, + GSS_C_INDEFINITE, desired_mechs, + GSS_C_INITIATE, + &text->client_creds, NULL, NULL); + if (GSS_ERROR(maj_stat)) { + sasl_gss_seterror(text->utils, maj_stat, min_stat); + sasl_gss_free_context_contents(text); + return SASL_FAIL; + } + client_creds = text->client_creds; + } + + maj_stat = gss_set_cred_option(&min_stat, &client_creds, + (gss_OID)GSS_KRB5_CRED_NO_CI_FLAGS_X, + &empty_buffer); + if (GSS_ERROR(maj_stat)) { + sasl_gss_seterror(text->utils, maj_stat, min_stat); + sasl_gss_free_context_contents(text); + return SASL_FAIL; + } +#endif + } + + if (params->props.security_flags & SASL_SEC_PASS_CREDENTIALS) { req_flags = req_flags | GSS_C_DELEG_FLAG;