winbind: Fix no memory check in _wbint_PingDc().
[obnox/samba/samba-obnox.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
578         {
579                 struct rpc_pipe_client *netlogon_pipe;
580                 status = cm_connect_netlogon(domain, &netlogon_pipe);
581         }
582
583         /* There is a race condition between fetching the trust account
584            password and the periodic machine password change.  So it's
585            possible that the trust account password has been changed on us.
586            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
587
588 #define MAX_RETRIES 3
589
590         if ((num_retries < MAX_RETRIES)
591             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
592                 num_retries++;
593                 goto again;
594         }
595
596         if (!NT_STATUS_IS_OK(status)) {
597                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
598                 goto done;
599         }
600
601         /* Pass back result code - zero for success, other values for
602            specific failures. */
603
604         DEBUG(3,("domain %s secret is %s\n", domain->name,
605                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
606
607  done:
608         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
609               ("Checking the trust account password for domain %s returned %s\n",
610                domain->name, nt_errstr(status)));
611
612         return status;
613 }
614
615 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
616                                      struct wbint_ChangeMachineAccount *r)
617 {
618         struct winbindd_domain *domain;
619         int num_retries = 0;
620         NTSTATUS status;
621         struct rpc_pipe_client *netlogon_pipe;
622         TALLOC_CTX *tmp_ctx;
623
624 again:
625         domain = wb_child_domain();
626         if (domain == NULL) {
627                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
628         }
629
630         invalidate_cm_connection(&domain->conn);
631
632         {
633                 status = cm_connect_netlogon(domain, &netlogon_pipe);
634         }
635
636         /* There is a race condition between fetching the trust account
637            password and the periodic machine password change.  So it's
638            possible that the trust account password has been changed on us.
639            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
640
641 #define MAX_RETRIES 3
642
643         if ((num_retries < MAX_RETRIES)
644              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
645                 num_retries++;
646                 goto again;
647         }
648
649         if (!NT_STATUS_IS_OK(status)) {
650                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
651                 goto done;
652         }
653
654         tmp_ctx = talloc_new(p->mem_ctx);
655
656         status = trust_pw_find_change_and_store_it(netlogon_pipe,
657                                                    tmp_ctx,
658                                                    domain->name);
659         talloc_destroy(tmp_ctx);
660
661         /* Pass back result code - zero for success, other values for
662            specific failures. */
663
664         DEBUG(3,("domain %s secret %s\n", domain->name,
665                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
666
667  done:
668         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
669               ("Changing the trust account password for domain %s returned %s\n",
670                domain->name, nt_errstr(status)));
671
672         return status;
673 }
674
675 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
676 {
677         NTSTATUS status;
678         struct winbindd_domain *domain;
679         struct rpc_pipe_client *netlogon_pipe;
680         union netr_CONTROL_QUERY_INFORMATION info;
681         WERROR werr;
682         fstring logon_server;
683         struct dcerpc_binding_handle *b;
684
685         domain = wb_child_domain();
686         if (domain == NULL) {
687                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
688         }
689
690         status = cm_connect_netlogon(domain, &netlogon_pipe);
691         reset_cm_connection_on_error(domain, status);
692         if (!NT_STATUS_IS_OK(status)) {
693                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
694                 return status;
695         }
696
697         b = netlogon_pipe->binding_handle;
698
699         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
700         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
701         if (*r->out.dcname == NULL) {
702                 DEBUG(2, ("Could not allocate memory\n"));
703                 return NT_STATUS_NO_MEMORY;
704         }
705
706         /*
707          * This provokes a WERR_NOT_SUPPORTED error message. This is
708          * documented in the wspp docs. I could not get a successful
709          * call to work, but the main point here is testing that the
710          * netlogon pipe works.
711          */
712         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
713                                           logon_server, NETLOGON_CONTROL_QUERY,
714                                           2, &info, &werr);
715
716         reset_cm_connection_on_error(domain, status);
717         if (!NT_STATUS_IS_OK(status)) {
718                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
719                         nt_errstr(status)));
720                 return status;
721         }
722
723         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
724                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
725                           "WERR_NOT_SUPPORTED\n",
726                           win_errstr(werr)));
727                 return werror_to_ntstatus(werr);
728         }
729
730         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
731         return NT_STATUS_OK;
732 }