From b518cb0597d269002105644302c58ca8f9f0f717 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Feb 2018 16:04:44 +0100 Subject: [PATCH] winbind: Maintain a binding handle per domain and always go via wb_domain_request_send() Pair-Programmed-With: Stefan Metzmacher BUG: https://bugzilla.samba.org/show_bug.cgi?id=13292 Signed-off-by: Stefan Metzmacher Signed-off-by: Volker Lendecke --- source3/winbindd/winbindd.h | 2 + source3/winbindd/winbindd_dual.c | 11 +++-- source3/winbindd/winbindd_dual_ndr.c | 61 ++++++++++++++++++++++++---- source3/winbindd/winbindd_util.c | 6 +++ 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 3e4b256ef32..8a44f37789b 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -184,6 +184,8 @@ struct winbindd_domain { struct winbindd_child *children; + struct dcerpc_binding_handle *binding_handle; + /* Callback we use to try put us back online. */ uint32_t check_online_timeout; diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 21fe3c29fc1..a30ac36a8b0 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -321,10 +321,7 @@ static struct winbindd_child *choose_domain_child(struct winbindd_domain *domain struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain) { - struct winbindd_child *child; - - child = choose_domain_child(domain); - return child->binding_handle; + return domain->binding_handle; } struct wb_domain_request_state { @@ -608,8 +605,10 @@ void setup_child(struct winbindd_domain *domain, struct winbindd_child *child, child->table = table; child->queue = tevent_queue_create(NULL, "winbind_child"); SMB_ASSERT(child->queue != NULL); - child->binding_handle = wbint_binding_handle(NULL, domain, child); - SMB_ASSERT(child->binding_handle != NULL); + if (domain == NULL) { + child->binding_handle = wbint_binding_handle(NULL, NULL, child); + SMB_ASSERT(child->binding_handle != NULL); + } } void winbind_child_died(pid_t pid) diff --git a/source3/winbindd/winbindd_dual_ndr.c b/source3/winbindd/winbindd_dual_ndr.c index 00c7df1f863..25e7445edc6 100644 --- a/source3/winbindd/winbindd_dual_ndr.c +++ b/source3/winbindd/winbindd_dual_ndr.c @@ -42,7 +42,7 @@ static bool wbint_bh_is_connected(struct dcerpc_binding_handle *h) struct wbint_bh_state *hs = dcerpc_binding_handle_data(h, struct wbint_bh_state); - if (!hs->child) { + if ((hs->domain == NULL) && (hs->child == NULL)) { return false; } @@ -65,7 +65,8 @@ struct wbint_bh_raw_call_state { DATA_BLOB out_data; }; -static void wbint_bh_raw_call_done(struct tevent_req *subreq); +static void wbint_bh_raw_call_child_done(struct tevent_req *subreq); +static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq); static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -114,17 +115,28 @@ static struct tevent_req *wbint_bh_raw_call_send(TALLOC_CTX *mem_ctx, state->request.extra_data.data = (char *)state->in_data.data; state->request.extra_len = state->in_data.length; - subreq = wb_child_request_send(state, ev, hs->child, - &state->request); + if (hs->child != NULL) { + subreq = wb_child_request_send(state, ev, hs->child, + &state->request); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback( + subreq, wbint_bh_raw_call_child_done, req); + return req; + } + + subreq = wb_domain_request_send(state, ev, hs->domain, + &state->request); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, wbint_bh_raw_call_done, req); + tevent_req_set_callback(subreq, wbint_bh_raw_call_domain_done, req); return req; } -static void wbint_bh_raw_call_done(struct tevent_req *subreq) +static void wbint_bh_raw_call_child_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data(subreq, @@ -158,6 +170,40 @@ static void wbint_bh_raw_call_done(struct tevent_req *subreq) tevent_req_done(req); } +static void wbint_bh_raw_call_domain_done(struct tevent_req *subreq) +{ + struct tevent_req *req = + tevent_req_callback_data(subreq, + struct tevent_req); + struct wbint_bh_raw_call_state *state = + tevent_req_data(req, + struct wbint_bh_raw_call_state); + int ret, err; + + ret = wb_domain_request_recv(subreq, state, &state->response, &err); + TALLOC_FREE(subreq); + if (ret == -1) { + NTSTATUS status = map_nt_error_from_unix(err); + tevent_req_nterror(req, status); + return; + } + + state->out_data = data_blob_talloc(state, + state->response->extra_data.data, + state->response->length - sizeof(struct winbindd_response)); + if (state->response->extra_data.data && !state->out_data.data) { + tevent_req_oom(req); + return; + } + + if (state->domain != NULL) { + wcache_store_ndr(state->domain, state->opnum, + &state->in_data, &state->out_data); + } + + tevent_req_done(req); +} + static NTSTATUS wbint_bh_raw_call_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint8_t **out_data, @@ -209,9 +255,8 @@ static struct tevent_req *wbint_bh_disconnect_send(TALLOC_CTX *mem_ctx, /* * TODO: do a real async disconnect ... - * - * For now the caller needs to free rpc_cli */ + hs->domain = NULL; hs->child = NULL; tevent_req_done(req); diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 9950c669629..78f526cdea8 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -228,6 +228,12 @@ static NTSTATUS add_trusted_domain(const char *domain_name, return NT_STATUS_NO_MEMORY; } + domain->binding_handle = wbint_binding_handle(domain, domain, NULL); + if (domain->binding_handle == NULL) { + TALLOC_FREE(domain); + return NT_STATUS_NO_MEMORY; + } + domain->name = talloc_strdup(domain, domain_name); if (domain->name == NULL) { TALLOC_FREE(domain); -- 2.34.1