summaryrefslogtreecommitdiff
path: root/source3/winbindd
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2009-08-24 00:13:02 +0200
committerVolker Lendecke <vl@samba.org>2009-08-27 15:04:09 +0200
commitf3d71d3e8c1e9c98df38ef5f8c547ff2780e9cfb (patch)
treeded7ed669abc08a5329f21edc9a879a42ae1d45d /source3/winbindd
parent3532c8b9d831c8122de871db62d17608ff24f409 (diff)
downloadsamba-f3d71d3e8c1e9c98df38ef5f8c547ff2780e9cfb.tar.gz
samba-f3d71d3e8c1e9c98df38ef5f8c547ff2780e9cfb.tar.bz2
samba-f3d71d3e8c1e9c98df38ef5f8c547ff2780e9cfb.zip
s3:winbind: Add a generic cache for NDR based parent-child requests
Diffstat (limited to 'source3/winbindd')
-rw-r--r--source3/winbindd/winbindd_cache.c112
-rw-r--r--source3/winbindd/winbindd_domain.c2
-rw-r--r--source3/winbindd/winbindd_dual.c4
-rw-r--r--source3/winbindd/winbindd_dual_ndr.c49
-rw-r--r--source3/winbindd/winbindd_idmap.c2
-rw-r--r--source3/winbindd/winbindd_locator.c2
-rw-r--r--source3/winbindd/winbindd_proto.h7
7 files changed, 157 insertions, 21 deletions
diff --git a/source3/winbindd/winbindd_cache.c b/source3/winbindd/winbindd_cache.c
index 0fab04c02a..e8f928867b 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 5ff2e16abb..eb4e131259 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 2158834bdd..edf784cc21 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 e6f3265bd5..8a23ce48e0 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 7bcc58a014..5986c3b6c3 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 b35d8dcf54..5488394976 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 5ef61ded42..3ab95c1ba6 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);