Skip to content

Commit

Permalink
s3:winbind: Convert ListTrustedDomains parent/child call to NDR
Browse files Browse the repository at this point in the history
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 <scabrero@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
  • Loading branch information
Samuel Cabrero authored and abartlet committed Mar 6, 2022
1 parent d05b536 commit e07f890
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 172 deletions.
4 changes: 2 additions & 2 deletions librpc/idl/netlogon.idl
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions librpc/idl/winbind.idl
Expand Up @@ -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;
Expand Down
4 changes: 0 additions & 4 deletions source3/winbindd/winbindd_domain.c
Expand Up @@ -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,
Expand Down
88 changes: 52 additions & 36 deletions source3/winbindd/winbindd_dual_srv.c
Expand Up @@ -1927,69 +1927,85 @@ 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; i<trusts.count; i++) {
struct dom_sid_buf buf;
r->out.domains = out;

for (i=0; i<trusts.count; i++) {
if (trusts.array[i].sid == NULL) {
continue;
}
if (dom_sid_equal(trusts.array[i].sid, &global_sid_NULL)) {
continue;
}

extra_data = talloc_asprintf_append_buffer(
extra_data, "%s\\%s\\%s\\%u\\%u\\%u\n",
trusts.array[i].netbios_name, trusts.array[i].dns_name,
dom_sid_str_buf(trusts.array[i].sid, &buf),
trusts.array[i].trust_flags,
(uint32_t)trusts.array[i].trust_type,
trusts.array[i].trust_attributes);
}

/* add our primary domain */
n = out->count;
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; i<trusts.count; i++) {
if (strequal(trusts.array[i].netbios_name, domain->name)) {
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"
2 changes: 0 additions & 2 deletions source3/winbindd/winbindd_proto.h
Expand Up @@ -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);
Expand Down
159 changes: 31 additions & 128 deletions source3/winbindd/winbindd_util.c
Expand Up @@ -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);
Expand All @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -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; i<state->trusts.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;
}

/*
Expand All @@ -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);
Expand All @@ -575,8 +480,6 @@ static void trustdom_list_done(struct tevent_req *req)
nt_errstr(status));
return;
}

p = q + strlen(q) + 1;
}

/*
Expand Down

0 comments on commit e07f890

Please sign in to comment.