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