s4:librpc/rpc: let dcerpc_ship_next_request() use DCERPC_AUTH_PAD_ALIGNMENT define
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob911fd7565b6c080fa0cfd5ed8882dcd02e70f42b
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_wbint.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "idmap.h"
31 #include "../libcli/security/security.h"
33 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
35 *r->out.out_data = r->in.in_data;
38 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
39 NTSTATUS status)
41 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42 invalidate_cm_connection(&domain->conn);
43 /* We invalidated the connection. */
44 return true;
46 return false;
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
51 struct winbindd_domain *domain = wb_child_domain();
52 char *dom_name;
53 char *name;
54 enum lsa_SidType type;
55 NTSTATUS status;
57 if (domain == NULL) {
58 return NT_STATUS_REQUEST_NOT_ACCEPTED;
61 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
62 &dom_name, &name, &type);
63 reset_cm_connection_on_error(domain, status);
64 if (!NT_STATUS_IS_OK(status)) {
65 return status;
68 *r->out.domain = dom_name;
69 *r->out.name = name;
70 *r->out.type = type;
71 return NT_STATUS_OK;
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
76 struct winbindd_domain *domain = wb_child_domain();
77 struct lsa_RefDomainList *domains = r->out.domains;
78 NTSTATUS status;
80 if (domain == NULL) {
81 return NT_STATUS_REQUEST_NOT_ACCEPTED;
85 * This breaks the winbindd_domain->methods abstraction: This
86 * is only called for remote domains, and both winbindd_msrpc
87 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
88 * done at the wbint RPC layer.
90 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
91 &domains, &r->out.names);
93 if (domains != NULL) {
94 r->out.domains = domains;
97 reset_cm_connection_on_error(domain, status);
98 return status;
101 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
103 struct winbindd_domain *domain = wb_child_domain();
104 NTSTATUS status;
106 if (domain == NULL) {
107 return NT_STATUS_REQUEST_NOT_ACCEPTED;
110 status = domain->methods->name_to_sid(
111 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
112 r->out.sid, r->out.type);
113 reset_cm_connection_on_error(domain, status);
114 return status;
117 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
118 struct wbint_Sids2UnixIDs *r)
120 uint32_t i, j;
121 struct id_map *ids = NULL;
122 struct id_map **id_ptrs = NULL;
123 struct dom_sid *sids = NULL;
124 uint32_t *id_idx = NULL;
125 NTSTATUS status = NT_STATUS_NO_MEMORY;
127 for (i=0; i<r->in.domains->count; i++) {
128 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
129 struct idmap_domain *dom;
130 uint32_t num_ids;
132 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
133 if (dom == NULL) {
134 DEBUG(10, ("idmap domain %s:%s not found\n",
135 d->name.string, sid_string_dbg(d->sid)));
136 continue;
139 num_ids = 0;
141 for (j=0; j<r->in.ids->num_ids; j++) {
142 if (r->in.ids->ids[j].domain_index == i) {
143 num_ids += 1;
147 ids = talloc_realloc(talloc_tos(), ids,
148 struct id_map, num_ids);
149 if (ids == NULL) {
150 goto nomem;
152 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
153 struct id_map *, num_ids+1);
154 if (id_ptrs == NULL) {
155 goto nomem;
157 id_idx = talloc_realloc(talloc_tos(), id_idx,
158 uint32_t, num_ids);
159 if (id_idx == NULL) {
160 goto nomem;
162 sids = talloc_realloc(talloc_tos(), sids,
163 struct dom_sid, num_ids);
164 if (sids == NULL) {
165 goto nomem;
168 num_ids = 0;
171 * Convert the input data into a list of
172 * id_map structs suitable for handing in
173 * to the idmap sids_to_unixids method.
175 for (j=0; j<r->in.ids->num_ids; j++) {
176 struct wbint_TransID *id = &r->in.ids->ids[j];
178 if (id->domain_index != i) {
179 continue;
181 id_idx[num_ids] = j;
182 id_ptrs[num_ids] = &ids[num_ids];
184 ids[num_ids].sid = &sids[num_ids];
185 sid_compose(ids[num_ids].sid, d->sid, id->rid);
186 ids[num_ids].xid.type = id->type;
187 ids[num_ids].status = ID_UNKNOWN;
188 num_ids += 1;
190 id_ptrs[num_ids] = NULL;
192 status = dom->methods->sids_to_unixids(dom, id_ptrs);
193 DEBUG(10, ("sids_to_unixids returned %s\n",
194 nt_errstr(status)));
197 * Extract the results for handing them back to the caller.
199 for (j=0; j<num_ids; j++) {
200 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
202 if (ids[j].status != ID_MAPPED) {
203 id->xid.id = UINT32_MAX;
204 id->xid.type = ID_TYPE_NOT_SPECIFIED;
205 continue;
208 id->xid = ids[j].xid;
211 status = NT_STATUS_OK;
212 nomem:
213 TALLOC_FREE(ids);
214 TALLOC_FREE(id_ptrs);
215 TALLOC_FREE(id_idx);
216 TALLOC_FREE(sids);
217 return status;
220 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
222 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
223 r->out.sid, r->in.uid);
226 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
228 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
229 r->out.sid, r->in.gid);
232 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
234 struct unixid xid;
235 NTSTATUS status;
237 status = idmap_allocate_uid(&xid);
238 if (!NT_STATUS_IS_OK(status)) {
239 return status;
241 *r->out.uid = xid.id;
242 return NT_STATUS_OK;
245 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
247 struct unixid xid;
248 NTSTATUS status;
250 status = idmap_allocate_gid(&xid);
251 if (!NT_STATUS_IS_OK(status)) {
252 return status;
254 *r->out.gid = xid.id;
255 return NT_STATUS_OK;
258 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
260 struct winbindd_domain *domain = wb_child_domain();
261 NTSTATUS status;
263 if (domain == NULL) {
264 return NT_STATUS_REQUEST_NOT_ACCEPTED;
267 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
268 r->out.info);
269 reset_cm_connection_on_error(domain, status);
270 return status;
273 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
274 struct wbint_LookupUserAliases *r)
276 struct winbindd_domain *domain = wb_child_domain();
277 NTSTATUS status;
279 if (domain == NULL) {
280 return NT_STATUS_REQUEST_NOT_ACCEPTED;
283 status = domain->methods->lookup_useraliases(
284 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
285 &r->out.rids->num_rids, &r->out.rids->rids);
286 reset_cm_connection_on_error(domain, status);
287 return status;
290 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
291 struct wbint_LookupUserGroups *r)
293 struct winbindd_domain *domain = wb_child_domain();
294 NTSTATUS status;
296 if (domain == NULL) {
297 return NT_STATUS_REQUEST_NOT_ACCEPTED;
300 status = domain->methods->lookup_usergroups(
301 domain, p->mem_ctx, r->in.sid,
302 &r->out.sids->num_sids, &r->out.sids->sids);
303 reset_cm_connection_on_error(domain, status);
304 return status;
307 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
308 struct wbint_QuerySequenceNumber *r)
310 struct winbindd_domain *domain = wb_child_domain();
311 NTSTATUS status;
313 if (domain == NULL) {
314 return NT_STATUS_REQUEST_NOT_ACCEPTED;
317 status = domain->methods->sequence_number(domain, r->out.sequence);
318 reset_cm_connection_on_error(domain, status);
319 return status;
322 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
323 struct wbint_LookupGroupMembers *r)
325 struct winbindd_domain *domain = wb_child_domain();
326 uint32_t i, num_names;
327 struct dom_sid *sid_mem;
328 char **names;
329 uint32_t *name_types;
330 NTSTATUS status;
332 if (domain == NULL) {
333 return NT_STATUS_REQUEST_NOT_ACCEPTED;
336 status = domain->methods->lookup_groupmem(
337 domain, p->mem_ctx, r->in.sid, r->in.type,
338 &num_names, &sid_mem, &names, &name_types);
339 reset_cm_connection_on_error(domain, status);
340 if (!NT_STATUS_IS_OK(status)) {
341 return status;
344 r->out.members->num_principals = num_names;
345 r->out.members->principals = talloc_array(
346 r->out.members, struct wbint_Principal, num_names);
347 if (r->out.members->principals == NULL) {
348 return NT_STATUS_NO_MEMORY;
351 for (i=0; i<num_names; i++) {
352 struct wbint_Principal *m = &r->out.members->principals[i];
353 sid_copy(&m->sid, &sid_mem[i]);
354 m->name = talloc_move(r->out.members->principals, &names[i]);
355 m->type = (enum lsa_SidType)name_types[i];
358 return NT_STATUS_OK;
361 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
362 struct wbint_QueryUserList *r)
364 struct winbindd_domain *domain = wb_child_domain();
365 NTSTATUS status;
367 if (domain == NULL) {
368 return NT_STATUS_REQUEST_NOT_ACCEPTED;
371 status = domain->methods->query_user_list(
372 domain, p->mem_ctx, &r->out.users->num_userinfos,
373 &r->out.users->userinfos);
374 reset_cm_connection_on_error(domain, status);
375 return status;
378 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
379 struct wbint_QueryGroupList *r)
381 struct winbindd_domain *domain = wb_child_domain();
382 uint32_t i, num_groups;
383 struct wb_acct_info *groups;
384 struct wbint_Principal *result;
385 NTSTATUS status;
387 if (domain == NULL) {
388 return NT_STATUS_REQUEST_NOT_ACCEPTED;
391 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
392 &num_groups, &groups);
393 reset_cm_connection_on_error(domain, status);
394 if (!NT_STATUS_IS_OK(status)) {
395 return status;
398 result = talloc_array(r->out.groups, struct wbint_Principal,
399 num_groups);
400 if (result == NULL) {
401 return NT_STATUS_NO_MEMORY;
404 for (i=0; i<num_groups; i++) {
405 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
406 result[i].type = SID_NAME_DOM_GRP;
407 result[i].name = talloc_strdup(result, groups[i].acct_name);
408 if (result[i].name == NULL) {
409 TALLOC_FREE(result);
410 TALLOC_FREE(groups);
411 return NT_STATUS_NO_MEMORY;
415 r->out.groups->num_principals = num_groups;
416 r->out.groups->principals = result;
418 TALLOC_FREE(groups);
419 return NT_STATUS_OK;
422 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
424 struct winbindd_domain *domain = wb_child_domain();
425 struct rpc_pipe_client *netlogon_pipe;
426 struct netr_DsRGetDCNameInfo *dc_info;
427 NTSTATUS status;
428 WERROR werr;
429 unsigned int orig_timeout;
430 struct dcerpc_binding_handle *b;
432 if (domain == NULL) {
433 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
434 r->in.domain_name, r->in.domain_guid,
435 r->in.site_name ? r->in.site_name : "",
436 r->in.flags,
437 r->out.dc_info);
440 status = cm_connect_netlogon(domain, &netlogon_pipe);
442 reset_cm_connection_on_error(domain, status);
443 if (!NT_STATUS_IS_OK(status)) {
444 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
445 return status;
448 b = netlogon_pipe->binding_handle;
450 /* This call can take a long time - allow the server to time out.
451 35 seconds should do it. */
453 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
455 if (domain->active_directory) {
456 status = dcerpc_netr_DsRGetDCName(b,
457 p->mem_ctx, domain->dcname,
458 r->in.domain_name, NULL, r->in.domain_guid,
459 r->in.flags, r->out.dc_info, &werr);
460 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
461 goto done;
463 if (reset_cm_connection_on_error(domain, status)) {
464 /* Re-initialize. */
465 status = cm_connect_netlogon(domain, &netlogon_pipe);
467 reset_cm_connection_on_error(domain, status);
468 if (!NT_STATUS_IS_OK(status)) {
469 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
470 return status;
473 b = netlogon_pipe->binding_handle;
475 /* This call can take a long time - allow the server to time out.
476 35 seconds should do it. */
478 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
483 * Fallback to less capable methods
486 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
487 if (dc_info == NULL) {
488 status = NT_STATUS_NO_MEMORY;
489 goto done;
492 if (r->in.flags & DS_PDC_REQUIRED) {
493 status = dcerpc_netr_GetDcName(b,
494 p->mem_ctx, domain->dcname,
495 r->in.domain_name, &dc_info->dc_unc, &werr);
496 } else {
497 status = dcerpc_netr_GetAnyDCName(b,
498 p->mem_ctx, domain->dcname,
499 r->in.domain_name, &dc_info->dc_unc, &werr);
502 reset_cm_connection_on_error(domain, status);
503 if (!NT_STATUS_IS_OK(status)) {
504 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
505 nt_errstr(status)));
506 goto done;
508 if (!W_ERROR_IS_OK(werr)) {
509 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
510 win_errstr(werr)));
511 status = werror_to_ntstatus(werr);
512 goto done;
515 *r->out.dc_info = dc_info;
516 status = NT_STATUS_OK;
518 done:
519 /* And restore our original timeout. */
520 rpccli_set_timeout(netlogon_pipe, orig_timeout);
522 return status;
525 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
527 struct winbindd_domain *domain = wb_child_domain();
528 char *domain_name;
529 char **names;
530 enum lsa_SidType *types;
531 struct wbint_Principal *result;
532 NTSTATUS status;
533 int i;
535 if (domain == NULL) {
536 return NT_STATUS_REQUEST_NOT_ACCEPTED;
539 status = domain->methods->rids_to_names(
540 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
541 r->in.rids->num_rids, &domain_name, &names, &types);
542 reset_cm_connection_on_error(domain, status);
543 if (!NT_STATUS_IS_OK(status)) {
544 return status;
547 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
549 result = talloc_array(p->mem_ctx, struct wbint_Principal,
550 r->in.rids->num_rids);
551 if (result == NULL) {
552 return NT_STATUS_NO_MEMORY;
555 for (i=0; i<r->in.rids->num_rids; i++) {
556 sid_compose(&result[i].sid, r->in.domain_sid,
557 r->in.rids->rids[i]);
558 result[i].type = types[i];
559 result[i].name = talloc_move(result, &names[i]);
561 TALLOC_FREE(types);
562 TALLOC_FREE(names);
564 r->out.names->num_principals = r->in.rids->num_rids;
565 r->out.names->principals = result;
566 return NT_STATUS_OK;
569 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
570 struct wbint_CheckMachineAccount *r)
572 struct winbindd_domain *domain;
573 int num_retries = 0;
574 NTSTATUS status;
576 domain = wb_child_domain();
577 if (domain == NULL) {
578 return NT_STATUS_REQUEST_NOT_ACCEPTED;
581 again:
582 invalidate_cm_connection(&domain->conn);
585 struct rpc_pipe_client *netlogon_pipe;
586 status = cm_connect_netlogon(domain, &netlogon_pipe);
589 /* There is a race condition between fetching the trust account
590 password and the periodic machine password change. So it's
591 possible that the trust account password has been changed on us.
592 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
594 #define MAX_RETRIES 3
596 if ((num_retries < MAX_RETRIES)
597 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
598 num_retries++;
599 goto again;
602 if (!NT_STATUS_IS_OK(status)) {
603 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
604 goto done;
607 /* Pass back result code - zero for success, other values for
608 specific failures. */
610 DEBUG(3,("domain %s secret is %s\n", domain->name,
611 NT_STATUS_IS_OK(status) ? "good" : "bad"));
613 done:
614 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
615 ("Checking the trust account password for domain %s returned %s\n",
616 domain->name, nt_errstr(status)));
618 return status;
621 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
622 struct wbint_ChangeMachineAccount *r)
624 struct winbindd_domain *domain;
625 int num_retries = 0;
626 NTSTATUS status;
627 struct rpc_pipe_client *netlogon_pipe;
628 TALLOC_CTX *tmp_ctx;
630 again:
631 domain = wb_child_domain();
632 if (domain == NULL) {
633 return NT_STATUS_REQUEST_NOT_ACCEPTED;
636 invalidate_cm_connection(&domain->conn);
639 status = cm_connect_netlogon(domain, &netlogon_pipe);
642 /* There is a race condition between fetching the trust account
643 password and the periodic machine password change. So it's
644 possible that the trust account password has been changed on us.
645 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
647 #define MAX_RETRIES 3
649 if ((num_retries < MAX_RETRIES)
650 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
651 num_retries++;
652 goto again;
655 if (!NT_STATUS_IS_OK(status)) {
656 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
657 goto done;
660 tmp_ctx = talloc_new(p->mem_ctx);
662 status = trust_pw_find_change_and_store_it(netlogon_pipe,
663 tmp_ctx,
664 domain->name);
665 talloc_destroy(tmp_ctx);
667 /* Pass back result code - zero for success, other values for
668 specific failures. */
670 DEBUG(3,("domain %s secret %s\n", domain->name,
671 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
673 done:
674 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
675 ("Changing the trust account password for domain %s returned %s\n",
676 domain->name, nt_errstr(status)));
678 return status;
681 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
683 NTSTATUS status;
684 struct winbindd_domain *domain;
685 struct rpc_pipe_client *netlogon_pipe;
686 union netr_CONTROL_QUERY_INFORMATION info;
687 WERROR werr;
688 fstring logon_server;
689 struct dcerpc_binding_handle *b;
690 bool retry = false;
692 domain = wb_child_domain();
693 if (domain == NULL) {
694 return NT_STATUS_REQUEST_NOT_ACCEPTED;
697 reconnect:
698 status = cm_connect_netlogon(domain, &netlogon_pipe);
699 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
701 * Retry to open new connection with new kerberos ticket.
703 invalidate_cm_connection(&domain->conn);
704 status = cm_connect_netlogon(domain, &netlogon_pipe);
707 reset_cm_connection_on_error(domain, status);
708 if (!NT_STATUS_IS_OK(status)) {
709 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
710 nt_errstr(status)));
711 return status;
714 b = netlogon_pipe->binding_handle;
716 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
717 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
718 if (*r->out.dcname == NULL) {
719 DEBUG(2, ("Could not allocate memory\n"));
720 return NT_STATUS_NO_MEMORY;
724 * This provokes a WERR_NOT_SUPPORTED error message. This is
725 * documented in the wspp docs. I could not get a successful
726 * call to work, but the main point here is testing that the
727 * netlogon pipe works.
729 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
730 logon_server, NETLOGON_CONTROL_QUERY,
731 2, &info, &werr);
733 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR) && !retry) {
734 DEBUG(10, ("Session might have expired. "
735 "Reconnect and retry once.\n"));
736 invalidate_cm_connection(&domain->conn);
737 retry = true;
738 goto reconnect;
741 reset_cm_connection_on_error(domain, status);
742 if (!NT_STATUS_IS_OK(status)) {
743 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
744 nt_errstr(status)));
745 return status;
748 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
749 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
750 "WERR_NOT_SUPPORTED\n",
751 win_errstr(werr)));
752 return werror_to_ntstatus(werr);
755 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
756 return NT_STATUS_OK;