From e07f8901ec95aab8c36965000de185d99e642644 Mon Sep 17 00:00:00 2001 From: Samuel Cabrero Date: Fri, 4 Jun 2021 15:36:16 +0200 Subject: [PATCH] s3:winbind: Convert ListTrustedDomains parent/child call to NDR By using NDR we avoid manual marshalling (netr_DomainTrust array to text string) and unmarshalling (parse the received text string back to a netr_DomainTrust array). Signed-off-by: Samuel Cabrero Reviewed-by: Andrew Bartlett --- librpc/idl/netlogon.idl | 4 +- librpc/idl/winbind.idl | 6 + source3/winbindd/winbindd_domain.c | 4 - source3/winbindd/winbindd_dual_srv.c | 88 +++++++++------ source3/winbindd/winbindd_proto.h | 2 - source3/winbindd/winbindd_util.c | 159 ++++++--------------------- 6 files changed, 91 insertions(+), 172 deletions(-) diff --git a/librpc/idl/netlogon.idl b/librpc/idl/netlogon.idl index cbfc88fe0782..05c592be7e50 100644 --- a/librpc/idl/netlogon.idl +++ b/librpc/idl/netlogon.idl @@ -1598,7 +1598,7 @@ interface netlogon /****************/ /* Function 0x24 */ - typedef struct { + typedef [public] struct { [string,charset(UTF16)] uint16 *netbios_name; [string,charset(UTF16)] uint16 *dns_name; netr_TrustFlags trust_flags; @@ -1609,7 +1609,7 @@ interface netlogon GUID guid; } netr_DomainTrust; - typedef struct { + typedef [public] struct { uint32 count; [size_is(count)] netr_DomainTrust *array; } netr_DomainTrustList; diff --git a/librpc/idl/winbind.idl b/librpc/idl/winbind.idl index a2bc81a9333d..4acad1b091fd 100644 --- a/librpc/idl/winbind.idl +++ b/librpc/idl/winbind.idl @@ -168,6 +168,12 @@ interface winbind [out,string,charset(UTF8)] char **dcname ); + NTSTATUS wbint_ListTrustedDomains( + [in,string,charset(UTF8)] char *client_name, + [in] hyper client_pid, + [out,ref] netr_DomainTrustList *domains + ); + /* Public methods available via IRPC */ typedef [switch_type(uint16)] union netr_LogonLevel netr_LogonLevel; diff --git a/source3/winbindd/winbindd_domain.c b/source3/winbindd/winbindd_domain.c index e998275c8e2a..fdf5768c5263 100644 --- a/source3/winbindd/winbindd_domain.c +++ b/source3/winbindd/winbindd_domain.c @@ -30,10 +30,6 @@ static const struct winbindd_child_dispatch_table domain_dispatch_table[] = { .name = "PING", .struct_cmd = WINBINDD_PING, .struct_fn = winbindd_dual_ping, - },{ - .name = "LIST_TRUSTDOM", - .struct_cmd = WINBINDD_LIST_TRUSTDOM, - .struct_fn = winbindd_dual_list_trusted_domains, },{ .name = "INIT_CONNECTION", .struct_cmd = WINBINDD_INIT_CONNECTION, diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 511e93416b5c..3daa8468ddc0 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -1927,33 +1927,45 @@ NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r) return status; } -enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain, - struct winbindd_cli_state *state) +NTSTATUS _wbint_ListTrustedDomains(struct pipes_struct *p, + struct wbint_ListTrustedDomains *r) { - uint32_t i; - int extra_data_len = 0; - char *extra_data; + struct winbindd_domain *domain = wb_child_domain(); + uint32_t i, n; NTSTATUS result; - bool have_own_domain = False; struct netr_DomainTrustList trusts; + struct netr_DomainTrustList *out = NULL; + pid_t client_pid; - DBG_NOTICE("[%s %u]: list trusted domains\n", - state->client_name, - (unsigned int)state->pid); + if (domain == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } - result = wb_cache_trusted_domains(domain, state->mem_ctx, &trusts); + /* Cut client_pid to 32bit */ + client_pid = r->in.client_pid; + if ((uint64_t)client_pid != r->in.client_pid) { + DBG_DEBUG("pid out of range\n"); + return NT_STATUS_INVALID_PARAMETER; + } + + DBG_NOTICE("[%s %"PRIu32"]: list trusted domains\n", + r->in.client_name, client_pid); + result = wb_cache_trusted_domains(domain, p->mem_ctx, &trusts); if (!NT_STATUS_IS_OK(result)) { DBG_NOTICE("wb_cache_trusted_domains returned %s\n", nt_errstr(result)); - return WINBINDD_ERROR; + return result; } - extra_data = talloc_strdup(state->mem_ctx, ""); + out = talloc_zero(p->mem_ctx, struct netr_DomainTrustList); + if (out == NULL) { + return NT_STATUS_NO_MEMORY; + } - for (i=0; iout.domains = out; + for (i=0; icount; + out->array = talloc_realloc(out, out->array, + struct netr_DomainTrust, + n + 1); + if (out->array == NULL) { + return NT_STATUS_NO_MEMORY; + } + out->count = n + 1; - for (i=0; iname)) { - have_own_domain = True; - break; + out->array[n].netbios_name = talloc_steal( + out->array, trusts.array[i].netbios_name); + if (out->array[n].netbios_name == NULL) { + return NT_STATUS_NO_MEMORY; } - } - extra_data_len = strlen(extra_data); - if (extra_data_len > 0) { + out->array[n].dns_name = talloc_steal( + out->array, trusts.array[i].dns_name); + if (out->array[n].dns_name == NULL) { + return NT_STATUS_NO_MEMORY; + } - /* Strip the last \n */ - extra_data[extra_data_len-1] = '\0'; + out->array[n].sid = dom_sid_dup(out->array, + trusts.array[i].sid); + if (out->array[n].sid == NULL) { + return NT_STATUS_NO_MEMORY; + } - state->response->extra_data.data = extra_data; - state->response->length += extra_data_len; + out->array[n].trust_flags = trusts.array[i].trust_flags; + out->array[n].trust_type = trusts.array[i].trust_type; + out->array[n].trust_attributes = trusts.array[i].trust_attributes; } - return WINBINDD_OK; + return NT_STATUS_OK; } #include "librpc/gen_ndr/ndr_winbind_scompat.c" diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h index 16c23f3de401..b9b7be40245e 100644 --- a/source3/winbindd/winbindd_proto.h +++ b/source3/winbindd/winbindd_proto.h @@ -396,8 +396,6 @@ struct dcerpc_binding_handle *locator_child_handle(void); /* The following definitions come from winbindd/winbindd_misc.c */ bool winbindd_list_trusted_domains(struct winbindd_cli_state *state); -enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain, - struct winbindd_cli_state *state); bool winbindd_dc_info(struct winbindd_cli_state *state); bool winbindd_ping(struct winbindd_cli_state *state); bool winbindd_info(struct winbindd_cli_state *state); diff --git a/source3/winbindd/winbindd_util.c b/source3/winbindd/winbindd_util.c index bd9d36bb2483..53e7f32b5b98 100644 --- a/source3/winbindd/winbindd_util.c +++ b/source3/winbindd/winbindd_util.c @@ -376,7 +376,7 @@ bool domain_is_forest_root(const struct winbindd_domain *domain) struct trustdom_state { struct winbindd_domain *domain; - struct winbindd_request request; + struct netr_DomainTrustList trusts; }; static void trustdom_list_done(struct tevent_req *req); @@ -385,8 +385,11 @@ static void rescan_forest_trusts( void ); static void add_trusted_domains( struct winbindd_domain *domain ) { + struct tevent_context *ev = global_event_context(); struct trustdom_state *state; struct tevent_req *req; + const char *client_name = NULL; + pid_t client_pid; state = talloc_zero(NULL, struct trustdom_state); if (state == NULL) { @@ -395,13 +398,18 @@ static void add_trusted_domains( struct winbindd_domain *domain ) } state->domain = domain; - state->request.length = sizeof(state->request); - state->request.cmd = WINBINDD_LIST_TRUSTDOM; + /* Called from timer, not from a real client */ + client_name = getprogname(); + client_pid = getpid(); - req = wb_domain_request_send(state, global_event_context(), - domain, &state->request); + req = dcerpc_wbint_ListTrustedDomains_send(state, + ev, + dom_child_handle(domain), + client_name, + client_pid, + &state->trusts); if (req == NULL) { - DEBUG(1, ("wb_domain_request_send failed\n")); + DBG_ERR("dcerpc_wbint_ListTrustedDomains_send failed\n"); TALLOC_FREE(state); return; } @@ -412,12 +420,9 @@ static void trustdom_list_done(struct tevent_req *req) { struct trustdom_state *state = tevent_req_callback_data( req, struct trustdom_state); - struct winbindd_response *response; - int res, err; - char *p; - ptrdiff_t extra_len; bool within_forest = false; - NTSTATUS status; + NTSTATUS status, result; + uint32_t i; /* * Only when we enumerate our primary domain @@ -432,125 +437,25 @@ static void trustdom_list_done(struct tevent_req *req) within_forest = true; } - res = wb_domain_request_recv(req, state, &response, &err); - if ((res == -1) || (response->result != WINBINDD_OK)) { - DBG_WARNING("Could not receive trusts for domain %s\n", - state->domain->name); - TALLOC_FREE(state); - return; - } - - if (response->length < sizeof(struct winbindd_response)) { - DBG_ERR("ill-formed trustdom response - short length\n"); + status = dcerpc_wbint_ListTrustedDomains_recv(req, state, &result); + if (any_nt_status_not_ok(status, result, &status)) { + DBG_WARNING("Could not receive trusts for domain %s: %s-%s\n", + state->domain->name, nt_errstr(status), + nt_errstr(result)); TALLOC_FREE(state); return; } - extra_len = response->length - sizeof(struct winbindd_response); - - p = (char *)response->extra_data.data; - - while ((p - (char *)response->extra_data.data) < extra_len) { + for (i=0; itrusts.count; i++) { + struct netr_DomainTrust *trust = &state->trusts.array[i]; struct winbindd_domain *domain = NULL; - char *name, *q, *sidstr, *alt_name; - struct dom_sid sid; - uint32_t trust_type; - uint32_t trust_attribs; - uint32_t trust_flags; - int error = 0; - - DBG_DEBUG("parsing response line '%s'\n", p); - - name = p; - - alt_name = strchr(p, '\\'); - if (alt_name == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - *alt_name = '\0'; - alt_name += 1; - - sidstr = strchr(alt_name, '\\'); - if (sidstr == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - *sidstr = '\0'; - sidstr += 1; - - /* use the real alt_name if we have one, else pass in NULL */ - if (strequal(alt_name, "(null)")) { - alt_name = NULL; - } - - q = strtok(sidstr, "\\"); - if (q == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - if (!string_to_sid(&sid, sidstr)) { - DEBUG(0, ("Got invalid trustdom response\n")); - break; - } - - q = strtok(NULL, "\\"); - if (q == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - trust_flags = (uint32_t)smb_strtoul(q, - NULL, - 10, - &error, - SMB_STR_STANDARD); - if (error != 0) { - DBG_ERR("Failed to convert trust_flags\n"); - break; - } - - q = strtok(NULL, "\\"); - if (q == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - trust_type = (uint32_t)smb_strtoul(q, - NULL, - 10, - &error, - SMB_STR_STANDARD); - if (error != 0) { - DBG_ERR("Failed to convert trust_type\n"); - break; - } - - q = strtok(NULL, "\n"); - if (q == NULL) { - DBG_ERR("Got invalid trustdom response\n"); - break; - } - - trust_attribs = (uint32_t)smb_strtoul(q, - NULL, - 10, - &error, - SMB_STR_STANDARD); - if (error != 0) { - DBG_ERR("Failed to convert trust_attribs\n"); - break; - } if (!within_forest) { - trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST; + trust->trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST; } if (!state->domain->primary) { - trust_flags &= ~NETR_TRUST_FLAG_PRIMARY; + trust->trust_flags &= ~NETR_TRUST_FLAG_PRIMARY; } /* @@ -559,12 +464,12 @@ static void trustdom_list_done(struct tevent_req *req) * This is important because we need the SID for sibling * domains. */ - status = add_trusted_domain(name, - alt_name, - &sid, - trust_type, - trust_flags, - trust_attribs, + status = add_trusted_domain(trust->netbios_name, + trust->dns_name, + trust->sid, + trust->trust_type, + trust->trust_flags, + trust->trust_attributes, SEC_CHAN_NULL, find_default_route_domain(), &domain); @@ -575,8 +480,6 @@ static void trustdom_list_done(struct tevent_req *req) nt_errstr(status)); return; } - - p = q + strlen(q) + 1; } /*