s3:winbindd: add an explanatory comment to _wbint_Sids2UnixIDs()
[metze/samba/wip.git] / source3 / winbindd / winbindd_dual_srv.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    In-Child server implementation of the routines defined in wbint.idl
5
6    Copyright (C) Volker Lendecke 2009
7    Copyright (C) Guenther Deschner 2009
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
27 #include "ntdomain.h"
28 #include "librpc/gen_ndr/srv_wbint.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "idmap.h"
31 #include "../libcli/security/security.h"
32
33 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
34 {
35         *r->out.out_data = r->in.in_data;
36 }
37
38 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
39                                         NTSTATUS status)
40 {
41         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
42                 invalidate_cm_connection(&domain->conn);
43                 /* We invalidated the connection. */
44                 return true;
45         }
46         return false;
47 }
48
49 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
50 {
51         struct winbindd_domain *domain = wb_child_domain();
52         char *dom_name;
53         char *name;
54         enum lsa_SidType type;
55         NTSTATUS status;
56
57         if (domain == NULL) {
58                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
59         }
60
61         status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
62                                               &dom_name, &name, &type);
63         reset_cm_connection_on_error(domain, status);
64         if (!NT_STATUS_IS_OK(status)) {
65                 return status;
66         }
67
68         *r->out.domain = dom_name;
69         *r->out.name = name;
70         *r->out.type = type;
71         return NT_STATUS_OK;
72 }
73
74 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
75 {
76         struct winbindd_domain *domain = wb_child_domain();
77         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                 /*
219                  * Extract the results for handing them back to the caller.
220                  */
221                 for (j=0; j<num_ids; j++) {
222                         struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
223
224                         if (ids[j].status != ID_MAPPED) {
225                                 continue;
226                         }
227                         id->unix_id = ids[j].xid.id;
228                 }
229         }
230         status = NT_STATUS_OK;
231 nomem:
232         TALLOC_FREE(ids);
233         TALLOC_FREE(id_ptrs);
234         TALLOC_FREE(id_idx);
235         TALLOC_FREE(sids);
236         return status;
237 }
238
239 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
240 {
241         return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
242                                 r->out.sid, r->in.uid);
243 }
244
245 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
246 {
247         return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
248                                 r->out.sid, r->in.gid);
249 }
250
251 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
252 {
253         struct unixid xid;
254         NTSTATUS status;
255
256         status = idmap_allocate_uid(&xid);
257         if (!NT_STATUS_IS_OK(status)) {
258                 return status;
259         }
260         *r->out.uid = xid.id;
261         return NT_STATUS_OK;
262 }
263
264 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
265 {
266         struct unixid xid;
267         NTSTATUS status;
268
269         status = idmap_allocate_gid(&xid);
270         if (!NT_STATUS_IS_OK(status)) {
271                 return status;
272         }
273         *r->out.gid = xid.id;
274         return NT_STATUS_OK;
275 }
276
277 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
278 {
279         struct winbindd_domain *domain = wb_child_domain();
280         NTSTATUS status;
281
282         if (domain == NULL) {
283                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
284         }
285
286         status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
287                                              r->out.info);
288         reset_cm_connection_on_error(domain, status);
289         return status;
290 }
291
292 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
293                                   struct wbint_LookupUserAliases *r)
294 {
295         struct winbindd_domain *domain = wb_child_domain();
296         NTSTATUS status;
297
298         if (domain == NULL) {
299                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
300         }
301
302         status = domain->methods->lookup_useraliases(
303                 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
304                 &r->out.rids->num_rids, &r->out.rids->rids);
305         reset_cm_connection_on_error(domain, status);
306         return status;
307 }
308
309 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
310                                  struct wbint_LookupUserGroups *r)
311 {
312         struct winbindd_domain *domain = wb_child_domain();
313         NTSTATUS status;
314
315         if (domain == NULL) {
316                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
317         }
318
319         status = domain->methods->lookup_usergroups(
320                 domain, p->mem_ctx, r->in.sid,
321                 &r->out.sids->num_sids, &r->out.sids->sids);
322         reset_cm_connection_on_error(domain, status);
323         return status;
324 }
325
326 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
327                                     struct wbint_QuerySequenceNumber *r)
328 {
329         struct winbindd_domain *domain = wb_child_domain();
330         NTSTATUS status;
331
332         if (domain == NULL) {
333                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
334         }
335
336         status = domain->methods->sequence_number(domain, r->out.sequence);
337         reset_cm_connection_on_error(domain, status);
338         return status;
339 }
340
341 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
342                                    struct wbint_LookupGroupMembers *r)
343 {
344         struct winbindd_domain *domain = wb_child_domain();
345         uint32_t i, num_names;
346         struct dom_sid *sid_mem;
347         char **names;
348         uint32_t *name_types;
349         NTSTATUS status;
350
351         if (domain == NULL) {
352                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
353         }
354
355         status = domain->methods->lookup_groupmem(
356                 domain, p->mem_ctx, r->in.sid, r->in.type,
357                 &num_names, &sid_mem, &names, &name_types);
358         reset_cm_connection_on_error(domain, status);
359         if (!NT_STATUS_IS_OK(status)) {
360                 return status;
361         }
362
363         r->out.members->num_principals = num_names;
364         r->out.members->principals = talloc_array(
365                 r->out.members, struct wbint_Principal, num_names);
366         if (r->out.members->principals == NULL) {
367                 return NT_STATUS_NO_MEMORY;
368         }
369
370         for (i=0; i<num_names; i++) {
371                 struct wbint_Principal *m = &r->out.members->principals[i];
372                 sid_copy(&m->sid, &sid_mem[i]);
373                 m->name = talloc_move(r->out.members->principals, &names[i]);
374                 m->type = (enum lsa_SidType)name_types[i];
375         }
376
377         return NT_STATUS_OK;
378 }
379
380 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
381                               struct wbint_QueryUserList *r)
382 {
383         struct winbindd_domain *domain = wb_child_domain();
384         NTSTATUS status;
385
386         if (domain == NULL) {
387                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
388         }
389
390         status = domain->methods->query_user_list(
391                 domain, p->mem_ctx, &r->out.users->num_userinfos,
392                 &r->out.users->userinfos);
393         reset_cm_connection_on_error(domain, status);
394         return status;
395 }
396
397 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
398                                struct wbint_QueryGroupList *r)
399 {
400         struct winbindd_domain *domain = wb_child_domain();
401         uint32_t i, num_groups;
402         struct wb_acct_info *groups;
403         struct wbint_Principal *result;
404         NTSTATUS status;
405
406         if (domain == NULL) {
407                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
408         }
409
410         status = domain->methods->enum_dom_groups(domain, talloc_tos(),
411                                                   &num_groups, &groups);
412         reset_cm_connection_on_error(domain, status);
413         if (!NT_STATUS_IS_OK(status)) {
414                 return status;
415         }
416
417         result = talloc_array(r->out.groups, struct wbint_Principal,
418                               num_groups);
419         if (result == NULL) {
420                 return NT_STATUS_NO_MEMORY;
421         }
422
423         for (i=0; i<num_groups; i++) {
424                 sid_compose(&result[i].sid, &domain->sid, groups[i].rid);
425                 result[i].type = SID_NAME_DOM_GRP;
426                 result[i].name = talloc_strdup(result, groups[i].acct_name);
427                 if (result[i].name == NULL) {
428                         TALLOC_FREE(result);
429                         TALLOC_FREE(groups);
430                         return NT_STATUS_NO_MEMORY;
431                 }
432         }
433
434         r->out.groups->num_principals = num_groups;
435         r->out.groups->principals = result;
436
437         TALLOC_FREE(groups);
438         return NT_STATUS_OK;
439 }
440
441 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
442 {
443         struct winbindd_domain *domain = wb_child_domain();
444         struct rpc_pipe_client *netlogon_pipe;
445         struct netr_DsRGetDCNameInfo *dc_info;
446         NTSTATUS status;
447         WERROR werr;
448         unsigned int orig_timeout;
449         struct dcerpc_binding_handle *b;
450
451         if (domain == NULL) {
452                 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
453                                    r->in.domain_name, r->in.domain_guid,
454                                    r->in.site_name ? r->in.site_name : "",
455                                    r->in.flags,
456                                    r->out.dc_info);
457         }
458
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         if (domain->active_directory) {
475                 status = dcerpc_netr_DsRGetDCName(b,
476                         p->mem_ctx, domain->dcname,
477                         r->in.domain_name, NULL, r->in.domain_guid,
478                         r->in.flags, r->out.dc_info, &werr);
479                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
480                         goto done;
481                 }
482                 if (reset_cm_connection_on_error(domain, status)) {
483                         /* Re-initialize. */
484                         status = cm_connect_netlogon(domain, &netlogon_pipe);
485
486                         reset_cm_connection_on_error(domain, status);
487                         if (!NT_STATUS_IS_OK(status)) {
488                                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
489                                 return status;
490                         }
491
492                         b = netlogon_pipe->binding_handle;
493
494                         /* This call can take a long time - allow the server to time out.
495                            35 seconds should do it. */
496
497                         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
498                 }
499         }
500
501         /*
502          * Fallback to less capable methods
503          */
504
505         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
506         if (dc_info == NULL) {
507                 status = NT_STATUS_NO_MEMORY;
508                 goto done;
509         }
510
511         if (r->in.flags & DS_PDC_REQUIRED) {
512                 status = dcerpc_netr_GetDcName(b,
513                         p->mem_ctx, domain->dcname,
514                         r->in.domain_name, &dc_info->dc_unc, &werr);
515         } else {
516                 status = dcerpc_netr_GetAnyDCName(b,
517                         p->mem_ctx, domain->dcname,
518                         r->in.domain_name, &dc_info->dc_unc, &werr);
519         }
520
521         reset_cm_connection_on_error(domain, status);
522         if (!NT_STATUS_IS_OK(status)) {
523                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
524                            nt_errstr(status)));
525                 goto done;
526         }
527         if (!W_ERROR_IS_OK(werr)) {
528                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
529                            win_errstr(werr)));
530                 status = werror_to_ntstatus(werr);
531                 goto done;
532         }
533
534         *r->out.dc_info = dc_info;
535         status = NT_STATUS_OK;
536
537 done:
538         /* And restore our original timeout. */
539         rpccli_set_timeout(netlogon_pipe, orig_timeout);
540
541         return status;
542 }
543
544 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
545 {
546         struct winbindd_domain *domain = wb_child_domain();
547         char *domain_name;
548         char **names;
549         enum lsa_SidType *types;
550         struct wbint_Principal *result;
551         NTSTATUS status;
552         int i;
553
554         if (domain == NULL) {
555                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
556         }
557
558         status = domain->methods->rids_to_names(
559                 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
560                 r->in.rids->num_rids, &domain_name, &names, &types);
561         reset_cm_connection_on_error(domain, status);
562         if (!NT_STATUS_IS_OK(status)) {
563                 return status;
564         }
565
566         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
567
568         result = talloc_array(p->mem_ctx, struct wbint_Principal,
569                               r->in.rids->num_rids);
570         if (result == NULL) {
571                 return NT_STATUS_NO_MEMORY;
572         }
573
574         for (i=0; i<r->in.rids->num_rids; i++) {
575                 sid_compose(&result[i].sid, r->in.domain_sid,
576                             r->in.rids->rids[i]);
577                 result[i].type = types[i];
578                 result[i].name = talloc_move(result, &names[i]);
579         }
580         TALLOC_FREE(types);
581         TALLOC_FREE(names);
582
583         r->out.names->num_principals = r->in.rids->num_rids;
584         r->out.names->principals = result;
585         return NT_STATUS_OK;
586 }
587
588 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
589                                     struct wbint_CheckMachineAccount *r)
590 {
591         struct winbindd_domain *domain;
592         int num_retries = 0;
593         NTSTATUS status;
594
595         domain = wb_child_domain();
596         if (domain == NULL) {
597                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
598         }
599
600 again:
601         invalidate_cm_connection(&domain->conn);
602
603         {
604                 struct rpc_pipe_client *netlogon_pipe;
605                 status = cm_connect_netlogon(domain, &netlogon_pipe);
606         }
607
608         /* There is a race condition between fetching the trust account
609            password and the periodic machine password change.  So it's
610            possible that the trust account password has been changed on us.
611            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
612
613 #define MAX_RETRIES 3
614
615         if ((num_retries < MAX_RETRIES)
616             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
617                 num_retries++;
618                 goto again;
619         }
620
621         if (!NT_STATUS_IS_OK(status)) {
622                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
623                 goto done;
624         }
625
626         /* Pass back result code - zero for success, other values for
627            specific failures. */
628
629         DEBUG(3,("domain %s secret is %s\n", domain->name,
630                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
631
632  done:
633         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
634               ("Checking the trust account password for domain %s returned %s\n",
635                domain->name, nt_errstr(status)));
636
637         return status;
638 }
639
640 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
641                                      struct wbint_ChangeMachineAccount *r)
642 {
643         struct winbindd_domain *domain;
644         int num_retries = 0;
645         NTSTATUS status;
646         struct rpc_pipe_client *netlogon_pipe;
647         TALLOC_CTX *tmp_ctx;
648
649 again:
650         domain = wb_child_domain();
651         if (domain == NULL) {
652                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
653         }
654
655         invalidate_cm_connection(&domain->conn);
656
657         {
658                 status = cm_connect_netlogon(domain, &netlogon_pipe);
659         }
660
661         /* There is a race condition between fetching the trust account
662            password and the periodic machine password change.  So it's
663            possible that the trust account password has been changed on us.
664            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
665
666 #define MAX_RETRIES 3
667
668         if ((num_retries < MAX_RETRIES)
669              && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
670                 num_retries++;
671                 goto again;
672         }
673
674         if (!NT_STATUS_IS_OK(status)) {
675                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
676                 goto done;
677         }
678
679         tmp_ctx = talloc_new(p->mem_ctx);
680
681         status = trust_pw_find_change_and_store_it(netlogon_pipe,
682                                                    tmp_ctx,
683                                                    domain->name);
684         talloc_destroy(tmp_ctx);
685
686         /* Pass back result code - zero for success, other values for
687            specific failures. */
688
689         DEBUG(3,("domain %s secret %s\n", domain->name,
690                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
691
692  done:
693         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
694               ("Changing the trust account password for domain %s returned %s\n",
695                domain->name, nt_errstr(status)));
696
697         return status;
698 }
699
700 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
701 {
702         NTSTATUS status;
703         struct winbindd_domain *domain;
704         struct rpc_pipe_client *netlogon_pipe;
705         union netr_CONTROL_QUERY_INFORMATION info;
706         WERROR werr;
707         fstring logon_server;
708         struct dcerpc_binding_handle *b;
709
710         domain = wb_child_domain();
711         if (domain == NULL) {
712                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
713         }
714
715         status = cm_connect_netlogon(domain, &netlogon_pipe);
716         reset_cm_connection_on_error(domain, status);
717         if (!NT_STATUS_IS_OK(status)) {
718                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
719                 return status;
720         }
721
722         b = netlogon_pipe->binding_handle;
723
724         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
725         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
726         if (r->out.dcname == NULL) {
727                 DEBUG(2, ("Could not allocate memory\n"));
728                 return NT_STATUS_NO_MEMORY;
729         }
730
731         /*
732          * This provokes a WERR_NOT_SUPPORTED error message. This is
733          * documented in the wspp docs. I could not get a successful
734          * call to work, but the main point here is testing that the
735          * netlogon pipe works.
736          */
737         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
738                                           logon_server, NETLOGON_CONTROL_QUERY,
739                                           2, &info, &werr);
740
741         reset_cm_connection_on_error(domain, status);
742         if (!NT_STATUS_IS_OK(status)) {
743                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
744                         nt_errstr(status)));
745                 return status;
746         }
747
748         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
749                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
750                           "WERR_NOT_SUPPORTED\n",
751                           win_errstr(werr)));
752                 return werror_to_ntstatus(werr);
753         }
754
755         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
756         return NT_STATUS_OK;
757 }