From f3d71d3e8c1e9c98df38ef5f8c547ff2780e9cfb Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 24 Aug 2009 00:13:02 +0200 Subject: [PATCH] s3:winbind: Add a generic cache for NDR based parent-child requests --- source3/winbindd/winbindd_cache.c | 112 +++++++++++++++++++++++++++ source3/winbindd/winbindd_domain.c | 2 +- source3/winbindd/winbindd_dual.c | 4 +- source3/winbindd/winbindd_dual_ndr.c | 49 ++++++++---- source3/winbindd/winbindd_idmap.c | 2 +- source3/winbindd/winbindd_locator.c | 2 +- source3/winbindd/winbindd_proto.h | 7 +- 7 files changed, 157 insertions(+), 21 deletions(-) diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c index 0fab04c02a2..e8f928867b5 100644 --- a/source3/winbindd/winbindd_cache.c +++ b/source3/winbindd/winbindd_cache.c @@ -4298,3 +4298,115 @@ struct winbindd_methods cache_methods = { password_policy, trusted_domains }; + +static bool wcache_ndr_key(TALLOC_CTX *mem_ctx, char *domain_name, + uint32_t opnum, const DATA_BLOB *req, + TDB_DATA *pkey) +{ + char *key; + size_t keylen; + + key = talloc_asprintf(mem_ctx, "NDR/%s/%d/", domain_name, (int)opnum); + if (key == NULL) { + return false; + } + keylen = talloc_get_size(key) - 1; + + key = talloc_realloc(mem_ctx, key, char, keylen + req->length); + if (key == NULL) { + return false; + } + memcpy(key + keylen, req->data, req->length); + + pkey->dptr = (uint8_t *)key; + pkey->dsize = talloc_get_size(key); + return true; +} + +bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, + uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp) +{ + TDB_DATA key, data; + bool ret = false; + + if (wcache->tdb == NULL) { + return false; + } + + if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) { + return false; + } + data = tdb_fetch(wcache->tdb, key); + TALLOC_FREE(key.dptr); + + if (data.dptr == NULL) { + return false; + } + if (data.dsize < 4) { + goto fail; + } + + if (IS_DOMAIN_ONLINE(domain)) { + uint32_t entry_seqnum, dom_seqnum, last_check; + + if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, + &last_check)) { + goto fail; + } + entry_seqnum = IVAL(data.dptr, 0); + if (entry_seqnum != dom_seqnum) { + DEBUG(10, ("Entry has wrong sequence number: %d\n", + (int)entry_seqnum)); + goto fail; + } + } + + resp->data = (uint8_t *)talloc_memdup(mem_ctx, data.dptr + 4, + data.dsize - 4); + if (resp->data == NULL) { + DEBUG(10, ("talloc failed\n")); + goto fail; + } + resp->length = data.dsize - 4; + + ret = true; +fail: + SAFE_FREE(data.dptr); + return ret; +} + +void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum, + const DATA_BLOB *req, const DATA_BLOB *resp) +{ + TDB_DATA key, data; + uint32_t dom_seqnum, last_check; + + if (wcache->tdb == NULL) { + return; + } + + if (!wcache_fetch_seqnum(domain->name, &dom_seqnum, &last_check)) { + DEBUG(10, ("could not fetch seqnum for domain %s\n", + domain->name)); + return; + } + + if (!wcache_ndr_key(talloc_tos(), domain->name, opnum, req, &key)) { + return; + } + + data.dsize = resp->length + 4; + data.dptr = talloc_array(key.dptr, uint8_t, data.dsize); + if (data.dptr == NULL) { + goto done; + } + + SIVAL(data.dptr, 0, dom_seqnum); + memcpy(data.dptr+4, resp->data, resp->length); + + tdb_store(wcache->tdb, key, data, 0); + +done: + TALLOC_FREE(key.dptr); + return; +} diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c index 5ff2e16abb7..eb4e131259f 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -30,7 +30,7 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[]; void setup_domain_child(struct winbindd_domain *domain, struct winbindd_child *child) { - setup_child(child, domain_dispatch_table, + setup_child(domain, child, domain_dispatch_table, "log.wb", domain->name); child->domain = domain; diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 2158834bdd5..edf784cc210 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -573,7 +573,7 @@ static void child_process_request(struct winbindd_child *child, state->response->result = WINBINDD_ERROR; } -void setup_child(struct winbindd_child *child, +void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, const struct winbindd_child_dispatch_table *table, const char *logprefix, const char *logname) @@ -592,7 +592,7 @@ void setup_child(struct winbindd_child *child, child->table = table; child->queue = tevent_queue_create(NULL, "winbind_child"); SMB_ASSERT(child->queue != NULL); - child->rpccli = wbint_rpccli_create(NULL, child); + child->rpccli = wbint_rpccli_create(NULL, domain, child); SMB_ASSERT(child->rpccli != NULL); } diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c index e6f3265bd57..8a23ce48e04 100644 --- a/source3/winbindd/winbindd_dual_ndr.c +++ b/source3/winbindd/winbindd_dual_ndr.c @@ -32,13 +32,16 @@ #include "librpc/gen_ndr/srv_wbint.h" struct wb_ndr_transport_priv { + struct winbindd_domain *domain; struct winbindd_child *child; }; struct wb_ndr_dispatch_state { + struct wb_ndr_transport_priv *transport; + uint32_t opnum; const struct ndr_interface_call *call; void *r; - struct ndr_push *push; + DATA_BLOB req_blob, resp_blob; struct winbindd_request request; struct winbindd_response *response; }; @@ -56,7 +59,7 @@ static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx, struct wb_ndr_dispatch_state *state; struct wb_ndr_transport_priv *transport = talloc_get_type_abort( cli->transport->priv, struct wb_ndr_transport_priv); - DATA_BLOB blob; + struct ndr_push *push; enum ndr_err_code ndr_err; req = tevent_req_create(mem_ctx, &state, @@ -67,25 +70,34 @@ static struct tevent_req *wb_ndr_dispatch_send(TALLOC_CTX *mem_ctx, state->r = r; state->call = &table->calls[opnum]; + state->transport = transport; + state->opnum = opnum; - state->push = ndr_push_init_ctx(state, NULL); - if (tevent_req_nomem(state->push, req)) { + push = ndr_push_init_ctx(state, NULL); + if (tevent_req_nomem(push, req)) { return tevent_req_post(req, ev); } - ndr_err = state->call->ndr_push(state->push, NDR_IN, r); + ndr_err = state->call->ndr_push(push, NDR_IN, r); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { tevent_req_nterror(req, ndr_map_error2ntstatus(ndr_err)); - TALLOC_FREE(state->push); + TALLOC_FREE(push); return tevent_req_post(req, ev); } - blob = ndr_push_blob(state->push); + state->req_blob = ndr_push_blob(push); + + if ((transport->domain != NULL) + && wcache_fetch_ndr(state, transport->domain, opnum, + &state->req_blob, &state->resp_blob)) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } state->request.cmd = WINBINDD_DUAL_NDRCMD; state->request.data.ndrcmd = opnum; - state->request.extra_data.data = (char *)blob.data; - state->request.extra_len = blob.length; + state->request.extra_data.data = (char *)state->req_blob.data; + state->request.extra_len = state->req_blob.length; subreq = wb_child_request_send(state, ev, transport->child, &state->request); @@ -110,6 +122,16 @@ static void wb_ndr_dispatch_done(struct tevent_req *subreq) tevent_req_nterror(req, map_nt_error_from_unix(err)); return; } + + state->resp_blob = data_blob_const( + state->response->extra_data.data, + state->response->length - sizeof(struct winbindd_response)); + + if (state->transport->domain != NULL) { + wcache_store_ndr(state->transport->domain, state->opnum, + &state->req_blob, &state->resp_blob); + } + tevent_req_done(req); } @@ -121,17 +143,12 @@ static NTSTATUS wb_ndr_dispatch_recv(struct tevent_req *req, NTSTATUS status; struct ndr_pull *pull; enum ndr_err_code ndr_err; - DATA_BLOB blob; if (tevent_req_is_nterror(req, &status)) { return status; } - blob.data = (uint8_t *)state->response->extra_data.data; - blob.length = state->response->length - - sizeof(struct winbindd_response); - - pull = ndr_pull_init_blob(&blob, mem_ctx, NULL); + pull = ndr_pull_init_blob(&state->resp_blob, mem_ctx, NULL); if (pull == NULL) { return NT_STATUS_NO_MEMORY; } @@ -182,6 +199,7 @@ static NTSTATUS wb_ndr_dispatch(struct rpc_pipe_client *cli, } struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_domain *domain, struct winbindd_child *child) { struct rpc_pipe_client *result; @@ -220,6 +238,7 @@ struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, TALLOC_FREE(result); return NULL; } + transp->domain = domain; transp->child = child; result->transport->priv = transp; return result; diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index 7bcc58a0140..5986c3b6c35 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -44,7 +44,7 @@ static struct winbindd_child static_idmap_child; void init_idmap_child(void) { - setup_child(&static_idmap_child, + setup_child(NULL, &static_idmap_child, idmap_dispatch_table, "log.winbindd", "idmap"); } diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c index b35d8dcf545..5488394976d 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -33,7 +33,7 @@ static struct winbindd_child static_locator_child; void init_locator_child(void) { - setup_child(&static_locator_child, + setup_child(NULL, &static_locator_child, locator_dispatch_table, "log.winbindd", "locator"); } diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 5ef61ded42d..3ab95c1ba64 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -210,6 +210,10 @@ NTSTATUS nss_get_info_cached( struct winbindd_domain *domain, ADS_STRUCT *ads, LDAPMessage *msg, const char **homedir, const char **shell, const char **gecos, gid_t *p_gid); +bool wcache_fetch_ndr(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, + uint32_t opnum, const DATA_BLOB *req, DATA_BLOB *resp); +void wcache_store_ndr(struct winbindd_domain *domain, uint32_t opnum, + const DATA_BLOB *req, const DATA_BLOB *resp); /* The following definitions come from winbindd/winbindd_ccache_access.c */ @@ -324,7 +328,7 @@ void sendto_child(struct winbindd_cli_state *state, struct winbindd_child *child); void sendto_domain(struct winbindd_cli_state *state, struct winbindd_domain *domain); -void setup_child(struct winbindd_child *child, +void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, const struct winbindd_child_dispatch_table *table, const char *logprefix, const char *logname); @@ -641,6 +645,7 @@ enum winbindd_result winbindd_dual_ping(struct winbindd_domain *domain, struct winbindd_cli_state *state); struct rpc_pipe_client *wbint_rpccli_create(TALLOC_CTX *mem_ctx, + struct winbindd_domain *domain, struct winbindd_child *child); enum winbindd_result winbindd_dual_ndrcmd(struct winbindd_domain *domain, struct winbindd_cli_state *state); -- 2.34.1