CVE-2016-2110: winbindd: add new_spnego to the WINBINDD_CCACHE_NTLMAUTH response
[kai/samba-autobuild/.git] / source3 / winbindd / winbindd_ccache_access.c
index 5557b959f05afbf54c34e2c74ad06a3d614851e6..039e653401322dc21809f83846de7420277982ae 100644 (file)
@@ -48,14 +48,16 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
                                            const char *password,
                                            const DATA_BLOB initial_msg,
                                            const DATA_BLOB challenge_msg,
+                                           TALLOC_CTX *mem_ctx,
                                            DATA_BLOB *auth_msg,
-                                           uint8_t session_key[16])
+                                           uint8_t session_key[16],
+                                           uint8_t *new_spnego)
 {
        NTSTATUS status;
        struct auth_generic_state *auth_generic_state = NULL;
-       DATA_BLOB dummy_msg, reply, session_key_blob;
+       DATA_BLOB reply, session_key_blob;
 
-       status = auth_generic_client_prepare(NULL, &auth_generic_state);
+       status = auth_generic_client_prepare(mem_ctx, &auth_generic_state);
 
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("Could not start NTLMSSP client: %s\n",
@@ -87,29 +89,26 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
                goto done;
        }
 
-       gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SESSION_KEY);
+       if (initial_msg.length == 0) {
+               gensec_want_feature(auth_generic_state->gensec_security,
+                                   GENSEC_FEATURE_SESSION_KEY);
+       }
 
-       status = auth_generic_client_start(auth_generic_state, GENSEC_OID_NTLMSSP);
+       status = auth_generic_client_start_by_name(auth_generic_state,
+                                                  "ntlmssp_resume_ccache");
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Could not start NTLMSSP mech: %s\n",
+               DEBUG(1, ("Could not start NTLMSSP resume mech: %s\n",
                        nt_errstr(status)));
                goto done;
        }
 
-       /* We need to get our protocol handler into the right state. So first
-          we ask it to generate the initial message. Actually the client has already
-          sent its own initial message, so we're going to drop this one on the floor.
-          The client might have sent a different message, for example with different
-          negotiation options, but as far as I can tell this won't hurt us. (Unless
-          the client sent a different username or domain, in which case that's their
-          problem for telling us the wrong username or domain.)
-          Since we have a copy of the initial message that the client sent, we could
-          resolve any discrepancies if we had to.
-       */
-       dummy_msg = data_blob_null;
+       /*
+        * We inject the inital NEGOTIATE message our caller used
+        * in order to get the state machine into the correct possition.
+        */
        reply = data_blob_null;
        status = gensec_update(auth_generic_state->gensec_security,
-                              talloc_tos(), NULL, dummy_msg, &reply);
+                              talloc_tos(), initial_msg, &reply);
        data_blob_free(&reply);
 
        if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -120,7 +119,7 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
 
        /* Now we are ready to handle the server's actual response. */
        status = gensec_update(auth_generic_state->gensec_security,
-                              NULL, NULL, challenge_msg, &reply);
+                              mem_ctx, challenge_msg, &reply);
        if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
                DEBUG(1, ("We didn't get a response to the challenge! [%s]\n",
                        nt_errstr(status)));
@@ -146,6 +145,8 @@ static NTSTATUS do_ntlm_auth_with_stored_pw(const char *username,
        memcpy(session_key, session_key_blob.data, 16);
        data_blob_free(&session_key_blob);
        *auth_msg = reply;
+       *new_spnego = gensec_have_feature(auth_generic_state->gensec_security,
+                                         GENSEC_FEATURE_NEW_SPNEGO);
        status = NT_STATUS_OK;
 
 done:
@@ -168,7 +169,7 @@ static bool check_client_uid(struct winbindd_cli_state *state, uid_t uid)
                return False;
        }
 
-       if (uid != ret_uid) {
+       if (uid != ret_uid && ret_uid != sec_initial_uid()) {
                DEBUG(1, ("check_client_uid: Client lied about its uid: said %u, "
                        "actually was %u; denying access\n",
                        (unsigned int)uid, (unsigned int)ret_uid));
@@ -185,7 +186,7 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
        NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
        struct WINBINDD_MEMORY_CREDS *entry;
        DATA_BLOB initial, challenge, auth;
-       uint32 initial_blob_len, challenge_blob_len, extra_len;
+       uint32_t initial_blob_len, challenge_blob_len, extra_len;
 
        /* Ensure null termination */
        state->request->data.ccache_ntlm_auth.user[
@@ -273,8 +274,9 @@ void winbindd_ccache_ntlm_auth(struct winbindd_cli_state *state)
 
        result = do_ntlm_auth_with_stored_pw(
                name_user, name_domain, entry->pass,
-               initial, challenge, &auth,
-               state->response->data.ccache_ntlm_auth.session_key);
+               initial, challenge, talloc_tos(), &auth,
+               state->response->data.ccache_ntlm_auth.session_key,
+               &state->response->data.ccache_ntlm_auth.new_spnego);
 
        if (!NT_STATUS_IS_OK(result)) {
                goto process_result;