netlogon_creds_cli: Protect netlogon_creds_cli_check by _lck
authorVolker Lendecke <vl@samba.org>
Wed, 13 Sep 2017 16:40:57 +0000 (09:40 -0700)
committerVolker Lendecke <vl@samba.org>
Mon, 25 Sep 2017 07:43:12 +0000 (09:43 +0200)
netlogon_creds_cli_lck provides the locking around the operation

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
libcli/auth/netlogon_creds_cli.c
source3/rpc_client/cli_pipe.c

index 248fb371fed52ff3237eda9a9e329b7cdc2c4f85..081b18efb0e301161ddf644e110b78274a7aba5d 100644 (file)
@@ -1525,14 +1525,13 @@ struct netlogon_creds_cli_check_state {
        union netr_Capabilities caps;
 
        struct netlogon_creds_CredentialState *creds;
-       struct netlogon_creds_CredentialState tmp_creds;
        struct netr_Authenticator req_auth;
        struct netr_Authenticator rep_auth;
 };
 
 static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
                                             NTSTATUS status);
-static void netlogon_creds_cli_check_locked(struct tevent_req *subreq);
+static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
 
 struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
@@ -1544,6 +1543,7 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
        struct tevent_req *subreq;
        enum dcerpc_AuthType auth_type;
        enum dcerpc_AuthLevel auth_level;
+       NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct netlogon_creds_cli_check_state);
@@ -1555,6 +1555,17 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
        state->context = context;
        state->binding_handle = b;
 
+       if (context->db.lock != NETLOGON_CREDS_CLI_LCK_EXCLUSIVE) {
+               tevent_req_nterror(req, NT_STATUS_NOT_LOCKED);
+               return tevent_req_post(req, ev);
+       }
+
+       status = netlogon_creds_cli_get_internal(context, state,
+                                                &state->creds);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
        state->srv_name_slash = talloc_asprintf(state, "\\\\%s",
                                                context->server.computer);
        if (tevent_req_nomem(state->srv_name_slash, req)) {
@@ -1578,14 +1589,29 @@ struct tevent_req *netlogon_creds_cli_check_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
-       subreq = netlogon_creds_cli_lock_send(state, state->ev,
-                                             state->context);
+       /*
+        * we defer all callbacks in order to cleanup
+        * the database record.
+        */
+       tevent_req_defer_callback(req, state->ev);
+
+       netlogon_creds_client_authenticator(state->creds, &state->req_auth);
+       ZERO_STRUCT(state->rep_auth);
+
+       subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
+                                               state->binding_handle,
+                                               state->srv_name_slash,
+                                               state->context->client.computer,
+                                               &state->req_auth,
+                                               &state->rep_auth,
+                                               1,
+                                               &state->caps);
        if (tevent_req_nomem(subreq, req)) {
                return tevent_req_post(req, ev);
        }
 
        tevent_req_set_callback(subreq,
-                               netlogon_creds_cli_check_locked,
+                               netlogon_creds_cli_check_caps,
                                req);
 
        return req;
@@ -1611,58 +1637,10 @@ static void netlogon_creds_cli_check_cleanup(struct tevent_req *req,
                return;
        }
 
-       netlogon_creds_cli_delete(state->context, state->creds);
+       netlogon_creds_cli_delete_lck(state->context);
        TALLOC_FREE(state->creds);
 }
 
