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