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