From cd9eadc314880473b696a374aba2693360beea19 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Feb 2018 13:24:54 +0100 Subject: [PATCH 1/5] winbind: add idmap_child_handle() and use it instead of child->binding_handle BUG: https://bugzilla.samba.org/show_bug.cgi?id=13292 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit c2d78a0a0a3f9b9ade61cf707f23e59a1a16c61b) --- source3/winbindd/wb_sids2xids.c | 6 +++--- source3/winbindd/winbindd_allocate_gid.c | 6 +++--- source3/winbindd/winbindd_allocate_uid.c | 6 +++--- source3/winbindd/winbindd_idmap.c | 5 +++++ source3/winbindd/winbindd_proto.h | 1 + 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c index b8ad300ba3c..c687f7064bb 100644 --- a/source3/winbindd/wb_sids2xids.c +++ b/source3/winbindd/wb_sids2xids.c @@ -167,7 +167,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) req, struct wb_sids2xids_state); struct lsa_RefDomainList *domains = NULL; struct lsa_TransNameArray *names = NULL; - struct winbindd_child *child; + struct dcerpc_binding_handle *child_binding_handle = NULL; NTSTATUS status; int i; @@ -237,7 +237,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) TALLOC_FREE(names); TALLOC_FREE(domains); - child = idmap_child(); + child_binding_handle = idmap_child_handle(); state->dom_ids = wb_sids2xids_extract_for_domain_index( state, &state->ids, state->dom_index); @@ -252,7 +252,7 @@ static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq) }; subreq = dcerpc_wbint_Sids2UnixIDs_send( - state, state->ev, child->binding_handle, &state->idmap_dom, + state, state->ev, child_binding_handle, &state->idmap_dom, state->dom_ids); if (tevent_req_nomem(subreq, req)) { return; diff --git a/source3/winbindd/winbindd_allocate_gid.c b/source3/winbindd/winbindd_allocate_gid.c index a9236bbf23d..85aa1369473 100644 --- a/source3/winbindd/winbindd_allocate_gid.c +++ b/source3/winbindd/winbindd_allocate_gid.c @@ -34,7 +34,7 @@ struct tevent_req *winbindd_allocate_gid_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req, *subreq; struct winbindd_allocate_gid_state *state; - struct winbindd_child *child; + struct dcerpc_binding_handle *child_binding_handle = NULL; req = tevent_req_create(mem_ctx, &state, struct winbindd_allocate_gid_state); @@ -44,9 +44,9 @@ struct tevent_req *winbindd_allocate_gid_send(TALLOC_CTX *mem_ctx, DEBUG(3, ("allocate_gid\n")); - child = idmap_child(); + child_binding_handle = idmap_child_handle(); - subreq = dcerpc_wbint_AllocateGid_send(state, ev, child->binding_handle, + subreq = dcerpc_wbint_AllocateGid_send(state, ev, child_binding_handle, &state->gid); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); diff --git a/source3/winbindd/winbindd_allocate_uid.c b/source3/winbindd/winbindd_allocate_uid.c index 99c0bdac102..69ce61c872e 100644 --- a/source3/winbindd/winbindd_allocate_uid.c +++ b/source3/winbindd/winbindd_allocate_uid.c @@ -34,7 +34,7 @@ struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req, *subreq; struct winbindd_allocate_uid_state *state; - struct winbindd_child *child; + struct dcerpc_binding_handle *child_binding_handle = NULL; req = tevent_req_create(mem_ctx, &state, struct winbindd_allocate_uid_state); @@ -44,9 +44,9 @@ struct tevent_req *winbindd_allocate_uid_send(TALLOC_CTX *mem_ctx, DEBUG(3, ("allocate_uid\n")); - child = idmap_child(); + child_binding_handle = idmap_child_handle(); - subreq = dcerpc_wbint_AllocateUid_send(state, ev, child->binding_handle, + subreq = dcerpc_wbint_AllocateUid_send(state, ev, child_binding_handle, &state->uid); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); diff --git a/source3/winbindd/winbindd_idmap.c b/source3/winbindd/winbindd_idmap.c index 028026087d6..2ee436bc7dc 100644 --- a/source3/winbindd/winbindd_idmap.c +++ b/source3/winbindd/winbindd_idmap.c @@ -34,6 +34,11 @@ struct winbindd_child *idmap_child(void) return &static_idmap_child; } +struct dcerpc_binding_handle *idmap_child_handle(void) +{ + return static_idmap_child.binding_handle; +} + static const struct winbindd_child_dispatch_table idmap_dispatch_table[] = { { .name = "PING", diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index d09176d954a..66d4a19617c 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -351,6 +351,7 @@ NTSTATUS winbindd_print_groupmembers(struct db_context *members, void init_idmap_child(void); struct winbindd_child *idmap_child(void); +struct dcerpc_binding_handle *idmap_child_handle(void); struct idmap_domain *idmap_find_domain_with_sid(const char *domname, const struct dom_sid *sid); const char *idmap_config_const_string(const char *domname, const char *option, -- 2.13.6 From 59027a05dfae6391be56f0914381664ccbbbdf38 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Feb 2018 13:24:54 +0100 Subject: [PATCH 2/5] winbind: add locator_child_handle() and use it instead of child->binding_handle BUG: https://bugzilla.samba.org/show_bug.cgi?id=13292 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 44ebaaac8933f5fc16a043b8c15a9449746af47b) --- source3/winbindd/wb_dsgetdcname.c | 8 ++++---- source3/winbindd/winbindd_dsgetdcname.c | 6 +++--- source3/winbindd/winbindd_locator.c | 5 +++++ source3/winbindd/winbindd_proto.h | 1 + 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/source3/winbindd/wb_dsgetdcname.c b/source3/winbindd/wb_dsgetdcname.c index 8bd74198bcb..2f450c7a2b4 100644 --- a/source3/winbindd/wb_dsgetdcname.c +++ b/source3/winbindd/wb_dsgetdcname.c @@ -37,7 +37,7 @@ struct tevent_req *wb_dsgetdcname_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req, *subreq; struct wb_dsgetdcname_state *state; - struct winbindd_child *child; + struct dcerpc_binding_handle *child_binding_handle = NULL; struct GUID guid; struct GUID *guid_ptr = NULL; @@ -72,10 +72,10 @@ struct tevent_req *wb_dsgetdcname_send(TALLOC_CTX *mem_ctx, /* * We have to figure out the DC ourselves */ - child = locator_child(); + child_binding_handle = locator_child_handle(); } else { struct winbindd_domain *domain = find_our_domain(); - child = choose_domain_child(domain); + child_binding_handle = dom_child_handle(domain); } if (domain_guid != NULL) { @@ -85,7 +85,7 @@ struct tevent_req *wb_dsgetdcname_send(TALLOC_CTX *mem_ctx, } subreq = dcerpc_wbint_DsGetDcName_send( - state, ev, child->binding_handle, domain_name, guid_ptr, site_name, + state, ev, child_binding_handle, domain_name, guid_ptr, site_name, flags, &state->dcinfo); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); diff --git a/source3/winbindd/winbindd_dsgetdcname.c b/source3/winbindd/winbindd_dsgetdcname.c index 8eb1de74d92..fd9270f106c 100644 --- a/source3/winbindd/winbindd_dsgetdcname.c +++ b/source3/winbindd/winbindd_dsgetdcname.c @@ -35,7 +35,7 @@ struct tevent_req *winbindd_dsgetdcname_send(TALLOC_CTX *mem_ctx, struct winbindd_request *request) { struct tevent_req *req, *subreq; - struct winbindd_child *child; + struct dcerpc_binding_handle *child_binding_handle = NULL; struct winbindd_dsgetdcname_state *state; struct GUID *guid_ptr = NULL; uint32_t ds_flags = 0; @@ -65,10 +65,10 @@ struct tevent_req *winbindd_dsgetdcname_send(TALLOC_CTX *mem_ctx, guid_ptr = &state->guid; } - child = locator_child(); + child_binding_handle = locator_child_handle(); subreq = dcerpc_wbint_DsGetDcName_send( - state, ev, child->binding_handle, + state, ev, child_binding_handle, request->data.dsgetdcname.domain_name, guid_ptr, request->data.dsgetdcname.site_name, ds_flags, &state->dc_info); diff --git a/source3/winbindd/winbindd_locator.c b/source3/winbindd/winbindd_locator.c index 59e8614fdbc..55b64555376 100644 --- a/source3/winbindd/winbindd_locator.c +++ b/source3/winbindd/winbindd_locator.c @@ -34,6 +34,11 @@ struct winbindd_child *locator_child(void) return &static_locator_child; } +struct dcerpc_binding_handle *locator_child_handle(void) +{ + return static_locator_child.binding_handle; +} + static const struct winbindd_child_dispatch_table locator_dispatch_table[] = { { .name = "PING", diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 66d4a19617c..5d31490ff16 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -367,6 +367,7 @@ bool lp_scan_idmap_domains(bool (*fn)(const char *domname, void init_locator_child(void); struct winbindd_child *locator_child(void); +struct dcerpc_binding_handle *locator_child_handle(void); /* The following definitions come from winbindd/winbindd_misc.c */ -- 2.13.6 From 5bb5a4c032fe933634512b9dea14cf5c20cd9fa9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 20 Feb 2018 14:43:38 +0100 Subject: [PATCH 3/5] winbind: make choose_domain_child() static BUG: https://bugzilla.samba.org/show_bug.cgi?id=13292 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke (cherry picked from commit 5116aff286bdffe4abc9ddda09cf64ab999fd13e) --- source3/winbindd/winbindd_dual.c | 2 +- source3/winbindd/winbindd_proto.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 3d44e2027ae..e756aff98de 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -292,7 +292,7 @@ static void wb_child_request_cleanup(struct tevent_req *req, DLIST_REMOVE(winbindd_children, state->child); } -struct winbindd_child *choose_domain_child(struct winbindd_domain *domain) +static struct winbindd_child *choose_domain_child(struct winbindd_domain *domain) { struct winbindd_child *shortest = &domain->children[0]; struct winbindd_child *current; diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 5d31490ff16..704a8dd2924 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -272,7 +272,6 @@ void setup_domain_child(struct winbindd_domain *domain); /* The following definitions come from winbindd/winbindd_dual.c */ struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain); -struct winbindd_child *choose_domain_child(struct winbindd_domain *domain); struct tevent_req *wb_child_request_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 2.13.6 From a8414c6c8710caff8691c70da8351e03c05cb99e Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Feb 2018 16:04:44 +0100 Subject: [PATCH 4/5] 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 (cherry picked from commit b518cb0597d269002105644302c58ca8f9f0f717) --- 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 e756aff98de..263e5e598b7 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.13.6 From 71c8069686192aad122f212ac58c85a7ab6022dd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Feb 2018 15:04:01 +0100 Subject: [PATCH 5/5] winbind: Use one queue for all domain children If we have multiple domain children, it's important that the first idle child takes over the next waiting request. Before we had the problem that a request could get stuck in the queue of a busy child, while later requests could get served fine by other children. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13292 Signed-off-by: Stefan Metzmacher Reviewed-by: Volker Lendecke Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Fri Feb 23 09:04:23 CET 2018 on sn-devel-144 (cherry picked from commit 7f2d45a6c2a88dd8833fc66d314ec21507dd52c3) --- source3/winbindd/winbindd.h | 1 + source3/winbindd/winbindd_dual.c | 127 ++++++++++++++++++++++++++++++++++++--- source3/winbindd/winbindd_util.c | 6 ++ 3 files changed, 125 insertions(+), 9 deletions(-) diff --git a/source3/winbindd/winbindd.h b/source3/winbindd/winbindd.h index 8a44f37789b..081722f6a90 100644 --- a/source3/winbindd/winbindd.h +++ b/source3/winbindd/winbindd.h @@ -184,6 +184,7 @@ struct winbindd_domain { struct winbindd_child *children; + struct tevent_queue *queue; struct dcerpc_binding_handle *binding_handle; /* Callback we use to try put us back online. */ diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index 263e5e598b7..2ae21b09c43 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -223,8 +223,21 @@ static void wb_child_request_done(struct tevent_req *subreq) static void wb_child_request_orphaned(struct tevent_req *subreq) { + struct winbindd_child *child = + (struct winbindd_child *)tevent_req_callback_data_void(subreq); + DBG_WARNING("cleanup orphaned subreq[%p]\n", subreq); TALLOC_FREE(subreq); + + if (child->domain != NULL) { + /* + * If the child is attached to a domain, + * we need to make sure the domain queue + * can move forward, after the orphaned + * request is done. + */ + tevent_queue_start(child->domain->queue); + } } int wb_child_request_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, @@ -267,7 +280,7 @@ static void wb_child_request_cleanup(struct tevent_req *req, talloc_move(subreq, &state->queue_subreq); tevent_req_set_callback(subreq, wb_child_request_orphaned, - NULL); + state->child); DBG_WARNING("keep orphaned subreq[%p]\n", subreq); return; @@ -276,6 +289,16 @@ static void wb_child_request_cleanup(struct tevent_req *req, TALLOC_FREE(state->subreq); TALLOC_FREE(state->queue_subreq); + if (state->child->domain != NULL) { + /* + * If the child is attached to a domain, + * we need to make sure the domain queue + * can move forward, after the request + * is done. + */ + tevent_queue_start(state->child->domain->queue); + } + if (req_state == TEVENT_REQ_DONE) { /* transmitted request and got response */ return; @@ -326,13 +349,35 @@ struct dcerpc_binding_handle *dom_child_handle(struct winbindd_domain *domain) struct wb_domain_request_state { struct tevent_context *ev; + struct tevent_queue_entry *queue_entry; struct winbindd_domain *domain; struct winbindd_child *child; struct winbindd_request *request; struct winbindd_request *init_req; struct winbindd_response *response; + struct tevent_req *pending_subreq; }; +static void wb_domain_request_cleanup(struct tevent_req *req, + enum tevent_req_state req_state) +{ + struct wb_domain_request_state *state = tevent_req_data( + req, struct wb_domain_request_state); + + /* + * If we're completely done or got a failure. + * we should remove ourself from the domain queue, + * after removing the child subreq from the child queue + * and give the next one in the queue the chance + * to check for an idle child. + */ + TALLOC_FREE(state->pending_subreq); + TALLOC_FREE(state->queue_entry); + tevent_queue_start(state->domain->queue); +} + +static void wb_domain_request_trigger(struct tevent_req *req, + void *private_data); static void wb_domain_request_gotdc(struct tevent_req *subreq); static void wb_domain_request_initialized(struct tevent_req *subreq); static void wb_domain_request_done(struct tevent_req *subreq); @@ -342,7 +387,7 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, struct winbindd_request *request) { - struct tevent_req *req, *subreq; + struct tevent_req *req; struct wb_domain_request_state *state; req = tevent_req_create(mem_ctx, &state, @@ -355,21 +400,66 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, state->ev = ev; state->request = request; + tevent_req_set_cleanup_fn(req, wb_domain_request_cleanup); + + state->queue_entry = tevent_queue_add_entry( + domain->queue, state->ev, req, + wb_domain_request_trigger, NULL); + if (tevent_req_nomem(state->queue_entry, req)) { + return tevent_req_post(req, ev); + } + + return req; +} + +static void wb_domain_request_trigger(struct tevent_req *req, + void *private_data) +{ + struct wb_domain_request_state *state = tevent_req_data( + req, struct wb_domain_request_state); + struct winbindd_domain *domain = state->domain; + struct tevent_req *subreq = NULL; + size_t shortest_queue_length; + state->child = choose_domain_child(domain); + shortest_queue_length = tevent_queue_length(state->child->queue); + if (shortest_queue_length > 0) { + /* + * All children are busy, we need to stop + * the queue and untrigger our own queue + * entry. Once a pending request + * is done it calls tevent_queue_start + * and we get retriggered. + */ + state->child = NULL; + tevent_queue_stop(state->domain->queue); + tevent_queue_entry_untrigger(state->queue_entry); + return; + } if (domain->initialized) { subreq = wb_child_request_send(state, state->ev, state->child, state->request); if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); + return; } tevent_req_set_callback(subreq, wb_domain_request_done, req); - return req; + state->pending_subreq = subreq; + + /* + * Once the domain is initialized and + * once we placed our real request into the child queue, + * we can remove ourself from the domain queue + * and give the next one in the queue the chance + * to check for an idle child. + */ + TALLOC_FREE(state->queue_entry); + return; } state->init_req = talloc_zero(state, struct winbindd_request); if (tevent_req_nomem(state->init_req, req)) { - return tevent_req_post(req, ev); + return; } if (IS_DC || domain->primary || domain->internal) { @@ -382,11 +472,12 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, subreq = wb_child_request_send(state, state->ev, state->child, state->init_req); if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); + return; } tevent_req_set_callback(subreq, wb_domain_request_initialized, req); - return req; + state->pending_subreq = subreq; + return; } /* @@ -403,10 +494,11 @@ struct tevent_req *wb_domain_request_send(TALLOC_CTX *mem_ctx, NULL, /* site_name */ DS_RETURN_DNS_NAME); /* flags */ if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); + return; } tevent_req_set_callback(subreq, wb_domain_request_gotdc, req); - return req; + state->pending_subreq = subreq; + return; } static void wb_domain_request_gotdc(struct tevent_req *subreq) @@ -419,6 +511,8 @@ static void wb_domain_request_gotdc(struct tevent_req *subreq) NTSTATUS status; const char *dcname = NULL; + state->pending_subreq = NULL; + status = wb_dsgetdcname_recv(subreq, state, &dcinfo); TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { @@ -442,6 +536,7 @@ static void wb_domain_request_gotdc(struct tevent_req *subreq) return; } tevent_req_set_callback(subreq, wb_domain_request_initialized, req); + state->pending_subreq = subreq; } static void wb_domain_request_initialized(struct tevent_req *subreq) @@ -453,6 +548,8 @@ static void wb_domain_request_initialized(struct tevent_req *subreq) struct winbindd_response *response; int ret, err; + state->pending_subreq = NULL; + ret = wb_child_request_recv(subreq, talloc_tos(), &response, &err); TALLOC_FREE(subreq); if (ret == -1) { @@ -500,6 +597,16 @@ static void wb_domain_request_initialized(struct tevent_req *subreq) return; } tevent_req_set_callback(subreq, wb_domain_request_done, req); + state->pending_subreq = subreq; + + /* + * Once the domain is initialized and + * once we placed our real request into the child queue, + * we can remove ourself from the domain queue + * and give the next one in the queue the chance + * to check for an idle child. + */ + TALLOC_FREE(state->queue_entry); } static void wb_domain_request_done(struct tevent_req *subreq) @@ -510,6 +617,8 @@ static void wb_domain_request_done(struct tevent_req *subreq) req, struct wb_domain_request_state); int ret, err; + state->pending_subreq = NULL; + ret = wb_child_request_recv(subreq, talloc_tos(), &state->response, &err); TALLOC_FREE(subreq); diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 78f526cdea8..73e6b76ec73 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->queue = tevent_queue_create(domain, "winbind_domain"); + if (domain->queue == NULL) { + TALLOC_FREE(domain); + return NT_STATUS_NO_MEMORY; + } + domain->binding_handle = wbint_binding_handle(domain, domain, NULL); if (domain->binding_handle == NULL) { TALLOC_FREE(domain); -- 2.13.6