]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Allow GSS mechs to force mechlistMIC in SPNEGO
authorSimo Sorce <simo@redhat.com>
Mon, 5 May 2014 21:59:08 +0000 (17:59 -0400)
committerGreg Hudson <ghudson@mit.edu>
Thu, 8 May 2014 19:19:10 +0000 (15:19 -0400)
During a SPNEGO negotiation, if the NTLMSSP mechanism is used and a
MIC is produced within the final initiator mechanism token, Microsoft
servers require a mechlistMIC even if NTLMSSP was the most preferred
mechanism.

In spnego_mech.c, add a helper function mech_requires_mechlistMIC
which queries the mechanism to determine whether we might need to
produce a mechlistMIC for interoperability.  Call it after each call
to the mechanism's gss_init_sec_context and set sc->mic_reqd if it
returns true.  Although only the second call to NTLMSSP will actually
ever return true, the first call makes the mechanism aware that the
SPNEGO implementation supports this feature.

[ghudson@mit.edu: clarified commit message and code]

ticket: 7907 (new)

src/lib/gssapi/spnego/spnego_mech.c

index 7529c7426d8445ce8ded3ce8c51ae8f8aca0f607..c9c1b11653d716d02ce7deb9ad871fc8afaf768a 100644 (file)
@@ -474,6 +474,39 @@ create_spnego_ctx(void)
        return (spnego_ctx);
 }
 
+/* iso(1) org(3) dod(6) internet(1) private(4) enterprises(1) samba(7165)
+ * gssntlmssp(655) controls(1) spnego_req_mechlistMIC(2) */
+static const gss_OID_desc spnego_req_mechlistMIC_oid =
+       { 11, "\x2B\x06\x01\x04\x01\xB7\x7D\x85\x0F\x01\x02" };
+
+/*
+ * Return nonzero if the mechanism has reason to believe that a mechlistMIC
+ * exchange will be required.  Microsoft servers erroneously require SPNEGO
+ * mechlistMIC if they see an internal MIC within an NTLMSSP Authenticate
+ * message, even if NTLMSSP was the preferred mechanism.
+ */
+static int
+mech_requires_mechlistMIC(spnego_gss_ctx_id_t sc)
+{
+       OM_uint32 major, minor;
+       gss_ctx_id_t ctx = sc->ctx_handle;
+       gss_OID oid = (gss_OID)&spnego_req_mechlistMIC_oid;
+       gss_buffer_set_t bufs;
+       int result;
+
+       major = gss_inquire_sec_context_by_oid(&minor, ctx, oid, &bufs);
+       if (major != GSS_S_COMPLETE)
+               return 0;
+
+       /* Report true if the mech returns a single buffer containing a single
+        * byte with value 1. */
+       result = (bufs != NULL && bufs->count == 1 &&
+                 bufs->elements[0].length == 1 &&
+                 memcmp(bufs->elements[0].value, "\1", 1) == 0);
+       (void) gss_release_buffer_set(&minor, &bufs);
+       return result;
+}
+
 /*
  * Both initiator and acceptor call here to verify and/or create mechListMIC,
  * and to consistency-check the MIC state.  handle_mic is invoked only if the
@@ -1014,6 +1047,10 @@ spnego_gss_init_sec_context(
                        actual_mech, &mechtok_out,
                        ret_flags, time_rec,
                        &negState, &send_token);
+
+               /* Give the mechanism a chance to force a mechlistMIC. */
+               if (!HARD_ERROR(ret) && mech_requires_mechlistMIC(spnego_ctx))
+                       spnego_ctx->mic_reqd = 1;
        }
 
        /* Step 3: process or generate the MIC, if the negotiated mech is