netlogon_creds_cli: Add netlogon_creds_cli_lck
authorVolker Lendecke <vl@samba.org>
Mon, 11 Sep 2017 23:48:27 +0000 (16:48 -0700)
committerVolker Lendecke <vl@samba.org>
Mon, 25 Sep 2017 07:43:12 +0000 (09:43 +0200)
This adds an external locking scheme to protect our
netlogon_creds_CredentialState. This is needed because the routines
exposed by netlogon_creds_cli.h need a more flexible locking to
set up our credentials in a properly protected way.

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

index 3209f6cf871a6c385a4d048372ccb1fffd2e1dcd..06d7260c8b6673f97fa5b3a4eaad192ce5db78a9 100644 (file)
@@ -68,6 +68,7 @@ struct netlogon_creds_cli_context {
                struct db_context *ctx;
                struct g_lock_ctx *g_ctx;
                struct netlogon_creds_cli_locked_state *locked_state;
+               enum netlogon_creds_cli_lck_type lock;
        } db;
 };
 
@@ -909,6 +910,148 @@ NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
        return status;
 }
 
+struct netlogon_creds_cli_lck {
+       struct netlogon_creds_cli_context *context;
+};
+
+struct netlogon_creds_cli_lck_state {
+       struct netlogon_creds_cli_lck *lck;
+       enum netlogon_creds_cli_lck_type type;
+};
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq);
+static int netlogon_creds_cli_lck_destructor(
+       struct netlogon_creds_cli_lck *lck);
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       struct netlogon_creds_cli_context *context,
+       enum netlogon_creds_cli_lck_type type)
+{
+       struct tevent_req *req, *subreq;
+       struct netlogon_creds_cli_lck_state *state;
+       enum g_lock_type gtype;
+
+       req = tevent_req_create(mem_ctx, &state,
+                               struct netlogon_creds_cli_lck_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       if (context->db.lock != NETLOGON_CREDS_CLI_LCK_NONE) {
+               DBG_DEBUG("context already locked\n");
+               tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+               return tevent_req_post(req, ev);
+       }
+
+       switch (type) {
+           case NETLOGON_CREDS_CLI_LCK_SHARED:
+                   gtype = G_LOCK_READ;
+                   break;
+           case NETLOGON_CREDS_CLI_LCK_EXCLUSIVE:
+                   gtype = G_LOCK_WRITE;
+                   break;
+           default:
+                   tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+                   return tevent_req_post(req, ev);
+       }
+
+       state->lck = talloc(state, struct netlogon_creds_cli_lck);
+       if (tevent_req_nomem(state->lck, req)) {
+               return tevent_req_post(req, ev);
+       }
+       state->lck->context = context;
+       state->type = type;
+
+       subreq = g_lock_lock_send(state, ev,
+                                 context->db.g_ctx,
+                                 context->db.key_name,
+                                 gtype);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, netlogon_creds_cli_lck_locked, req);
+
+       return req;
+}
+
+static void netlogon_creds_cli_lck_locked(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+               req, struct netlogon_creds_cli_lck_state);
+       NTSTATUS status;
+
+       status = g_lock_lock_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       state->lck->context->db.lock = state->type;
+       talloc_set_destructor(state->lck, netlogon_creds_cli_lck_destructor);
+
+       tevent_req_done(req);
+}
+
+static int netlogon_creds_cli_lck_destructor(
+       struct netlogon_creds_cli_lck *lck)
+{
+       struct netlogon_creds_cli_context *ctx = lck->context;
+       NTSTATUS status;
+
+       status = g_lock_unlock(ctx->db.g_ctx, ctx->db.key_name);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_WARNING("g_lock_unlock failed: %s\n", nt_errstr(status));
+               smb_panic("g_lock_unlock failed");
+       }
+       ctx->db.lock = NETLOGON_CREDS_CLI_LCK_NONE;
+       return 0;
+}
+
+NTSTATUS netlogon_creds_cli_lck_recv(
+       struct tevent_req *req, TALLOC_CTX *mem_ctx,
+       struct netlogon_creds_cli_lck **lck)
+{
+       struct netlogon_creds_cli_lck_state *state = tevent_req_data(
+               req, struct netlogon_creds_cli_lck_state);
+       NTSTATUS status;
+
+       if (tevent_req_is_nterror(req, &status)) {
+               return status;
+       }
+       *lck = talloc_move(mem_ctx, &state->lck);
+       return NT_STATUS_OK;
+}
+
+NTSTATUS netlogon_creds_cli_lck(
+       struct netlogon_creds_cli_context *context,
+       enum netlogon_creds_cli_lck_type type,
+       TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct tevent_context *ev;
+       struct tevent_req *req;
+       NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+       ev = samba_tevent_context_init(frame);
+       if (ev == NULL) {
+               goto fail;
+       }
+       req = netlogon_creds_cli_lck_send(frame, ev, context, type);
+       if (req == NULL) {
+               goto fail;
+       }
+       if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+               goto fail;
+       }
+       status = netlogon_creds_cli_lck_recv(req, mem_ctx, lck);
+ fail:
+       TALLOC_FREE(frame);
+       return status;
+}
+
 struct netlogon_creds_cli_auth_state {
        struct tevent_context *ev;
        struct netlogon_creds_cli_context *context;
index 7664387ab9548ebd23e6fbfa30740f623052051e..b3e30eb67bfbe6ccac26ae408a45b96b214258e0 100644 (file)
@@ -76,6 +76,26 @@ NTSTATUS netlogon_creds_cli_lock(struct netlogon_creds_cli_context *context,
                        TALLOC_CTX *mem_ctx,
                        struct netlogon_creds_CredentialState **creds);
 
+struct netlogon_creds_cli_lck;
+
+enum netlogon_creds_cli_lck_type {
+       NETLOGON_CREDS_CLI_LCK_NONE,
+       NETLOGON_CREDS_CLI_LCK_SHARED,
+       NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
+};
+
+struct tevent_req *netlogon_creds_cli_lck_send(
+       TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+       struct netlogon_creds_cli_context *context,
+       enum netlogon_creds_cli_lck_type type);
+NTSTATUS netlogon_creds_cli_lck_recv(
+       struct tevent_req *req, TALLOC_CTX *mem_ctx,
+       struct netlogon_creds_cli_lck **lck);
+NTSTATUS netlogon_creds_cli_lck(
+       struct netlogon_creds_cli_context *context,
+       enum netlogon_creds_cli_lck_type type,
+       TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_lck **lck);
+
 struct tevent_req *netlogon_creds_cli_auth_send(TALLOC_CTX *mem_ctx,
                                struct tevent_context *ev,
                                struct netlogon_creds_cli_context *context,