s3:winbindd: also use idmap_passdb for own sam and builtin in wbint_Sids2UnixIDs()
[Samba/bb.git] / source3 / winbindd / winbindd_dual_srv.c
blob660008293d93784d0dcdc1a31e42f14794517704
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 NTSTATUS status;
79 if (domain == NULL) {
80 return NT_STATUS_REQUEST_NOT_ACCEPTED;
84 * This breaks the winbindd_domain->methods abstraction: This
85 * is only called for remote domains, and both winbindd_msrpc
86 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
87 * done at the wbint RPC layer.
89 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
90 &r->out.domains, &r->out.names);
91 reset_cm_connection_on_error(domain, status);
92 return status;
95 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
97 struct winbindd_domain *domain = wb_child_domain();
98 NTSTATUS status;
100 if (domain == NULL) {
101 return NT_STATUS_REQUEST_NOT_ACCEPTED;
104 status = domain->methods->name_to_sid(
105 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
106 r->out.sid, r->out.type);
107 reset_cm_connection_on_error(domain, status);
108 return status;
111 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
113 uid_t uid;
114 NTSTATUS status;
116 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
117 r->in.sid, &uid);
118 if (!NT_STATUS_IS_OK(status)) {
119 return status;
121 *r->out.uid = uid;
122 return NT_STATUS_OK;
125 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
127 gid_t gid;
128 NTSTATUS status;
130 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
131 r->in.sid, &gid);
132 if (!NT_STATUS_IS_OK(status)) {
133 return status;
135 *r->out.gid = gid;
136 return NT_STATUS_OK;
139 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
140 struct wbint_Sids2UnixIDs *r)
142 uint32_t i, j;
143 struct id_map *ids = NULL;
144 struct id_map **id_ptrs = NULL;
145 struct dom_sid *sids = NULL;
146 uint32_t *id_idx = NULL;
147 NTSTATUS status = NT_STATUS_NO_MEMORY;
149 for (i=0; i<r->in.domains->count; i++) {
150 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
151 struct idmap_domain *dom;
152 uint32_t num_ids;
154 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
155 if (dom == NULL) {
156 DEBUG(10, ("idmap domain %s:%s not found\n",
157 d->name.string, sid_string_dbg(d->sid)));
158 continue;
161 num_ids = 0;
163 for (j=0; j<r->in.ids->num_ids; j++) {
164 if (r->in.ids->ids[j].domain_index == i) {
165 num_ids += 1;
169 ids = talloc_realloc(talloc_tos(), ids,
170 struct id_map, num_ids);
171 if (ids == NULL) {
172 goto nomem;
174 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
175 struct id_map *, num_ids+1);
176 if (id_ptrs == NULL) {
177 goto nomem;
179 id_idx = talloc_realloc(talloc_tos(), id_idx,
180 uint32_t, num_ids);
181 if (id_idx == NULL) {
182 goto nomem;
184 sids = talloc_realloc(talloc_tos(), sids,
185 struct dom_sid, num_ids);
186 if (sids == NULL) {
187 goto nomem;
190 num_ids = 0;
193 * Convert the input data into a list of
194 * id_map structs suitable for handing in
195 * to the idmap sids_to_unixids method.
197 for (j=0; j<r->in.ids->num_ids; j++) {
198 struct wbint_TransID *id = &r->in.ids->ids[j];
200 if (id->domain_index != i) {
201 continue;
203 id_idx[num_ids] = j;
204 id_ptrs[num_ids] = &ids[num_ids];
206 ids[num_ids].sid = &sids[num_ids];
207 sid_compose(ids[num_ids].sid, d->sid, id->rid);
208 ids[num_ids].xid.type = id->type;
209 ids[num_ids].status = ID_UNKNOWN;
210 num_ids += 1;
212 id_ptrs[num_ids] = NULL;
214 status = dom->methods->sids_to_unixids(dom, id_ptrs);
215 DEBUG(10, ("sids_to_unixids returned %s\n",
216 nt_errstr(status)));
219 * Extract the results for handing them back to the caller.
221 for (j=0; j<num_ids; j++) {
222 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
224 if (ids[j].status != ID_MAPPED) {
225 id->xid.id = UINT32_MAX;
226 id->xid.type = ID_TYPE_NOT_SPECIFIED;
227 continue;
230 id->xid = ids[j].xid;
233 status = NT_STATUS_OK;
234 nomem:
235 TALLOC_FREE(ids);
236 TALLOC_FREE(id_ptrs);
237 TALLOC_FREE(id_idx);
238 TALLOC_FREE(sids);
239 return status;
242 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
244 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
245 r->out.sid, r->in.uid);
248 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
250 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
251 r->out.sid, r->in.gid);
254 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
256 struct unixid xid;
257 NTSTATUS status;
259 status = idmap_allocate_uid(&xid);
260 if (!NT_STATUS_IS_OK(status)) {
261 return status;
263 *r->out.uid = xid.id;
264 return NT_STATUS_OK;
267 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
269 struct unixid xid;
270 NTSTATUS status;
272 status = idmap_allocate_gid(&xid);
273 if (!NT_STATUS_IS_OK(status)) {
274 return status;
276 *r->out.gid = xid.id;
277 return NT_STATUS_OK;
280 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
282 struct winbindd_domain *domain = wb_child_domain();
283 NTSTATUS status;
285 if (domain == NULL) {
286 return NT_STATUS_REQUEST_NOT_ACCEPTED;
289 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
290 r->out.info);
291 reset_cm_connection_on_error(domain, status);
292 return status;
295 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
296 struct wbint_LookupUserAliases *r)
298 struct winbindd_domain *domain = wb_child_domain();
299 NTSTATUS status;
301 if (domain == NULL) {
302 return NT_STATUS_REQUEST_NOT_ACCEPTED;
305 status = domain->methods->lookup_useraliases(
306 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
307 &r->out.rids->num_rids, &r->out.rids->rids);
308 reset_cm_connection_on_error(domain, status);
309 return status;
312 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
313 struct wbint_LookupUserGroups *r)
315 struct winbindd_domain *domain = wb_child_domain();
316 NTSTATUS status;
318 if (domain == NULL) {
319 return NT_STATUS_REQUEST_NOT_ACCEPTED;
322 status = domain->methods->lookup_usergroups(
323 domain, p->mem_ctx, r->in.sid,
324 &r->out.sids->num_sids, &r->out.sids->sids);
325 reset_cm_connection_on_error(domain, status);
326 return status;
329 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
330 struct wbint_QuerySequenceNumber *r)
332 struct winbindd_domain *domain = wb_child_domain();
333 NTSTATUS status;
335 if (domain == NULL) {
336 return NT_STATUS_REQUEST_NOT_ACCEPTED;
339 status = domain->methods->sequence_number(domain, r->out.sequence);
340 reset_cm_connection_on_error(domain, status);
341 return status;
344 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
345 struct wbint_LookupGroupMembers *r)
347 struct winbindd_domain *domain = wb_child_domain();
348 uint32_t i, num_names;
349 struct dom_sid *sid_mem;
350 char **names;
351 uint32_t *name_types;
352 NTSTATUS status;
354 if (domain == NULL) {
355 return NT_STATUS_REQUEST_NOT_ACCEPTED;
358 status = domain->methods->lookup_groupmem(
359 domain, p->mem_ctx, r->in.sid, r->in.type,
360 &num_names, &sid_mem, &names, &name_types);
361 reset_cm_connection_on_error(domain, status);
362 if (!NT_STATUS_IS_OK(status)) {
363 return status;
366 r->out.members->num_principals = num_names;
367 r->out.members->principals = talloc_array(
368 r->out.members, struct wbint_Principal, num_names);
369 if (r->out.members->principals == NULL) {
370 return NT_STATUS_NO_MEMORY;
373 for (i=0; i<num_names; i++) {
374 struct wbint_Principal *m = &r->out.members->principals[i];
375 sid_copy(&m->sid, &sid_mem[i]);
376 m->name = talloc_move(r->out.members->principals, &names[i]);
377 m->type = (enum lsa_SidType)name_types[i];
380 return NT_STATUS_OK;
383 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
384 struct wbint_QueryUserList *r)
386 struct winbindd_domain *domain = wb_child_domain();
387 NTSTATUS status;
389 if (domain == NULL) {
390 return NT_STATUS_REQUEST_NOT_ACCEPTED;
393 status = domain->methods->query_user_list(
394 domain, p->mem_ctx, &r->out.users->num_userinfos,
395 &r->out.users->userinfos);
396 reset_cm_connection_on_error(domain, status);
397 return status;
400 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
401 struct wbint_QueryGroupList *r)
403 struct winbindd_domain *domain = wb_child_domain();
404 uint32_t i, num_groups;
405 struct wb_acct_info *groups;
406 struct wbint_Principal *result;
407 NTSTATUS status;
409 if (domain == NULL) {
410 return NT_STATUS_REQUEST_NOT_ACCEPTED;
413 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
414 &num_groups, &groups);
415 reset_cm_connection_on_error(domain, status);
416 if (!NT_STATUS_IS_OK(status)) {
417 return status;
420 result = talloc_array(r->out.groups, struct wbint_Principal,
421 num_groups);
422 if (result == NULL) {
423 return NT_STATUS_NO_MEMORY;
426 for (i=0; i<num_groups; i++) {
427 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
428 result[i].type = SID_NAME_DOM_GRP;
429 result[i].name = talloc_strdup(result, groups[i].acct_name);
430 if (result[i].name == NULL) {
431 TALLOC_FREE(result);
432 TALLOC_FREE(groups);
433 return NT_STATUS_NO_MEMORY;
437 r->out.groups->num_principals = num_groups;
438 r->out.groups->principals = result;
440 TALLOC_FREE(groups);
441 return NT_STATUS_OK;
444 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
446 struct winbindd_domain *domain = wb_child_domain();
447 struct rpc_pipe_client *netlogon_pipe;
448 struct netr_DsRGetDCNameInfo *dc_info;
449 NTSTATUS status;
450 WERROR werr;
451 unsigned int orig_timeout;
452 struct dcerpc_binding_handle *b;
454 if (domain == NULL) {
455 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
456 r->in.domain_name, r->in.domain_guid,
457 r->in.site_name ? r->in.site_name : "",
458 r->in.flags,
459 r->out.dc_info);
462 status = cm_connect_netlogon(domain, &netlogon_pipe);
464 reset_cm_connection_on_error(domain, status);
465 if (!NT_STATUS_IS_OK(status)) {
466 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
467 return status;
470 b = netlogon_pipe->binding_handle;
472 /* This call can take a long time - allow the server to time out.
473 35 seconds should do it. */
475 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
477 if (domain->active_directory) {
478 status = dcerpc_netr_DsRGetDCName(b,
479 p->mem_ctx, domain->dcname,
480 r->in.domain_name, NULL, r->in.domain_guid,
481 r->in.flags, r->out.dc_info, &werr);
482 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
483 goto done;
485 if (reset_cm_connection_on_error(domain, status)) {
486 /* Re-initialize. */
487 status = cm_connect_netlogon(domain, &netlogon_pipe);
489 reset_cm_connection_on_error(domain, status);
490 if (!NT_STATUS_IS_OK(status)) {
491 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
492 return status;
495 b = netlogon_pipe->binding_handle;
497 /* This call can take a long time - allow the server to time out.
498 35 seconds should do it. */
500 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
505 * Fallback to less capable methods
508 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
509 if (dc_info == NULL) {
510 status = NT_STATUS_NO_MEMORY;
511 goto done;
514 if (r->in.flags & DS_PDC_REQUIRED) {
515 status = dcerpc_netr_GetDcName(b,
516 p->mem_ctx, domain->dcname,
517 r->in.domain_name, &dc_info->dc_unc, &werr);
518 } else {
519 status = dcerpc_netr_GetAnyDCName(b,
520 p->mem_ctx, domain->dcname,
521 r->in.domain_name, &dc_info->dc_unc, &werr);
524 reset_cm_connection_on_error(domain, status);
525 if (!NT_STATUS_IS_OK(status)) {
526 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
527 nt_errstr(status)));
528 goto done;
530 if (!W_ERROR_IS_OK(werr)) {
531 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
532 win_errstr(werr)));
533 status = werror_to_ntstatus(werr);
534 goto done;
537 *r->out.dc_info = dc_info;
538 status = NT_STATUS_OK;
540 done:
541 /* And restore our original timeout. */
542 rpccli_set_timeout(netlogon_pipe, orig_timeout);
544 return status;
547 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
549 struct winbindd_domain *domain = wb_child_domain();
550 char *domain_name;
551 char **names;
552 enum lsa_SidType *types;
553 struct wbint_Principal *result;
554 NTSTATUS status;
555 int i;
557 if (domain == NULL) {
558 return NT_STATUS_REQUEST_NOT_ACCEPTED;
561 status = domain->methods->rids_to_names(
562 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
563 r->in.rids->num_rids, &domain_name, &names, &types);
564 reset_cm_connection_on_error(domain, status);
565 if (!NT_STATUS_IS_OK(status)) {
566 return status;
569 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
571 result = talloc_array(p->mem_ctx, struct wbint_Principal,
572 r->in.rids->num_rids);
573 if (result == NULL) {
574 return NT_STATUS_NO_MEMORY;
577 for (i=0; i<r->in.rids->num_rids; i++) {
578 sid_compose(&result[i].sid, r->in.domain_sid,
579 r->in.rids->rids[i]);
580 result[i].type = types[i];
581 result[i].name = talloc_move(result, &names[i]);
583 TALLOC_FREE(types);
584 TALLOC_FREE(names);
586 r->out.names->num_principals = r->in.rids->num_rids;
587 r->out.names->principals = result;
588 return NT_STATUS_OK;
591 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
592 struct wbint_CheckMachineAccount *r)
594 struct winbindd_domain *domain;
595 int num_retries = 0;
596 NTSTATUS status;
598 domain = wb_child_domain();
599 if (domain == NULL) {
600 return NT_STATUS_REQUEST_NOT_ACCEPTED;
603 again:
604 invalidate_cm_connection(&domain->conn);
607 struct rpc_pipe_client *netlogon_pipe;
608 status = cm_connect_netlogon(domain, &netlogon_pipe);
611 /* There is a race condition between fetching the trust account
612 password and the periodic machine password change. So it's
613 possible that the trust account password has been changed on us.
614 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
616 #define MAX_RETRIES 3
618 if ((num_retries < MAX_RETRIES)
619 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
620 num_retries++;
621 goto again;
624 if (!NT_STATUS_IS_OK(status)) {
625 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
626 goto done;
629 /* Pass back result code - zero for success, other values for
630 specific failures. */
632 DEBUG(3,("domain %s secret is %s\n", domain->name,
633 NT_STATUS_IS_OK(status) ? "good" : "bad"));
635 done:
636 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
637 ("Checking the trust account password for domain %s returned %s\n",
638 domain->name, nt_errstr(status)));
640 return status;
643 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
644 struct wbint_ChangeMachineAccount *r)
646 struct winbindd_domain *domain;
647 int num_retries = 0;
648 NTSTATUS status;
649 struct rpc_pipe_client *netlogon_pipe;
650 TALLOC_CTX *tmp_ctx;
652 again:
653 domain = wb_child_domain();
654 if (domain == NULL) {
655 return NT_STATUS_REQUEST_NOT_ACCEPTED;
658 invalidate_cm_connection(&domain->conn);
661 status = cm_connect_netlogon(domain, &netlogon_pipe);
664 /* There is a race condition between fetching the trust account
665 password and the periodic machine password change. So it's
666 possible that the trust account password has been changed on us.
667 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
669 #define MAX_RETRIES 3
671 if ((num_retries < MAX_RETRIES)
672 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
673 num_retries++;
674 goto again;
677 if (!NT_STATUS_IS_OK(status)) {
678 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
679 goto done;
682 tmp_ctx = talloc_new(p->mem_ctx);
684 status = trust_pw_find_change_and_store_it(netlogon_pipe,
685 tmp_ctx,
686 domain->name);
687 talloc_destroy(tmp_ctx);
689 /* Pass back result code - zero for success, other values for
690 specific failures. */
692 DEBUG(3,("domain %s secret %s\n", domain->name,
693 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
695 done:
696 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
697 ("Changing the trust account password for domain %s returned %s\n",
698 domain->name, nt_errstr(status)));
700 return status;
703 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
705 NTSTATUS status;
706 struct winbindd_domain *domain;
707 struct rpc_pipe_client *netlogon_pipe;
708 union netr_CONTROL_QUERY_INFORMATION info;
709 WERROR werr;
710 fstring logon_server;
711 struct dcerpc_binding_handle *b;
713 domain = wb_child_domain();
714 if (domain == NULL) {
715 return NT_STATUS_REQUEST_NOT_ACCEPTED;
718 status = cm_connect_netlogon(domain, &netlogon_pipe);
719 reset_cm_connection_on_error(domain, status);
720 if (!NT_STATUS_IS_OK(status)) {
721 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
722 return status;
725 b = netlogon_pipe->binding_handle;
727 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
728 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
729 if (r->out.dcname == NULL) {
730 DEBUG(2, ("Could not allocate memory\n"));
731 return NT_STATUS_NO_MEMORY;
735 * This provokes a WERR_NOT_SUPPORTED error message. This is
736 * documented in the wspp docs. I could not get a successful
737 * call to work, but the main point here is testing that the
738 * netlogon pipe works.
740 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
741 logon_server, NETLOGON_CONTROL_QUERY,
742 2, &info, &werr);
744 reset_cm_connection_on_error(domain, status);
745 if (!NT_STATUS_IS_OK(status)) {
746 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
747 nt_errstr(status)));
748 return status;
751 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
752 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
753 "WERR_NOT_SUPPORTED\n",
754 win_errstr(werr)));
755 return werror_to_ntstatus(werr);
758 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
759 return NT_STATUS_OK;