-static void netlogon_creds_cli_check_caps(struct tevent_req *subreq);
-
-static void netlogon_creds_cli_check_locked(struct tevent_req *subreq)
-{
-       struct tevent_req *req =
-               tevent_req_callback_data(subreq,
-               struct tevent_req);
-       struct netlogon_creds_cli_check_state *state =
-               tevent_req_data(req,
-               struct netlogon_creds_cli_check_state);
-       NTSTATUS status;
-
-       status = netlogon_creds_cli_lock_recv(subreq, state,
-                                             &state->creds);
-       TALLOC_FREE(subreq);
-       if (tevent_req_nterror(req, status)) {
-               return;
-       }
-
-       /*
-        * we defer all callbacks in order to cleanup
-        * the database record.
-        */
-       tevent_req_defer_callback(req, state->ev);
-
-       state->tmp_creds = *state->creds;
-       netlogon_creds_client_authenticator(&state->tmp_creds,
-                                           &state->req_auth);
-       ZERO_STRUCT(state->rep_auth);
-
-       subreq = dcerpc_netr_LogonGetCapabilities_send(state, state->ev,
-                                               state->binding_handle,
-                                               state->srv_name_slash,
-                                               state->context->client.computer,
-                                               &state->req_auth,
-                                               &state->rep_auth,
-                                               1,
-                                               &state->caps);
-       if (tevent_req_nomem(subreq, req)) {
-               status = NT_STATUS_NO_MEMORY;
-               netlogon_creds_cli_check_cleanup(req, status);
-               return;
-       }
-       tevent_req_set_callback(subreq,
-                               netlogon_creds_cli_check_caps,
-                               req);
-}
-
 static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
 {
        struct tevent_req *req =
@@ -1683,7 +1661,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
                 * Note that the negotiated flags are already checked
                 * for our required flags after the ServerAuthenticate3/2 call.
                 */
-               uint32_t negotiated = state->tmp_creds.negotiate_flags;
+               uint32_t negotiated = state->creds->negotiate_flags;
 
                if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
                        /*
@@ -1738,7 +1716,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
                 * Note that the negotiated flags are already checked
                 * for our required flags after the ServerAuthenticate3/2 call.
                 */
-               uint32_t negotiated = state->tmp_creds.negotiate_flags;
+               uint32_t negotiated = state->creds->negotiate_flags;
 
                if (negotiated & NETLOGON_NEG_SUPPORTS_AES) {
                        /*
@@ -1764,8 +1742,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
                return;
        }
 
-       ok = netlogon_creds_client_check(&state->tmp_creds,
-                                        &state->rep_auth.cred);
+       ok = netlogon_creds_client_check(state->creds, &state->rep_auth.cred);
        if (!ok) {
                status = NT_STATUS_ACCESS_DENIED;
                tevent_req_nterror(req, status);
@@ -1778,7 +1755,7 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
                return;
        }
 
-       if (state->caps.server_capabilities != state->tmp_creds.negotiate_flags) {
+       if (state->caps.server_capabilities != state->creds->negotiate_flags) {
                status = NT_STATUS_DOWNGRADE_DETECTED;
                tevent_req_nterror(req, status);
                netlogon_creds_cli_check_cleanup(req, status);
@@ -1800,10 +1777,8 @@ static void netlogon_creds_cli_check_caps(struct tevent_req *subreq)
                return;
        }
 
-       *state->creds = state->tmp_creds;
-       status = netlogon_creds_cli_store(state->context,
-                                         state->creds);
-       TALLOC_FREE(state->creds);
+       status = netlogon_creds_cli_store_internal(state->context,
+                                                  state->creds);
        if (tevent_req_nterror(req, status)) {
                return;
        }
index 5e87bad46a2c251b2f6e96c3ffa443ba8696c8e0..710d95a03163c98f91e5a170cc5e4550e7b7ef90 100644 (file)
@@ -3281,21 +3281,23 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
        struct rpc_pipe_client *rpccli;
        struct pipe_auth_data *rpcauth;
        const char *target_service = table->authservices->names[0];
-       struct netlogon_creds_CredentialState *ncreds = NULL;
        struct cli_credentials *cli_creds;
        enum dcerpc_AuthLevel auth_level;
        NTSTATUS status;
        int rpc_pipe_bind_dbglvl = 0;
+       struct netlogon_creds_cli_lck *lck;
 
        status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
 
-       status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
+       status = netlogon_creds_cli_lck(
+               netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+               rpccli, &lck);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("netlogon_creds_cli_lock returned %s\n",
-                         nt_errstr(status)));
+               DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
+                           nt_errstr(status));
                TALLOC_FREE(rpccli);
                return status;
        }
@@ -3333,8 +3335,7 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
                rpc_pipe_bind_dbglvl = 1;
-               netlogon_creds_cli_delete(netlogon_creds, ncreds);
-               TALLOC_FREE(ncreds);
+               netlogon_creds_cli_delete_lck(netlogon_creds);
        }
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(rpc_pipe_bind_dbglvl,
@@ -3344,8 +3345,6 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
                return status;
        }
 
-       TALLOC_FREE(ncreds);
-
        if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
                goto done;
        }
@@ -3359,13 +3358,14 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
                return status;
        }
 
-
 done:
        DEBUG(10,("%s: opened pipe %s to machine %s "
                  "for domain %s and bound using schannel.\n",
                  __func__, table->name,
                  rpccli->desthost, cli_credentials_get_domain(cli_creds)));
 
+       TALLOC_FREE(lck);
+
        *_rpccli = rpccli;
        return NT_STATUS_OK;
 }