s3:winbind: Add a generic cache for NDR based parent-child requests
authorVolker Lendecke <vl@samba.org>
Sun, 23 Aug 2009 22:13:02 +0000 (00:13 +0200)
committerVolker Lendecke <vl@samba.org>
Thu, 27 Aug 2009 13:04:09 +0000 (15:04 +0200)
source3/winbindd/winbindd_cache.c
source3/winbindd/winbindd_domain.c
source3/winbindd/winbindd_dual.c
source3/winbindd/winbindd_dual_ndr.c
source3/winbindd/winbindd_idmap.c
source3/winbindd/winbindd_locator.c
source3/winbindd/winbindd_proto.h

index 0fab04c02a27430b4adde9a5d15b9dd4fdfbb26f..e8f928867b53e5d089c971a2368fb43f0d9c1bc2 100644 (file)
@@ -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;
+}
index 5ff2e16abb75923953fe3bbde932698947a5b2b6..eb4e131259f02334899f0430cffae284139ca030 100644 (file)
@@ -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;
index 2158834bdd5cb8611b6ebfd90db15804f8f4fe1e..edf784cc210ddb466d7865c202e9e0016ed81530 100644 (file)
@@ -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);
 }
 
index e6f3265bd57c64688731a63370b4306a411dc1d9..8a23ce48e041f01f259c4cb954f043d0ec7fc02b 100644 (file)
 #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;
index 7bcc58a014086f9b3f6ba61ba4e9ba329470d9a5..5986c3b6c357e3d48624cabe9b7083fd943a4250 100644 (file)
@@ -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");
 }
index b35d8dcf545d55e4212449d321872333074ae3a9..5488394976dfeb6f95ef9b120a61c729023edab2 100644 (file)
@@ -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");
 }
index 5ef61ded42dfeb68434f807fb462b502e69e2cda..3ab95c1ba64a2ca04827e78bcd2734deeeaa846c 100644 (file)
@@ -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);