From 9fd05848d4a59db3977ae74f1a7a89f63f22b9ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 11 Oct 2024 13:32:22 +0000 Subject: [PATCH 1/3] s3:libsmb: let discover_dc_netbios() return DOMAIN_CONTROLLER_NOT_FOUND We may get NT_STATUS_NOT_FOUND when the name can't be resolved and NT_STATUS_INVALID_ADDRESS if the system doesn't have ipv4 addresses... Signed-off-by: Stefan Metzmacher Reviewed-by: Andreas Schneider (cherry picked from commit e47ce1d10b13d8ef165c70984e6e490f4c2a64c2) --- source3/libsmb/dsgetdcname.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/dsgetdcname.c b/source3/libsmb/dsgetdcname.c index 654893c172c..00e1fac6b93 100644 --- a/source3/libsmb/dsgetdcname.c +++ b/source3/libsmb/dsgetdcname.c @@ -483,7 +483,19 @@ static NTSTATUS discover_dc_netbios(TALLOC_CTX *mem_ctx, &count, resolve_order); if (!NT_STATUS_IS_OK(status)) { - DEBUG(10,("discover_dc_netbios: failed to find DC\n")); + NTSTATUS raw_status = status; + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) { + status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + } + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_ADDRESS)) { + status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; + } + + DBG_DEBUG("failed to find DC for %s: %s => %s\n", + domain_name, + nt_errstr(raw_status), + nt_errstr(status)); return status; } -- 2.47.2 From 4108b021383ccad766a571c93bd6d5fafc4e7b80 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 May 2025 09:38:41 +0200 Subject: [PATCH 2/3] s3:winbindd: avoid using any netlogon call to get a dc name BUG: https://bugzilla.samba.org/show_bug.cgi?id=15876 Signed-off-by: Stefan Metzmacher Reviewed-by: Guenther Deschner Reviewed-by: Andreas Schneider Reviewed-by: Ralph Boehme (backported from commit f86a4bf6848ade2db7229d182576db3320c3ece7) --- source3/winbindd/winbindd_cm.c | 145 --------------------------- source3/winbindd/winbindd_dual_srv.c | 105 +------------------ 2 files changed, 5 insertions(+), 245 deletions(-) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 1685edbabaa..28ebc15ddf9 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -475,135 +475,6 @@ static bool cm_is_ipc_credentials(struct cli_credentials *creds) return ret; } -static bool get_dc_name_via_netlogon(struct winbindd_domain *domain, - fstring dcname, - struct sockaddr_storage *dc_ss, - uint32_t request_flags) -{ - struct winbindd_domain *our_domain = NULL; - struct rpc_pipe_client *netlogon_pipe = NULL; - NTSTATUS result; - WERROR werr; - TALLOC_CTX *mem_ctx; - unsigned int orig_timeout; - const char *tmp = NULL; - const char *p; - struct dcerpc_binding_handle *b; - - /* Hmmmm. We can only open one connection to the NETLOGON pipe at the - * moment.... */ - - if (IS_DC) { - return False; - } - - if (domain->primary) { - return False; - } - - our_domain = find_our_domain(); - - if ((mem_ctx = talloc_init("get_dc_name_via_netlogon")) == NULL) { - return False; - } - - result = cm_connect_netlogon(our_domain, &netlogon_pipe); - if (!NT_STATUS_IS_OK(result)) { - talloc_destroy(mem_ctx); - return False; - } - - b = netlogon_pipe->binding_handle; - - /* This call can take a long time - allow the server to time out. - 35 seconds should do it. */ - - orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000); - - if (our_domain->active_directory) { - struct netr_DsRGetDCNameInfo *domain_info = NULL; - - /* - * TODO request flags are not respected in the server - * (and in some cases, like REQUIRE_PDC, causes an error) - */ - result = dcerpc_netr_DsRGetDCName(b, - mem_ctx, - our_domain->dcname, - domain->name, - NULL, - NULL, - request_flags|DS_RETURN_DNS_NAME, - &domain_info, - &werr); - if (NT_STATUS_IS_OK(result) && W_ERROR_IS_OK(werr)) { - tmp = talloc_strdup( - mem_ctx, domain_info->dc_unc); - if (tmp == NULL) { - DEBUG(0, ("talloc_strdup failed\n")); - talloc_destroy(mem_ctx); - return false; - } - if (domain->alt_name == NULL) { - domain->alt_name = talloc_strdup(domain, - domain_info->domain_name); - if (domain->alt_name == NULL) { - DEBUG(0, ("talloc_strdup failed\n")); - talloc_destroy(mem_ctx); - return false; - } - } - if (domain->forest_name == NULL) { - domain->forest_name = talloc_strdup(domain, - domain_info->forest_name); - if (domain->forest_name == NULL) { - DEBUG(0, ("talloc_strdup failed\n")); - talloc_destroy(mem_ctx); - return false; - } - } - } - } else { - result = dcerpc_netr_GetAnyDCName(b, mem_ctx, - our_domain->dcname, - domain->name, - &tmp, - &werr); - } - - /* And restore our original timeout. */ - rpccli_set_timeout(netlogon_pipe, orig_timeout); - - if (!NT_STATUS_IS_OK(result)) { - DEBUG(10,("dcerpc_netr_GetAnyDCName failed: %s\n", - nt_errstr(result))); - talloc_destroy(mem_ctx); - return false; - } - - if (!W_ERROR_IS_OK(werr)) { - DEBUG(10,("dcerpc_netr_GetAnyDCName failed: %s\n", - win_errstr(werr))); - talloc_destroy(mem_ctx); - return false; - } - - /* dcerpc_netr_GetAnyDCName gives us a name with \\ */ - p = strip_hostname(tmp); - - fstrcpy(dcname, p); - - talloc_destroy(mem_ctx); - - DEBUG(10,("dcerpc_netr_GetAnyDCName returned %s\n", dcname)); - - if (!resolve_name(dcname, dc_ss, 0x20, true)) { - return False; - } - - return True; -} - /** * Helper function to assemble trust password and account name */ @@ -1283,24 +1154,8 @@ static bool get_dcs(TALLOC_CTX *mem_ctx, struct winbindd_domain *domain, struct samba_sockaddr *sa_list = NULL; size_t salist_size = 0; size_t i; - bool is_our_domain; enum security_types sec = (enum security_types)lp_security(); - is_our_domain = strequal(domain->name, lp_workgroup()); - - /* If not our domain, get the preferred DC, by asking our primary DC */ - if ( !is_our_domain - && get_dc_name_via_netlogon(domain, dcname, &ss, request_flags) - && add_one_dc_unique(mem_ctx, domain->name, dcname, &ss, dcs, - num_dcs) ) - { - char addr[INET6_ADDRSTRLEN]; - print_sockaddr(addr, sizeof(addr), &ss); - DEBUG(10, ("Retrieved DC %s at %s via netlogon\n", - dcname, addr)); - return True; - } - if ((sec == SEC_ADS) && (domain->alt_name != NULL)) { char *sitename = NULL; diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index bbdaf6e5807..0d9d88733da 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -662,106 +662,11 @@ NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p, NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r) { - struct winbindd_domain *domain = wb_child_domain(); - struct rpc_pipe_client *netlogon_pipe; - struct netr_DsRGetDCNameInfo *dc_info; - NTSTATUS status; - WERROR werr; - unsigned int orig_timeout; - struct dcerpc_binding_handle *b; - bool retry = false; - bool try_dsrgetdcname = false; - - if (domain == NULL) { - return dsgetdcname(p->mem_ctx, global_messaging_context(), - r->in.domain_name, r->in.domain_guid, - r->in.site_name ? r->in.site_name : "", - r->in.flags, - r->out.dc_info); - } - - if (domain->active_directory) { - try_dsrgetdcname = true; - } - -reconnect: - status = cm_connect_netlogon(domain, &netlogon_pipe); - - reset_cm_connection_on_error(domain, NULL, status); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("Can't contact the NETLOGON pipe\n")); - return status; - } - - b = netlogon_pipe->binding_handle; - - /* This call can take a long time - allow the server to time out. - 35 seconds should do it. */ - - orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000); - - if (try_dsrgetdcname) { - status = dcerpc_netr_DsRGetDCName(b, - p->mem_ctx, domain->dcname, - r->in.domain_name, NULL, r->in.domain_guid, - r->in.flags, r->out.dc_info, &werr); - if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) { - goto done; - } - if (!retry && - reset_cm_connection_on_error(domain, NULL, status)) - { - retry = true; - goto reconnect; - } - try_dsrgetdcname = false; - retry = false; - } - - /* - * Fallback to less capable methods - */ - - dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo); - if (dc_info == NULL) { - status = NT_STATUS_NO_MEMORY; - goto done; - } - - if (r->in.flags & DS_PDC_REQUIRED) { - status = dcerpc_netr_GetDcName(b, - p->mem_ctx, domain->dcname, - r->in.domain_name, &dc_info->dc_unc, &werr); - } else { - status = dcerpc_netr_GetAnyDCName(b, - p->mem_ctx, domain->dcname, - r->in.domain_name, &dc_info->dc_unc, &werr); - } - - if (!retry && reset_cm_connection_on_error(domain, b, status)) { - retry = true; - goto reconnect; - } - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n", - nt_errstr(status))); - goto done; - } - if (!W_ERROR_IS_OK(werr)) { - DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n", - win_errstr(werr))); - status = werror_to_ntstatus(werr); - goto done; - } - - *r->out.dc_info = dc_info; - status = NT_STATUS_OK; - -done: - /* And restore our original timeout. */ - rpccli_set_timeout(netlogon_pipe, orig_timeout); - - return status; + return dsgetdcname(p->mem_ctx, global_messaging_context(), + r->in.domain_name, r->in.domain_guid, + r->in.site_name ? r->in.site_name : "", + r->in.flags, + r->out.dc_info); } NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r) -- 2.47.2 From 41191db034ea7825acd01a0166cd2a8b425878ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Wed, 2 Jul 2025 21:59:48 +0200 Subject: [PATCH 3/3] s3-winbindd: Fix internal winbind dsgetdcname calls w.r.t. domain name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit when winbind calls to dsgetdcname internally, make sure to prefer the DNS domain name if we have it. Makes DNS lookups much more likely to succeed. BUG: https://bugzilla.samba.org/show_bug.cgi?id=15876 Guenther Signed-off-by: Guenther Deschner Reviewed-by: Andreas Schneider Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Mon Jul 7 10:44:37 UTC 2025 on atb-devel-224 (cherry picked from commit 2560c9b3224816ffd371a62103f65b3aca301ad5) --- source3/winbindd/wb_queryuser.c | 17 +++++++++++++---- source3/winbindd/wb_sids2xids.c | 17 +++++++++++++---- source3/winbindd/wb_xids2sids.c | 12 +++++++++--- source3/winbindd/winbindd_dual.c | 6 +++++- source3/winbindd/winbindd_proto.h | 1 + source3/winbindd/winbindd_util.c | 19 +++++++++++++++++++ 6 files changed, 60 insertions(+), 12 deletions(-) diff --git a/source3/winbindd/wb_queryuser.c b/source3/winbindd/wb_queryuser.c index c2758f1b76a..db8e946ba71 100644 --- a/source3/winbindd/wb_queryuser.c +++ b/source3/winbindd/wb_queryuser.c @@ -289,10 +289,19 @@ static void wb_queryuser_done(struct tevent_req *subreq) if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) && !state->tried_dclookup) { - D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling wb_dsgetdcname_send()\n"); - subreq = wb_dsgetdcname_send( - state, state->ev, state->info->domain_name, NULL, NULL, - DS_RETURN_DNS_NAME); + const char *domain_name = find_dns_domain_name( + state->info->domain_name); + + D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling " + "wb_dsgetdcname_send(%s)\n", + domain_name); + + subreq = wb_dsgetdcname_send(state, + state->ev, + domain_name, + NULL, + NULL, + DS_RETURN_DNS_NAME); if (tevent_req_nomem(subreq, req)) { return; } diff --git a/source3/winbindd/wb_sids2xids.c b/source3/winbindd/wb_sids2xids.c index f0f6c23fc20..03e5e7e0258 100644 --- a/source3/winbindd/wb_sids2xids.c +++ b/source3/winbindd/wb_sids2xids.c @@ -612,13 +612,22 @@ static void wb_sids2xids_done(struct tevent_req *subreq) !state->tried_dclookup) { struct lsa_DomainInfo *d; + const char *domain_name = NULL; - D_DEBUG("Domain controller not found. Calling wb_dsgetdcname_send() to get it.\n"); d = &state->idmap_doms.domains[state->dom_index]; - subreq = wb_dsgetdcname_send( - state, state->ev, d->name.string, NULL, NULL, - DS_RETURN_DNS_NAME); + domain_name = find_dns_domain_name(d->name.string); + + D_DEBUG("Domain controller not found. Calling " + "wb_dsgetdcname_send(%s) to get it.\n", + domain_name); + + subreq = wb_dsgetdcname_send(state, + state->ev, + domain_name, + NULL, + NULL, + DS_RETURN_DNS_NAME); if (tevent_req_nomem(subreq, req)) { return; } diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c index 86bd7f9deab..6fcf524d94f 100644 --- a/source3/winbindd/wb_xids2sids.c +++ b/source3/winbindd/wb_xids2sids.c @@ -143,9 +143,15 @@ static void wb_xids2sids_dom_done(struct tevent_req *subreq) if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) && !state->tried_dclookup) { - subreq = wb_dsgetdcname_send( - state, state->ev, state->dom_map->name, NULL, NULL, - DS_RETURN_DNS_NAME); + const char *domain_name = find_dns_domain_name( + state->dom_map->name); + + subreq = wb_dsgetdcname_send(state, + state->ev, + domain_name, + NULL, + NULL, + DS_RETURN_DNS_NAME); if (tevent_req_nomem(subreq, req)) { return; } diff --git a/source3/winbindd/winbindd_dual.c b/source3/winbindd/winbindd_dual.c index b8e1ceddecc..ee80a4725fa 100644 --- a/source3/winbindd/winbindd_dual.c +++ b/source3/winbindd/winbindd_dual.c @@ -532,6 +532,7 @@ static void wb_domain_request_trigger(struct tevent_req *req, struct wb_domain_request_state *state = tevent_req_data( req, struct wb_domain_request_state); struct winbindd_domain *domain = state->domain; + const char *domain_name = NULL; struct tevent_req *subreq = NULL; size_t shortest_queue_length; @@ -604,8 +605,11 @@ static void wb_domain_request_trigger(struct tevent_req *req, * which is indicated by DS_RETURN_DNS_NAME. * For NT4 domains we still get the netbios name. */ + + domain_name = find_dns_domain_name(state->domain->name); + subreq = wb_dsgetdcname_send(state, state->ev, - state->domain->name, + domain_name, NULL, /* domain_guid */ NULL, /* site_name */ DS_RETURN_DNS_NAME); /* flags */ diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 4dee9b046cf..292b96ee5fa 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -603,6 +603,7 @@ bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr, struct dom_sid **sids, uint32_t *num_sids); bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr, struct unixid **pxids, uint32_t *pnum_xids); +const char *find_dns_domain_name(const char *domain_name); /* The following definitions come from winbindd/winbindd_wins.c */ diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index 7527a78b30e..5c832fc22b5 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -2241,3 +2241,22 @@ fail: TALLOC_FREE(xids); return false; } + +/** + * Helper to extract the DNS Domain Name from a struct winbindd_domain + */ +const char *find_dns_domain_name(const char *domain_name) +{ + struct winbindd_domain *wbdom = NULL; + + wbdom = find_domain_from_name(domain_name); + if (wbdom == NULL) { + return domain_name; + } + + if (wbdom->active_directory && wbdom->alt_name != NULL) { + return wbdom->alt_name; + } + + return wbdom->name; +} -- 2.47.2