gensec/spnego: work around missing server mechListMIC in SMB servers
authorStefan Metzmacher <metze@samba.org>
Thu, 1 Sep 2016 06:08:23 +0000 (08:08 +0200)
committerKarolin Seeger <kseeger@samba.org>
Fri, 16 Sep 2016 10:05:33 +0000 (12:05 +0200)
BUG: https://bugzilla.samba.org/show_bug.cgi?id=11994

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Christian Ambach <ambi@samba.org>
Autobuild-User(master): Christian Ambach <ambi@samba.org>
Autobuild-Date(master): Fri Sep  2 18:10:44 CEST 2016 on sn-devel-144

(cherry picked from commit 9b45ba5cd53bd513eb777590815a0b8408af64e2)

auth/gensec/spnego.c

index 6a82b5f98977826569cb13452646423783626db3..bed5cd2107118a44e9764cbd330525270b7803dd 100644 (file)
@@ -54,9 +54,11 @@ struct spnego_state {
 
        DATA_BLOB mech_types;
        size_t num_targs;
+       bool downgraded;
        bool mic_requested;
        bool needs_mic_sign;
        bool needs_mic_check;
+       bool may_skip_mic_check;
        bool done_mic_check;
 
        bool simulate_w2k;
@@ -433,6 +435,7 @@ static NTSTATUS gensec_spnego_parse_negTokenInit(struct gensec_security *gensec_
                                         * Indicate the downgrade and request a
                                         * mic.
                                         */
+                                       spnego_state->downgraded = true;
                                        spnego_state->mic_requested = true;
                                        break;
                                }
@@ -1077,7 +1080,7 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
                        DEBUG(3,("GENSEC SPNEGO: client preferred mech (%s) not accepted, server wants: %s\n",
                                 gensec_get_name_by_oid(gensec_security, spnego_state->neg_oid),
                                 gensec_get_name_by_oid(gensec_security, spnego.negTokenTarg.supportedMech)));
-
+                       spnego_state->downgraded = true;
                        spnego_state->no_response_expected = false;
                        talloc_free(spnego_state->sub_sec_security);
                        nt_status = gensec_subcontext_start(spnego_state,
@@ -1134,6 +1137,23 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
                                return NT_STATUS_INVALID_PARAMETER;
                        }
 
+                       if (spnego.negTokenTarg.mechListMIC.length == 0
+                           && spnego_state->may_skip_mic_check) {
+                               /*
+                                * In this case we don't require
+                                * a mechListMIC from the server.
+                                *
+                                * This works around bugs in the Azure
+                                * and Apple spnego implementations.
+                                *
+                                * See
+                                * https://bugzilla.samba.org/show_bug.cgi?id=11994
+                                */
+                               spnego_state->needs_mic_check = false;
+                               nt_status = NT_STATUS_OK;
+                               goto client_response;
+                       }
+
                        nt_status = gensec_check_packet(spnego_state->sub_sec_security,
                                                        spnego_state->mech_types.data,
                                                        spnego_state->mech_types.length,
@@ -1189,9 +1209,56 @@ static NTSTATUS gensec_spnego_update(struct gensec_security *gensec_security, TA
                                         */
                                        new_spnego = false;
                                }
+
                                break;
 
                        case SPNEGO_ACCEPT_INCOMPLETE:
+                               if (spnego.negTokenTarg.mechListMIC.length > 0) {
+                                       new_spnego = true;
+                                       break;
+                               }
+
+                               if (spnego_state->downgraded) {
+                                       /*
+                                        * A downgrade should be protected if
+                                        * supported
+                                        */
+                                       break;
+                               }
+
+                               /*
+                                * The caller may just asked for
+                                * GENSEC_FEATURE_SESSION_KEY, this
+                                * is only reflected in the want_features.
+                                *
+                                * As it will imply
+                                * gensec_have_features(GENSEC_FEATURE_SIGN)
+                                * to return true.
+                                */
+                               if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
+                                       break;
+                               }
+                               if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
+                                       break;
+                               }
+                               /*
+                                * Here we're sure our preferred mech was
+                                * selected by the server and our caller doesn't
+                                * need GENSEC_FEATURE_SIGN nor
+                                * GENSEC_FEATURE_SEAL support.
+                                *
+                                * In this case we don't require
+                                * a mechListMIC from the server.
+                                *
+                                * This works around bugs in the Azure
+                                * and Apple spnego implementations.
+                                *
+                                * See
+                                * https://bugzilla.samba.org/show_bug.cgi?id=11994
+                                */
+                               spnego_state->may_skip_mic_check = true;
+                               break;
+
                        case SPNEGO_REQUEST_MIC:
                                if (spnego.negTokenTarg.mechListMIC.length > 0) {
                                        new_spnego = true;