s3: explicitly pass domain_sid to wbint_LookupRids() (bug #7841)
[samba.git] / source3 / winbindd / winbindd_dual_srv.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    In-Child server implementation of the routines defined in wbint.idl
5
6    Copyright (C) Volker Lendecke 2009
7    Copyright (C) Guenther Deschner 2009
8
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.
13
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.
18
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/>.
21 */
22
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"
32
33 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
34 {
35         *r->out.out_data = r->in.in_data;
36 }
37
38 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
39 {
40         struct winbindd_domain *domain = wb_child_domain();
41         char *dom_name;
42         char *name;
43         enum lsa_SidType type;
44         NTSTATUS status;
45
46         if (domain == NULL) {
47                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
48         }
49
50         status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
51                                               &dom_name, &name, &type);
52         if (!NT_STATUS_IS_OK(status)) {
53                 return status;
54         }
55
56         *r->out.domain = dom_name;
57         *r->out.name = name;
58         *r->out.type = type;
59         return NT_STATUS_OK;
60 }
61
62 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
63 {
64         struct winbindd_domain *domain = wb_child_domain();
65
66         if (domain == NULL) {
67                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
68         }
69
70         /*
71          * This breaks the winbindd_domain->methods abstraction: This
72          * is only called for remote domains, and both winbindd_msrpc
73          * and winbindd_ad call into lsa_lookupsids anyway. Caching is
74          * done at the wbint RPC layer.
75          */
76         return rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
77                                &r->out.domains, &r->out.names);
78 }
79
80 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
81 {
82         struct winbindd_domain *domain = wb_child_domain();
83
84         if (domain == NULL) {
85                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
86         }
87
88         return domain->methods->name_to_sid(
89                 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
90                 r->out.sid, r->out.type);
91 }
92
93 NTSTATUS _wbint_Sid2Uid(struct pipes_struct *p, struct wbint_Sid2Uid *r)
94 {
95         uid_t uid;
96         NTSTATUS status;
97
98         status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
99                                   r->in.sid, &uid);
100         if (!NT_STATUS_IS_OK(status)) {
101                 return status;
102         }
103         *r->out.uid = uid;
104         return NT_STATUS_OK;
105 }
106
107 NTSTATUS _wbint_Sid2Gid(struct pipes_struct *p, struct wbint_Sid2Gid *r)
108 {
109         gid_t gid;
110         NTSTATUS status;
111
112         status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
113                                   r->in.sid, &gid);
114         if (!NT_STATUS_IS_OK(status)) {
115                 return status;
116         }
117         *r->out.gid = gid;
118         return NT_STATUS_OK;
119 }
120
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122                              struct wbint_Sids2UnixIDs *r)
123 {
124         uint32_t i, j;
125         struct id_map *ids = NULL;
126         struct id_map **id_ptrs = NULL;
127         struct dom_sid *sids = NULL;
128         uint32_t *id_idx = NULL;
129         NTSTATUS status = NT_STATUS_NO_MEMORY;
130
131         for (i=0; i<r->in.domains->count; i++) {
132                 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
133                 struct idmap_domain *dom;
134                 uint32_t num_ids;
135
136                 dom = idmap_find_domain(d->name.string);
137                 if (dom == NULL) {
138                         DEBUG(10, ("idmap domain %s not found\n",
139                                    d->name.string));
140                         continue;
141                 }
142
143                 num_ids = 0;
144
145                 for (j=0; j<r->in.ids->num_ids; j++) {
146                         if (r->in.ids->ids[j].domain_index == i) {
147                                 num_ids += 1;
148                         }
149                 }
150
151                 ids = talloc_realloc(talloc_tos(), ids,
152                                            struct id_map, num_ids);
153                 if (ids == NULL) {
154                         goto nomem;
155                 }
156                 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
157                                                struct id_map *, num_ids+1);
158                 if (id_ptrs == NULL) {
159                         goto nomem;
160                 }
161                 id_idx = talloc_realloc(talloc_tos(), id_idx,
162                                               uint32_t, num_ids);
163                 if (id_idx == NULL) {
164                         goto nomem;
165                 }
166                 sids = talloc_realloc(talloc_tos(), sids,
167                                             struct dom_sid, num_ids);
168                 if (sids == NULL) {
169                         goto nomem;
170                 }
171
172                 num_ids = 0;
173
174                 for (j=0; j<r->in.ids->num_ids; j++) {
175                         struct wbint_TransID *id = &r->in.ids->ids[j];
176
177                         if (id->domain_index != i) {
178                                 continue;
179                         }
180                         id_idx[num_ids] = j;
181                         id_ptrs[num_ids] = &ids[num_ids];
182
183                         ids[num_ids].sid = &sids[num_ids];
184                         sid_compose(ids[num_ids].sid, d->sid, id->rid);
185                         ids[num_ids].xid.type = id->type;
186                         ids[num_ids].status = ID_UNKNOWN;
187                         num_ids += 1;
188                 }
189                 id_ptrs[num_ids] = NULL;
190
191                 status = dom->methods->sids_to_unixids(dom, id_ptrs);
192                 DEBUG(10, ("sids_to_unixids returned %s\n",
193                            nt_errstr(status)));
194
195                 for (j=0; j<num_ids; j++) {
196                         struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
197
198                         if (ids[j].status != ID_MAPPED) {
199                                 continue;
200                         }
201                         id->unix_id = ids[j].xid.id;
202                 }
203         }
204         status = NT_STATUS_OK;
205 nomem:
206         TALLOC_FREE(ids);
207         TALLOC_FREE(id_ptrs);
208         TALLOC_FREE(id_idx);
209         TALLOC_FREE(sids);
210         return status;
211 }
212
213 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
214 {
215         return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
216                                 r->out.sid, r->in.uid);
217 }
218
219 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
220 {
221         return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
222                                 r->out.sid, r->in.gid);
223 }
224
225 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
226 {
227         struct unixid xid;
228         NTSTATUS status;
229
230         status = idmap_allocate_uid(&xid);
231         if (!NT_STATUS_IS_OK(status)) {
232                 return status;
233         }
234         *r->out.uid = xid.id;
235         return NT_STATUS_OK;
236 }
237
238 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
239 {
240         struct unixid xid;
241         NTSTATUS status;
242
243         status = idmap_allocate_gid(&xid);
244         if (!NT_STATUS_IS_OK(status)) {
245                 return status;
246         }
247         *r->out.gid = xid.id;
248         return NT_STATUS_OK;
249 }
250
251 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
252 {
253         struct winbindd_domain *domain = wb_child_domain();
254
255         if (domain == NULL) {
256                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
257         }
258
259         return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
260                                            r->out.info);
261 }
262
263 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
264                                   struct wbint_LookupUserAliases *r)
265 {
266         struct winbindd_domain *domain = wb_child_domain();
267
268         if (domain == NULL) {
269                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
270         }
271
272         return domain->methods->lookup_useraliases(
273                 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
274                 &r->out.rids->num_rids, &r->out.rids->rids);
275 }
276
277 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
278                                  struct wbint_LookupUserGroups *r)
279 {
280         struct winbindd_domain *domain = wb_child_domain();
281
282         if (domain == NULL) {
283                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
284         }
285
286         return domain->methods->lookup_usergroups(
287                 domain, p->mem_ctx, r->in.sid,
288                 &r->out.sids->num_sids, &r->out.sids->sids);
289 }
290
291 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
292                                     struct wbint_QuerySequenceNumber *r)
293 {
294         struct winbindd_domain *domain = wb_child_domain();
295
296         if (domain == NULL) {
297                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
298         }
299
300         return domain->methods->sequence_number(domain, r->out.sequence);
301 }
302
303 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
304                                    struct wbint_LookupGroupMembers *r)
305 {
306         struct winbindd_domain *domain = wb_child_domain();
307         uint32_t i, num_names;
308         struct dom_sid *sid_mem;
309         char **names;
310         uint32_t *name_types;
311         NTSTATUS status;
312
313         if (domain == NULL) {
314                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
315         }
316
317         status = domain->methods->lookup_groupmem(
318                 domain, p->mem_ctx, r->in.sid, r->in.type,
319                 &num_names, &sid_mem, &names, &name_types);
320         if (!NT_STATUS_IS_OK(status)) {
321                 return status;
322         }
323
324         r->out.members->num_principals = num_names;
325         r->out.members->principals = talloc_array(
326                 r->out.members, struct wbint_Principal, num_names);
327         if (r->out.members->principals == NULL) {
328                 return NT_STATUS_NO_MEMORY;
329         }
330
331         for (i=0; i<num_names; i++) {
332                 struct wbint_Principal *m = &r->out.members->principals[i];
333                 sid_copy(&m->sid, &sid_mem[i]);
334                 m->name = talloc_move(r->out.members->principals, &names[i]);
335                 m->type = (enum lsa_SidType)name_types[i];
336         }
337
338         return NT_STATUS_OK;
339 }
340
341 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
342                               struct wbint_QueryUserList *r)
343 {
344         struct winbindd_domain *domain = wb_child_domain();
345
346         if (domain == NULL) {
347                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
348         }
349
350         return domain->methods->query_user_list(
351                 domain, p->mem_ctx, &r->out.users->num_userinfos,
352                 &r->out.users->userinfos);
353 }
354
355 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
356                                struct wbint_QueryGroupList *r)
357 {
358         struct winbindd_domain *domain = wb_child_domain();
359         uint32_t i, num_groups;
360         struct wb_acct_info *groups;
361         struct wbint_Principal *result;
362         NTSTATUS status;
363
364         if (domain == NULL) {
365                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
366         }
367
368         status = domain->methods->enum_dom_groups(domain, talloc_tos(),
369                                                   &num_groups, &groups);
370         if (!NT_STATUS_IS_OK(status)) {
371                 return status;
372         }
373
374         result = talloc_array(r->out.groups, struct wbint_Principal,
375                               num_groups);
376         if (result == NULL) {
377                 return NT_STATUS_NO_MEMORY;
378         }
379
380         for (i=0; i<num_groups; i++) {
381                 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
382                 result[i].type = SID_NAME_DOM_GRP;
383                 result[i].name = talloc_strdup(result, groups[i].acct_name);
384                 if (result[i].name == NULL) {
385                         TALLOC_FREE(result);
386                         TALLOC_FREE(groups);
387                         return NT_STATUS_NO_MEMORY;
388                 }
389         }
390
391         r->out.groups->num_principals = num_groups;
392         r->out.groups->principals = result;
393
394         TALLOC_FREE(groups);
395         return NT_STATUS_OK;
396 }
397
398 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
399 {
400         struct winbindd_domain *domain = wb_child_domain();
401         struct rpc_pipe_client *netlogon_pipe;
402         struct netr_DsRGetDCNameInfo *dc_info;
403         NTSTATUS status;
404         WERROR werr;
405         unsigned int orig_timeout;
406         struct dcerpc_binding_handle *b;
407
408         if (domain == NULL) {
409                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
410                                    r->in.domain_name, r->in.domain_guid,
411                                    r->in.site_name ? r->in.site_name : "",
412                                    r->in.flags,
413                                    r->out.dc_info);
414         }
415
416         status = cm_connect_netlogon(domain, &netlogon_pipe);
417
418         if (!NT_STATUS_IS_OK(status)) {
419                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
420                 return status;
421         }
422
423         b = netlogon_pipe->binding_handle;
424
425         /* This call can take a long time - allow the server to time out.
426            35 seconds should do it. */
427
428         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
429
430         if (domain->active_directory) {
431                 status = dcerpc_netr_DsRGetDCName(b,
432                         p->mem_ctx, domain->dcname,
433                         r->in.domain_name, NULL, r->in.domain_guid,
434                         r->in.flags, r->out.dc_info, &werr);
435                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
436                         goto done;
437                 }
438         }
439
440         /*
441          * Fallback to less capable methods
442          */
443
444         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
445         if (dc_info == NULL) {
446                 status = NT_STATUS_NO_MEMORY;
447                 goto done;
448         }
449
450         if (r->in.flags & DS_PDC_REQUIRED) {
451                 status = dcerpc_netr_GetDcName(b,
452                         p->mem_ctx, domain->dcname,
453                         r->in.domain_name, &dc_info->dc_unc, &werr);
454         } else {
455                 status = dcerpc_netr_GetAnyDCName(b,
456                         p->mem_ctx, domain->dcname,
457                         r->in.domain_name, &dc_info->dc_unc, &werr);
458         }
459
460         if (!NT_STATUS_IS_OK(status)) {
461                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
462                            nt_errstr(status)));
463                 goto done;
464         }
465         if (!W_ERROR_IS_OK(werr)) {
466                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
467                            win_errstr(werr)));
468                 status = werror_to_ntstatus(werr);
469                 goto done;
470         }
471
472         *r->out.dc_info = dc_info;
473         status = NT_STATUS_OK;
474
475 done:
476         /* And restore our original timeout. */
477         rpccli_set_timeout(netlogon_pipe, orig_timeout);
478
479         return status;
480 }
481
482 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
483 {
484         struct winbindd_domain *domain = wb_child_domain();
485         char *domain_name;
486         char **names;
487         enum lsa_SidType *types;
488         struct wbint_Principal *result;
489         NTSTATUS status;
490         int i;
491
492         if (domain == NULL) {
493                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
494         }
495
496         status = domain->methods->rids_to_names(
497                 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
498                 r->in.rids->num_rids, &domain_name, &names, &types);
499         if (!NT_STATUS_IS_OK(status)) {
500                 return status;
501         }
502
503         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
504
505         result = talloc_array(p->mem_ctx, struct wbint_Principal,
506                               r->in.rids->num_rids);
507         if (result == NULL) {
508                 return NT_STATUS_NO_MEMORY;
509         }
510
511         for (i=0; i<r->in.rids->num_rids; i++) {
512                 sid_compose(&result[i].sid, r->in.domain_sid,
513                             r->in.rids->rids[i]);
514                 result[i].type = types[i];
515                 result[i].name = talloc_move(result, &names[i]);
516         }
517         TALLOC_FREE(types);
518         TALLOC_FREE(names);
519
520         r->out.names->num_principals = r->in.rids->num_rids;
521         r->out.names->principals = result;
522         return NT_STATUS_OK;
523 }
524
525 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
526                                     struct wbint_CheckMachineAccount *r)
527 {
528         struct winbindd_domain *domain;
529         int num_retries = 0;
530         NTSTATUS status;
531
532         domain = wb_child_domain();
533         if (domain == NULL) {
534                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
535         }
536
537 again:
538         invalidate_cm_connection(&domain->conn);
539
540         {
541                 struct rpc_pipe_client *netlogon_pipe;
542                 status = cm_connect_netlogon(domain, &netlogon_pipe);
543         }
544
545         /* There is a race condition between fetching the trust account
546            password and the periodic machine password change.  So it's
547            possible that the trust account password has been changed on us.
548            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
549
550 #define MAX_RETRIES 3
551
552         if ((num_retries < MAX_RETRIES)
553             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
554                 num_retries++;
555                 goto again;
556         }
557
558         if (!NT_STATUS_IS_OK(status)) {
559                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
560                 goto done;
561         }
562
563         /* Pass back result code - zero for success, other values for
564            specific failures. */
565
566         DEBUG(3,("domain %s secret is %s\n", domain->name,
567                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
568
569  done:
570         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
571               ("Checking the trust account password for domain %s returned %s\n",
572                domain->name, nt_errstr(status)));
573
574         return status;
575 }
576
577 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
578                                      struct wbint_ChangeMachineAccount *r)
579 {
580         struct winbindd_domain *domain;
581         int num_retries = 0;
582         NTSTATUS status;
583         struct rpc_pipe_client *netlogon_pipe;
584         TALLOC_CTX *tmp_ctx;
585
586 again:
587         domain = wb_child_domain();
588         if (domain == NULL) {
589                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
590         }
591
592         invalidate_cm_connection(&domain->conn);
593
594         {
595                 status = cm_connect_netlogon(domain, &netlogon_pipe);
596         }
597
598         /* There is a race condition between fetching the trust account
599            password and the periodic machine password change.  So it's
600            possible that the trust account password has been changed on us.
601            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
602
603 #define MAX_RETRIES 3
604
605         if ((num_retries < MAX_RETRIES)
606              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
607                 num_retries++;
608                 goto again;
609         }
610
611         if (!NT_STATUS_IS_OK(status)) {
612                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
613                 goto done;
614         }
615
616         tmp_ctx = talloc_new(p->mem_ctx);
617
618         status = trust_pw_find_change_and_store_it(netlogon_pipe,
619                                                    tmp_ctx,
620                                                    domain->name);
621         talloc_destroy(tmp_ctx);
622
623         /* Pass back result code - zero for success, other values for
624            specific failures. */
625
626         DEBUG(3,("domain %s secret %s\n", domain->name,
627                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
628
629  done:
630         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
631               ("Changing the trust account password for domain %s returned %s\n",
632                domain->name, nt_errstr(status)));
633
634         return status;
635 }
636
637 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
638 {
639         NTSTATUS status;
640         struct winbindd_domain *domain;
641         struct rpc_pipe_client *netlogon_pipe;
642         union netr_CONTROL_QUERY_INFORMATION info;
643         WERROR werr;
644         fstring logon_server;
645         struct dcerpc_binding_handle *b;
646
647         domain = wb_child_domain();
648         if (domain == NULL) {
649                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
650         }
651
652         status = cm_connect_netlogon(domain, &netlogon_pipe);
653         if (!NT_STATUS_IS_OK(status)) {
654                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
655                 return status;
656         }
657
658         b = netlogon_pipe->binding_handle;
659
660         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
661
662         /*
663          * This provokes a WERR_NOT_SUPPORTED error message. This is
664          * documented in the wspp docs. I could not get a successful
665          * call to work, but the main point here is testing that the
666          * netlogon pipe works.
667          */
668         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
669                                           logon_server, NETLOGON_CONTROL_QUERY,
670                                           2, &info, &werr);
671
672         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
673                 DEBUG(2, ("dcerpc_netr_LogonControl timed out\n"));
674                 invalidate_cm_connection(&domain->conn);
675                 return status;
676         }
677
678         if (!NT_STATUS_IS_OK(status)) {
679                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
680                         nt_errstr(status)));
681                 return status;
682         }
683
684         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
685                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
686                           "WERR_NOT_SUPPORTED\n",
687                           win_errstr(werr)));
688                 return werror_to_ntstatus(werr);
689         }
690
691         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
692         return NT_STATUS_OK;
693 }