s3:winbindd: fix _wbint_LookupSids() on error
[metze/samba/wip.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 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
39                                         NTSTATUS status)
40 {
41         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42                 invalidate_cm_connection(&domain->conn);
43                 /* We invalidated the connection. */
44                 return true;
45         }
46         return false;
47 }
48
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
50 {
51         struct winbindd_domain *domain = wb_child_domain();
52         char *dom_name;
53         char *name;
54         enum lsa_SidType type;
55         NTSTATUS status;
56
57         if (domain == NULL) {
58                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
59         }
60
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;
66         }
67
68         *r->out.domain = dom_name;
69         *r->out.name = name;
70         *r->out.type = type;
71         return NT_STATUS_OK;
72 }
73
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
75 {
76         struct winbindd_domain *domain = wb_child_domain();
77         struct lsa_RefDomainList *domains = r->out.domains;
78         NTSTATUS status;
79
80         if (domain == NULL) {
81                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
82         }
83
84         /*
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.
89          */
90         status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
91                                  &domains, &r->out.names);
92
93         if (domains != NULL) {
94                 r->out.domains = domains;
95         }
96
97         reset_cm_connection_on_error(domain, status);
98         return status;
99 }
100
101 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
102 {
103         struct winbindd_domain *domain = wb_child_domain();
104         NTSTATUS status;
105
106         if (domain == NULL) {
107                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
108         }
109
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;
115 }
116
117 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
118                              struct wbint_Sids2UnixIDs *r)
119 {
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;
126
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;
131
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;
137                 }
138
139                 num_ids = 0;
140
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;
144                         }
145                 }
146
147                 ids = talloc_realloc(talloc_tos(), ids,
148                                            struct id_map, num_ids);
149                 if (ids == NULL) {
150                         goto nomem;
151                 }
152                 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
153                                                struct id_map *, num_ids+1);
154                 if (id_ptrs == NULL) {
155                         goto nomem;
156                 }
157                 id_idx = talloc_realloc(talloc_tos(), id_idx,
158                                               uint32_t, num_ids);
159                 if (id_idx == NULL) {
160                         goto nomem;
161                 }
162                 sids = talloc_realloc(talloc_tos(), sids,
163                                             struct dom_sid, num_ids);
164                 if (sids == NULL) {
165                         goto nomem;
166                 }
167
168                 num_ids = 0;
169
170                 /*
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.
174                  */
175                 for (j=0; j<r->in.ids->num_ids; j++) {
176                         struct wbint_TransID *id = &r->in.ids->ids[j];
177
178                         if (id->domain_index != i) {
179                                 continue;
180                         }
181                         id_idx[num_ids] = j;
182                         id_ptrs[num_ids] = &ids[num_ids];
183
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;
189                 }
190                 id_ptrs[num_ids] = NULL;
191
192                 status = dom->methods->sids_to_unixids(dom, id_ptrs);
193                 DEBUG(10, ("sids_to_unixids returned %s\n",
194                            nt_errstr(status)));
195
196                 /*
197                  * Extract the results for handing them back to the caller.
198                  */
199                 for (j=0; j<num_ids; j++) {
200                         struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
201
202                         if (ids[j].status != ID_MAPPED) {
203                                 id->xid.id = UINT32_MAX;
204                                 id->xid.type = ID_TYPE_NOT_SPECIFIED;
205                                 continue;
206                         }
207
208                         id->xid = ids[j].xid;
209                 }
210         }
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;
218 }
219
220 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
221 {
222         return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
223                                 r->out.sid, r->in.uid);
224 }
225
226 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
227 {
228         return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
229                                 r->out.sid, r->in.gid);
230 }
231
232 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
233 {
234         struct unixid xid;
235         NTSTATUS status;
236
237         status = idmap_allocate_uid(&xid);
238         if (!NT_STATUS_IS_OK(status)) {
239                 return status;
240         }
241         *r->out.uid = xid.id;
242         return NT_STATUS_OK;
243 }
244
245 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
246 {
247         struct unixid xid;
248         NTSTATUS status;
249
250         status = idmap_allocate_gid(&xid);
251         if (!NT_STATUS_IS_OK(status)) {
252                 return status;
253         }
254         *r->out.gid = xid.id;
255         return NT_STATUS_OK;
256 }
257
258 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
259 {
260         struct winbindd_domain *domain = wb_child_domain();
261         NTSTATUS status;
262
263         if (domain == NULL) {
264                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
265         }
266
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;
271 }
272
273 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
274                                   struct wbint_LookupUserAliases *r)
275 {
276         struct winbindd_domain *domain = wb_child_domain();
277         NTSTATUS status;
278
279         if (domain == NULL) {
280                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
281         }
282
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;
288 }
289
290 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
291                                  struct wbint_LookupUserGroups *r)
292 {
293         struct winbindd_domain *domain = wb_child_domain();
294         NTSTATUS status;
295
296         if (domain == NULL) {
297                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
298         }
299
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;
305 }
306
307 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
308                                     struct wbint_QuerySequenceNumber *r)
309 {
310         struct winbindd_domain *domain = wb_child_domain();
311         NTSTATUS status;
312
313         if (domain == NULL) {
314                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
315         }
316
317         status = domain->methods->sequence_number(domain, r->out.sequence);
318         reset_cm_connection_on_error(domain, status);
319         return status;
320 }
321
322 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
323                                    struct wbint_LookupGroupMembers *r)
324 {
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;
331
332         if (domain == NULL) {
333                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
334         }
335
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;
342         }
343
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;
349         }
350
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];
356         }
357
358         return NT_STATUS_OK;
359 }
360
361 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
362                               struct wbint_QueryUserList *r)
363 {
364         struct winbindd_domain *domain = wb_child_domain();
365         NTSTATUS status;
366
367         if (domain == NULL) {
368                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
369         }
370
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;
376 }
377
378 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
379                                struct wbint_QueryGroupList *r)
380 {
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;
386
387         if (domain == NULL) {
388                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
389         }
390
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;
396         }
397
398         result = talloc_array(r->out.groups, struct wbint_Principal,
399                               num_groups);
400         if (result == NULL) {
401                 return NT_STATUS_NO_MEMORY;
402         }
403
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;
412                 }
413         }
414
415         r->out.groups->num_principals = num_groups;
416         r->out.groups->principals = result;
417
418         TALLOC_FREE(groups);
419         return NT_STATUS_OK;
420 }
421
422 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
423 {
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;
431
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);
438         }
439
440         status = cm_connect_netlogon(domain, &netlogon_pipe);
441
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;
446         }
447
448         b = netlogon_pipe->binding_handle;
449
450         /* This call can take a long time - allow the server to time out.
451            35 seconds should do it. */
452
453         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
454
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;
462                 }
463                 if (reset_cm_connection_on_error(domain, status)) {
464                         /* Re-initialize. */
465                         status = cm_connect_netlogon(domain, &netlogon_pipe);
466
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;
471                         }
472
473                         b = netlogon_pipe->binding_handle;
474
475                         /* This call can take a long time - allow the server to time out.
476                            35 seconds should do it. */
477
478                         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
479                 }
480         }
481
482         /*
483          * Fallback to less capable methods
484          */
485
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;
490         }
491
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);
500         }
501
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;
507         }
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;
513         }
514
515         *r->out.dc_info = dc_info;
516         status = NT_STATUS_OK;
517
518 done:
519         /* And restore our original timeout. */
520         rpccli_set_timeout(netlogon_pipe, orig_timeout);
521
522         return status;
523 }
524
525 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
526 {
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;
534
535         if (domain == NULL) {
536                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
537         }
538
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;
545         }
546
547         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
548
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;
553         }
554
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]);
560         }
561         TALLOC_FREE(types);
562         TALLOC_FREE(names);
563
564         r->out.names->num_principals = r->in.rids->num_rids;
565         r->out.names->principals = result;
566         return NT_STATUS_OK;
567 }
568
569 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
570                                     struct wbint_CheckMachineAccount *r)
571 {
572         struct winbindd_domain *domain;
573         int num_retries = 0;
574         NTSTATUS status;
575
576         domain = wb_child_domain();
577         if (domain == NULL) {
578                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
579         }
580
581 again:
582         invalidate_cm_connection(&domain->conn);
583         domain->conn.netlogon_force_reauth = true;
584
585         {
586                 struct rpc_pipe_client *netlogon_pipe;
587                 status = cm_connect_netlogon(domain, &netlogon_pipe);
588         }
589
590         /* There is a race condition between fetching the trust account
591            password and the periodic machine password change.  So it's
592            possible that the trust account password has been changed on us.
593            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
594
595 #define MAX_RETRIES 3
596
597         if ((num_retries < MAX_RETRIES)
598             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
599                 num_retries++;
600                 goto again;
601         }
602
603         if (!NT_STATUS_IS_OK(status)) {
604                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
605                 goto done;
606         }
607
608         /* Pass back result code - zero for success, other values for
609            specific failures. */
610
611         DEBUG(3,("domain %s secret is %s\n", domain->name,
612                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
613
614  done:
615         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
616               ("Checking the trust account password for domain %s returned %s\n",
617                domain->name, nt_errstr(status)));
618
619         return status;
620 }
621
622 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
623                                      struct wbint_ChangeMachineAccount *r)
624 {
625         struct messaging_context *msg_ctx = winbind_messaging_context();
626         struct winbindd_domain *domain;
627         NTSTATUS status;
628         struct rpc_pipe_client *netlogon_pipe;
629
630         domain = wb_child_domain();
631         if (domain == NULL) {
632                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
633         }
634
635         status = cm_connect_netlogon(domain, &netlogon_pipe);
636         if (!NT_STATUS_IS_OK(status)) {
637                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
638                 goto done;
639         }
640
641         status = trust_pw_change(domain->conn.netlogon_creds,
642                                  msg_ctx,
643                                  netlogon_pipe->binding_handle,
644                                  domain->name,
645                                  true); /* force */
646
647         /* Pass back result code - zero for success, other values for
648            specific failures. */
649
650         DEBUG(3,("domain %s secret %s\n", domain->name,
651                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
652
653  done:
654         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
655               ("Changing the trust account password for domain %s returned %s\n",
656                domain->name, nt_errstr(status)));
657
658         return status;
659 }
660
661 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
662 {
663         NTSTATUS status;
664         struct winbindd_domain *domain;
665         struct rpc_pipe_client *netlogon_pipe;
666         union netr_CONTROL_QUERY_INFORMATION info;
667         WERROR werr;
668         fstring logon_server;
669         struct dcerpc_binding_handle *b;
670
671         domain = wb_child_domain();
672         if (domain == NULL) {
673                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
674         }
675
676         status = cm_connect_netlogon(domain, &netlogon_pipe);
677         reset_cm_connection_on_error(domain, status);
678         if (!NT_STATUS_IS_OK(status)) {
679                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
680                           nt_errstr(status)));
681                 return status;
682         }
683
684         b = netlogon_pipe->binding_handle;
685
686         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
687         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
688         if (*r->out.dcname == NULL) {
689                 DEBUG(2, ("Could not allocate memory\n"));
690                 return NT_STATUS_NO_MEMORY;
691         }
692
693         /*
694          * This provokes a WERR_NOT_SUPPORTED error message. This is
695          * documented in the wspp docs. I could not get a successful
696          * call to work, but the main point here is testing that the
697          * netlogon pipe works.
698          */
699         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
700                                           logon_server, NETLOGON_CONTROL_QUERY,
701                                           2, &info, &werr);
702
703         reset_cm_connection_on_error(domain, status);
704         if (!NT_STATUS_IS_OK(status)) {
705                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
706                         nt_errstr(status)));
707                 return status;
708         }
709
710         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
711                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
712                           "WERR_NOT_SUPPORTED\n",
713                           win_errstr(werr)));
714                 return werror_to_ntstatus(werr);
715         }
716
717         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
718         return NT_STATUS_OK;
719 }