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