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