winbindd: Use dom_sid_str_buf
[nivanova/samba-autobuild/.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_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
31 #include "idmap.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
34 #include "passdb.h"
35 #include "../source4/dsdb/samdb/samdb.h"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
38 #include "libsmb/dsgetdcname.h"
39
40 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
41 {
42         *r->out.out_data = r->in.in_data;
43 }
44
45 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
46                                   struct dcerpc_binding_handle *b,
47                                   NTSTATUS status)
48 {
49         if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
50             NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
51             NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
52                 invalidate_cm_connection(domain);
53                 domain->conn.netlogon_force_reauth = true;
54                 return true;
55         }
56
57         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
58             NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
59         {
60                 invalidate_cm_connection(domain);
61                 /* We invalidated the connection. */
62                 return true;
63         }
64
65         if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
66                 invalidate_cm_connection(domain);
67                 return true;
68         }
69
70         return false;
71 }
72
73 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
74 {
75         struct winbindd_domain *domain = wb_child_domain();
76         char *dom_name;
77         char *name;
78         enum lsa_SidType type;
79         NTSTATUS status;
80
81         if (domain == NULL) {
82                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
83         }
84
85         status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
86                                       &dom_name, &name, &type);
87         reset_cm_connection_on_error(domain, NULL, status);
88         if (!NT_STATUS_IS_OK(status)) {
89                 return status;
90         }
91
92         *r->out.domain = dom_name;
93         *r->out.name = name;
94         *r->out.type = type;
95         return NT_STATUS_OK;
96 }
97
98 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
99 {
100         struct winbindd_domain *domain = wb_child_domain();
101         struct lsa_RefDomainList *domains = r->out.domains;
102         NTSTATUS status;
103         bool retry = false;
104
105         if (domain == NULL) {
106                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
107         }
108
109         /*
110          * This breaks the winbindd_domain->methods abstraction: This
111          * is only called for remote domains, and both winbindd_msrpc
112          * and winbindd_ad call into lsa_lookupsids anyway. Caching is
113          * done at the wbint RPC layer.
114          */
115 again:
116         status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
117                                  &domains, &r->out.names);
118
119         if (domains != NULL) {
120                 r->out.domains = domains;
121         }
122
123         if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
124                 retry = true;
125                 goto again;
126         }
127
128         return status;
129 }
130
131 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
132 {
133         struct winbindd_domain *domain = wb_child_domain();
134         NTSTATUS status;
135
136         if (domain == NULL) {
137                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
138         }
139
140         status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
141                                       r->in.name, r->in.flags,
142                                       r->out.sid, r->out.type);
143         reset_cm_connection_on_error(domain, NULL, status);
144         return status;
145 }
146
147 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
148                              struct wbint_Sids2UnixIDs *r)
149 {
150         uint32_t i;
151
152         struct lsa_DomainInfo *d;
153         struct wbint_TransID *ids;
154         uint32_t num_ids;
155
156         struct id_map **id_map_ptrs = NULL;
157         struct idmap_domain *dom;
158         NTSTATUS status = NT_STATUS_NO_MEMORY;
159
160         if (r->in.domains->count != 1) {
161                 return NT_STATUS_INVALID_PARAMETER;
162         }
163
164         d = &r->in.domains->domains[0];
165         ids = r->in.ids->ids;
166         num_ids = r->in.ids->num_ids;
167
168         dom = idmap_find_domain_with_sid(d->name.string, d->sid);
169         if (dom == NULL) {
170                 struct dom_sid_buf buf;
171                 DEBUG(10, ("idmap domain %s:%s not found\n",
172                            d->name.string,
173                            dom_sid_str_buf(d->sid, &buf)));
174
175                 for (i=0; i<num_ids; i++) {
176
177                         ids[i].xid = (struct unixid) {
178                                 .id = UINT32_MAX,
179                                 .type = ID_TYPE_NOT_SPECIFIED
180                         };
181                 }
182
183                 return NT_STATUS_OK;
184         }
185
186         id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
187         if (id_map_ptrs == NULL) {
188                 goto nomem;
189         }
190
191         /*
192          * Convert the input data into a list of id_map structs
193          * suitable for handing in to the idmap sids_to_unixids
194          * method.
195          */
196
197         for (i=0; i<num_ids; i++) {
198                 struct id_map *m = id_map_ptrs[i];
199
200                 sid_compose(m->sid, d->sid, ids[i].rid);
201                 m->status = ID_UNKNOWN;
202                 m->xid = (struct unixid) { .type = ids[i].type };
203         }
204
205         status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
206
207         if (!NT_STATUS_IS_OK(status)) {
208                 DEBUG(10, ("sids_to_unixids returned %s\n",
209                            nt_errstr(status)));
210                 goto done;
211         }
212
213         /*
214          * Extract the results for handing them back to the caller.
215          */
216
217         for (i=0; i<num_ids; i++) {
218                 struct id_map *m = id_map_ptrs[i];
219
220                 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
221                         DBG_DEBUG("id %"PRIu32" is out of range "
222                                   "%"PRIu32"-%"PRIu32" for domain %s\n",
223                                   m->xid.id, dom->low_id, dom->high_id,
224                                   dom->name);
225                         m->status = ID_UNMAPPED;
226                 }
227
228                 if (m->status == ID_MAPPED) {
229                         ids[i].xid = m->xid;
230                 } else {
231                         ids[i].xid.id = UINT32_MAX;
232                         ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
233                 }
234         }
235
236         goto done;
237 nomem:
238         status = NT_STATUS_NO_MEMORY;
239 done:
240         TALLOC_FREE(id_map_ptrs);
241         return status;
242 }
243
244 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
245                              struct wbint_UnixIDs2Sids *r)
246 {
247         struct id_map **maps;
248         NTSTATUS status;
249         uint32_t i;
250
251         maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
252         if (maps == NULL) {
253                 return NT_STATUS_NO_MEMORY;
254         }
255
256         for (i=0; i<r->in.num_ids; i++) {
257                 maps[i]->status = ID_UNKNOWN;
258                 maps[i]->xid = r->in.xids[i];
259         }
260
261         status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
262                                                r->in.domain_sid);
263         if (!NT_STATUS_IS_OK(status)) {
264                 TALLOC_FREE(maps);
265                 return status;
266         }
267
268         for (i=0; i<r->in.num_ids; i++) {
269                 r->out.xids[i] = maps[i]->xid;
270                 sid_copy(&r->out.sids[i], maps[i]->sid);
271         }
272
273         TALLOC_FREE(maps);
274
275         return NT_STATUS_OK;
276 }
277
278 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
279 {
280         struct unixid xid;
281         NTSTATUS status;
282
283         status = idmap_allocate_uid(&xid);
284         if (!NT_STATUS_IS_OK(status)) {
285                 return status;
286         }
287         *r->out.uid = xid.id;
288         return NT_STATUS_OK;
289 }
290
291 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
292 {
293         struct unixid xid;
294         NTSTATUS status;
295
296         status = idmap_allocate_gid(&xid);
297         if (!NT_STATUS_IS_OK(status)) {
298                 return status;
299         }
300         *r->out.gid = xid.id;
301         return NT_STATUS_OK;
302 }
303
304 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
305 {
306         struct idmap_domain *domain;
307         NTSTATUS status;
308
309         domain = idmap_find_domain(r->in.info->domain_name);
310         if ((domain == NULL) || (domain->query_user == NULL)) {
311                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
312         }
313
314         status = domain->query_user(domain, r->in.info);
315         return status;
316 }
317
318 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
319                                   struct wbint_LookupUserAliases *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 = wb_cache_lookup_useraliases(domain, p->mem_ctx,
329                                              r->in.sids->num_sids,
330                                              r->in.sids->sids,
331                                              &r->out.rids->num_rids,
332                                              &r->out.rids->rids);
333         reset_cm_connection_on_error(domain, NULL, status);
334         return status;
335 }
336
337 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
338                                  struct wbint_LookupUserGroups *r)
339 {
340         struct winbindd_domain *domain = wb_child_domain();
341         NTSTATUS status;
342
343         if (domain == NULL) {
344                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
345         }
346
347         status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
348                                             &r->out.sids->num_sids,
349                                             &r->out.sids->sids);
350         reset_cm_connection_on_error(domain, NULL, status);
351         return status;
352 }
353
354 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
355                                     struct wbint_QuerySequenceNumber *r)
356 {
357         struct winbindd_domain *domain = wb_child_domain();
358         NTSTATUS status;
359
360         if (domain == NULL) {
361                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
362         }
363
364         status = wb_cache_sequence_number(domain, r->out.sequence);
365         reset_cm_connection_on_error(domain, NULL, status);
366         return status;
367 }
368
369 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
370                                    struct wbint_LookupGroupMembers *r)
371 {
372         struct winbindd_domain *domain = wb_child_domain();
373         uint32_t i, num_names;
374         struct dom_sid *sid_mem;
375         char **names;
376         uint32_t *name_types;
377         NTSTATUS status;
378
379         if (domain == NULL) {
380                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
381         }
382
383         status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
384                                           r->in.type, &num_names, &sid_mem,
385                                           &names, &name_types);
386         reset_cm_connection_on_error(domain, NULL, status);
387         if (!NT_STATUS_IS_OK(status)) {
388                 return status;
389         }
390
391         r->out.members->num_principals = num_names;
392         r->out.members->principals = talloc_array(
393                 r->out.members, struct wbint_Principal, num_names);
394         if (r->out.members->principals == NULL) {
395                 return NT_STATUS_NO_MEMORY;
396         }
397
398         for (i=0; i<num_names; i++) {
399                 struct wbint_Principal *m = &r->out.members->principals[i];
400                 sid_copy(&m->sid, &sid_mem[i]);
401                 m->name = talloc_move(r->out.members->principals, &names[i]);
402                 m->type = (enum lsa_SidType)name_types[i];
403         }
404
405         return NT_STATUS_OK;
406 }
407
408 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
409                                struct wbint_QueryGroupList *r)
410 {
411         TALLOC_CTX *frame = NULL;
412         struct winbindd_domain *domain = wb_child_domain();
413         uint32_t i;
414         uint32_t num_local_groups = 0;
415         struct wb_acct_info *local_groups = NULL;
416         uint32_t num_dom_groups = 0;
417         struct wb_acct_info *dom_groups = NULL;
418         uint32_t ti = 0;
419         uint64_t num_total = 0;
420         struct wbint_Principal *result;
421         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
422         bool include_local_groups = false;
423
424         if (domain == NULL) {
425                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
426         }
427
428         frame = talloc_stackframe();
429
430         switch (lp_server_role()) {
431         case ROLE_ACTIVE_DIRECTORY_DC:
432                 if (domain->internal) {
433                         /*
434                          * we want to include local groups
435                          * for BUILTIN and WORKGROUP
436                          */
437                         include_local_groups = true;
438                 }
439                 break;
440         default:
441                 /*
442                  * We might include local groups in more
443                  * setups later, but that requires more work
444                  * elsewhere.
445                  */
446                 break;
447         }
448
449         if (include_local_groups) {
450                 status = wb_cache_enum_local_groups(domain, frame,
451                                                     &num_local_groups,
452                                                     &local_groups);
453                 reset_cm_connection_on_error(domain, NULL, status);
454                 if (!NT_STATUS_IS_OK(status)) {
455                         goto out;
456                 }
457         }
458
459         status = wb_cache_enum_dom_groups(domain, frame,
460                                           &num_dom_groups,
461                                           &dom_groups);
462         reset_cm_connection_on_error(domain, NULL, status);
463         if (!NT_STATUS_IS_OK(status)) {
464                 goto out;
465         }
466
467         num_total = num_local_groups + num_dom_groups;
468         if (num_total > UINT32_MAX) {
469                 status = NT_STATUS_INTERNAL_ERROR;
470                 goto out;
471         }
472
473         result = talloc_array(frame, struct wbint_Principal, num_total);
474         if (result == NULL) {
475                 status = NT_STATUS_NO_MEMORY;
476                 goto out;
477         }
478
479         for (i = 0; i < num_local_groups; i++) {
480                 struct wb_acct_info *lg = &local_groups[i];
481                 struct wbint_Principal *rg = &result[ti++];
482
483                 sid_compose(&rg->sid, &domain->sid, lg->rid);
484                 rg->type = SID_NAME_ALIAS;
485                 rg->name = talloc_strdup(result, lg->acct_name);
486                 if (rg->name == NULL) {
487                         status = NT_STATUS_NO_MEMORY;
488                         goto out;
489                 }
490         }
491         num_local_groups = 0;
492
493         for (i = 0; i < num_dom_groups; i++) {
494                 struct wb_acct_info *dg = &dom_groups[i];
495                 struct wbint_Principal *rg = &result[ti++];
496
497                 sid_compose(&rg->sid, &domain->sid, dg->rid);
498                 rg->type = SID_NAME_DOM_GRP;
499                 rg->name = talloc_strdup(result, dg->acct_name);
500                 if (rg->name == NULL) {
501                         status = NT_STATUS_NO_MEMORY;
502                         goto out;
503                 }
504         }
505         num_dom_groups = 0;
506
507         r->out.groups->num_principals = ti;
508         r->out.groups->principals = talloc_move(r->out.groups, &result);
509
510         status = NT_STATUS_OK;
511 out:
512         TALLOC_FREE(frame);
513         return status;
514 }
515
516 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
517                                  struct wbint_QueryUserRidList *r)
518 {
519         struct winbindd_domain *domain = wb_child_domain();
520         NTSTATUS status;
521
522         if (domain == NULL) {
523                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
524         }
525
526         /*
527          * Right now this is overkill. We should add a backend call
528          * just querying the rids.
529          */
530
531         status = wb_cache_query_user_list(domain, p->mem_ctx,
532                                           &r->out.rids->rids);
533         reset_cm_connection_on_error(domain, NULL, status);
534
535         if (!NT_STATUS_IS_OK(status)) {
536                 return status;
537         }
538
539         r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
540
541         return NT_STATUS_OK;
542 }
543
544 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
545 {
546         struct winbindd_domain *domain = wb_child_domain();
547         struct rpc_pipe_client *netlogon_pipe;
548         struct netr_DsRGetDCNameInfo *dc_info;
549         NTSTATUS status;
550         WERROR werr;
551         unsigned int orig_timeout;
552         struct dcerpc_binding_handle *b;
553         bool retry = false;
554         bool try_dsrgetdcname = false;
555
556         if (domain == NULL) {
557                 return dsgetdcname(p->mem_ctx, global_messaging_context(),
558                                    r->in.domain_name, r->in.domain_guid,
559                                    r->in.site_name ? r->in.site_name : "",
560                                    r->in.flags,
561                                    r->out.dc_info);
562         }
563
564         if (domain->active_directory) {
565                 try_dsrgetdcname = true;
566         }
567
568 reconnect:
569         status = cm_connect_netlogon(domain, &netlogon_pipe);
570
571         reset_cm_connection_on_error(domain, NULL, status);
572         if (!NT_STATUS_IS_OK(status)) {
573                 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
574                 return status;
575         }
576
577         b = netlogon_pipe->binding_handle;
578
579         /* This call can take a long time - allow the server to time out.
580            35 seconds should do it. */
581
582         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
583
584         if (try_dsrgetdcname) {
585                 status = dcerpc_netr_DsRGetDCName(b,
586                         p->mem_ctx, domain->dcname,
587                         r->in.domain_name, NULL, r->in.domain_guid,
588                         r->in.flags, r->out.dc_info, &werr);
589                 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
590                         goto done;
591                 }
592                 if (!retry &&
593                     reset_cm_connection_on_error(domain, NULL, status))
594                 {
595                         retry = true;
596                         goto reconnect;
597                 }
598                 try_dsrgetdcname = false;
599                 retry = false;
600         }
601
602         /*
603          * Fallback to less capable methods
604          */
605
606         dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
607         if (dc_info == NULL) {
608                 status = NT_STATUS_NO_MEMORY;
609                 goto done;
610         }
611
612         if (r->in.flags & DS_PDC_REQUIRED) {
613                 status = dcerpc_netr_GetDcName(b,
614                         p->mem_ctx, domain->dcname,
615                         r->in.domain_name, &dc_info->dc_unc, &werr);
616         } else {
617                 status = dcerpc_netr_GetAnyDCName(b,
618                         p->mem_ctx, domain->dcname,
619                         r->in.domain_name, &dc_info->dc_unc, &werr);
620         }
621
622         if (!retry && reset_cm_connection_on_error(domain, b, status)) {
623                 retry = true;
624                 goto reconnect;
625         }
626         if (!NT_STATUS_IS_OK(status)) {
627                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
628                            nt_errstr(status)));
629                 goto done;
630         }
631         if (!W_ERROR_IS_OK(werr)) {
632                 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
633                            win_errstr(werr)));
634                 status = werror_to_ntstatus(werr);
635                 goto done;
636         }
637
638         *r->out.dc_info = dc_info;
639         status = NT_STATUS_OK;
640
641 done:
642         /* And restore our original timeout. */
643         rpccli_set_timeout(netlogon_pipe, orig_timeout);
644
645         return status;
646 }
647
648 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
649 {
650         struct winbindd_domain *domain = wb_child_domain();
651         char *domain_name;
652         char **names;
653         enum lsa_SidType *types;
654         struct wbint_Principal *result;
655         NTSTATUS status;
656         uint32_t i;
657
658         if (domain == NULL) {
659                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
660         }
661
662         status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
663                                         r->in.rids->rids, r->in.rids->num_rids,
664                                         &domain_name, &names, &types);
665         reset_cm_connection_on_error(domain, NULL, status);
666         if (!NT_STATUS_IS_OK(status)) {
667                 return status;
668         }
669
670         *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
671
672         result = talloc_array(p->mem_ctx, struct wbint_Principal,
673                               r->in.rids->num_rids);
674         if (result == NULL) {
675                 return NT_STATUS_NO_MEMORY;
676         }
677
678         for (i=0; i<r->in.rids->num_rids; i++) {
679                 sid_compose(&result[i].sid, r->in.domain_sid,
680                             r->in.rids->rids[i]);
681                 result[i].type = types[i];
682                 result[i].name = talloc_move(result, &names[i]);
683         }
684         TALLOC_FREE(types);
685         TALLOC_FREE(names);
686
687         r->out.names->num_principals = r->in.rids->num_rids;
688         r->out.names->principals = result;
689         return NT_STATUS_OK;
690 }
691
692 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
693                                     struct wbint_CheckMachineAccount *r)
694 {
695         struct winbindd_domain *domain;
696         int num_retries = 0;
697         NTSTATUS status;
698
699         domain = wb_child_domain();
700         if (domain == NULL) {
701                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
702         }
703
704 again:
705         invalidate_cm_connection(domain);
706         domain->conn.netlogon_force_reauth = true;
707
708         {
709                 struct rpc_pipe_client *netlogon_pipe = NULL;
710                 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
711                 status = cm_connect_netlogon_secure(domain,
712                                                     &netlogon_pipe,
713                                                     &netlogon_creds_ctx);
714         }
715
716         /* There is a race condition between fetching the trust account
717            password and the periodic machine password change.  So it's
718            possible that the trust account password has been changed on us.
719            We are returned NT_STATUS_ACCESS_DENIED if this happens. */
720
721 #define MAX_RETRIES 3
722
723         if ((num_retries < MAX_RETRIES)
724             && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
725                 num_retries++;
726                 goto again;
727         }
728
729         if (!NT_STATUS_IS_OK(status)) {
730                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
731                 goto done;
732         }
733
734         /* Pass back result code - zero for success, other values for
735            specific failures. */
736
737         DEBUG(3,("domain %s secret is %s\n", domain->name,
738                 NT_STATUS_IS_OK(status) ? "good" : "bad"));
739
740  done:
741         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
742               ("Checking the trust account password for domain %s returned %s\n",
743                domain->name, nt_errstr(status)));
744
745         return status;
746 }
747
748 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
749                                      struct wbint_ChangeMachineAccount *r)
750 {
751         struct messaging_context *msg_ctx = global_messaging_context();
752         struct winbindd_domain *domain;
753         NTSTATUS status;
754         struct rpc_pipe_client *netlogon_pipe = NULL;
755         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
756
757         domain = wb_child_domain();
758         if (domain == NULL) {
759                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
760         }
761
762         status = cm_connect_netlogon_secure(domain,
763                                             &netlogon_pipe,
764                                             &netlogon_creds_ctx);
765         if (!NT_STATUS_IS_OK(status)) {
766                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
767                 goto done;
768         }
769
770         status = trust_pw_change(netlogon_creds_ctx,
771                                  msg_ctx,
772                                  netlogon_pipe->binding_handle,
773                                  domain->name,
774                                  domain->dcname,
775                                  true); /* force */
776
777         /* Pass back result code - zero for success, other values for
778            specific failures. */
779
780         DEBUG(3,("domain %s secret %s\n", domain->name,
781                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
782
783  done:
784         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
785               ("Changing the trust account password for domain %s returned %s\n",
786                domain->name, nt_errstr(status)));
787
788         return status;
789 }
790
791 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
792 {
793         NTSTATUS status;
794         struct winbindd_domain *domain;
795         struct rpc_pipe_client *netlogon_pipe;
796         union netr_CONTROL_QUERY_INFORMATION info;
797         WERROR werr;
798         fstring logon_server;
799         struct dcerpc_binding_handle *b;
800         bool retry = false;
801
802         domain = wb_child_domain();
803         if (domain == NULL) {
804                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
805         }
806
807 reconnect:
808         status = cm_connect_netlogon(domain, &netlogon_pipe);
809         reset_cm_connection_on_error(domain, NULL, status);
810         if (!NT_STATUS_IS_OK(status)) {
811                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
812                           nt_errstr(status)));
813                 return status;
814         }
815
816         b = netlogon_pipe->binding_handle;
817
818         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
819         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
820         if (*r->out.dcname == NULL) {
821                 DEBUG(2, ("Could not allocate memory\n"));
822                 return NT_STATUS_NO_MEMORY;
823         }
824
825         /*
826          * This provokes a WERR_NOT_SUPPORTED error message. This is
827          * documented in the wspp docs. I could not get a successful
828          * call to work, but the main point here is testing that the
829          * netlogon pipe works.
830          */
831         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
832                                           logon_server, NETLOGON_CONTROL_QUERY,
833                                           2, &info, &werr);
834
835         if (!retry && reset_cm_connection_on_error(domain, b, status)) {
836                 retry = true;
837                 goto reconnect;
838         }
839
840         if (!NT_STATUS_IS_OK(status)) {
841                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
842                         nt_errstr(status)));
843                 return status;
844         }
845
846         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
847                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
848                           "WERR_NOT_SUPPORTED\n",
849                           win_errstr(werr)));
850                 return werror_to_ntstatus(werr);
851         }
852
853         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
854         return NT_STATUS_OK;
855 }
856
857 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
858                                                     struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
859 {
860         struct winbindd_domain *domain;
861         NTSTATUS status;
862         struct rpc_pipe_client *netlogon_pipe = NULL;
863         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
864         struct dcerpc_binding_handle *b = NULL;
865         bool retry = false;
866
867         domain = wb_child_domain();
868         if (domain == NULL) {
869                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
870         }
871
872 reconnect:
873         status = cm_connect_netlogon_secure(domain,
874                                             &netlogon_pipe,
875                                             &netlogon_creds_ctx);
876         if (!NT_STATUS_IS_OK(status)) {
877                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
878                 goto done;
879         }
880
881         b = netlogon_pipe->binding_handle;
882
883         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
884                                                                       netlogon_pipe->binding_handle,
885                                                                       r->in.site_name,
886                                                                       r->in.dns_ttl,
887                                                                       r->in.dns_names);
888
889         if (!retry && reset_cm_connection_on_error(domain, b, status)) {
890                 retry = true;
891                 goto reconnect;
892         }
893
894         /* Pass back result code - zero for success, other values for
895            specific failures. */
896
897         DEBUG(3,("DNS records for domain %s %s\n", domain->name,
898                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
899
900  done:
901         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
902               ("Update of DNS records via RW DC %s returned %s\n",
903                domain->name, nt_errstr(status)));
904
905         return status;
906 }
907
908 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
909                         struct winbind_SamLogon *r)
910 {
911         struct winbindd_domain *domain;
912         NTSTATUS status;
913         struct netr_IdentityInfo *identity_info = NULL;
914         const uint8_t chal_zero[8] = {0, };
915         const uint8_t *challenge = chal_zero;
916         DATA_BLOB lm_response, nt_response;
917         uint32_t flags = 0;
918         uint16_t validation_level;
919         union netr_Validation *validation = NULL;
920         bool interactive = false;
921
922         domain = wb_child_domain();
923         if (domain == NULL) {
924                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
925         }
926
927         switch (r->in.validation_level) {
928         case 3:
929         case 6:
930                 break;
931         default:
932                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
933         }
934
935         switch (r->in.logon_level) {
936         case NetlogonInteractiveInformation:
937         case NetlogonServiceInformation:
938         case NetlogonInteractiveTransitiveInformation:
939         case NetlogonServiceTransitiveInformation:
940                 if (r->in.logon.password == NULL) {
941                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
942                 }
943
944                 interactive = true;
945                 identity_info = &r->in.logon.password->identity_info;
946
947                 challenge = chal_zero;
948                 lm_response = data_blob_talloc(p->mem_ctx,
949                                         r->in.logon.password->lmpassword.hash,
950                                         sizeof(r->in.logon.password->lmpassword.hash));
951                 nt_response = data_blob_talloc(p->mem_ctx,
952                                         r->in.logon.password->ntpassword.hash,
953                                         sizeof(r->in.logon.password->ntpassword.hash));
954                 break;
955
956         case NetlogonNetworkInformation:
957         case NetlogonNetworkTransitiveInformation:
958                 if (r->in.logon.network == NULL) {
959                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
960                 }
961
962                 interactive = false;
963                 identity_info = &r->in.logon.network->identity_info;
964
965                 challenge = r->in.logon.network->challenge;
966                 lm_response = data_blob_talloc(p->mem_ctx,
967                                         r->in.logon.network->lm.data,
968                                         r->in.logon.network->lm.length);
969                 nt_response = data_blob_talloc(p->mem_ctx,
970                                         r->in.logon.network->nt.data,
971                                         r->in.logon.network->nt.length);
972                 break;
973
974         case NetlogonGenericInformation:
975                 if (r->in.logon.generic == NULL) {
976                         return NT_STATUS_REQUEST_NOT_ACCEPTED;
977                 }
978
979                 identity_info = &r->in.logon.generic->identity_info;
980                 /*
981                  * Not implemented here...
982                  */
983                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
984
985         default:
986                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
987         }
988
989         status = winbind_dual_SamLogon(domain, p->mem_ctx,
990                                        interactive,
991                                        identity_info->parameter_control,
992                                        identity_info->account_name.string,
993                                        identity_info->domain_name.string,
994                                        identity_info->workstation.string,
995                                        challenge,
996                                        lm_response, nt_response,
997                                        &r->out.authoritative,
998                                        true, /* skip_sam */
999                                        &flags,
1000                                        &validation_level,
1001                                        &validation);
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 return status;
1004         }
1005         switch (r->in.validation_level) {
1006         case 3:
1007                 status = map_validation_to_info3(p->mem_ctx,
1008                                                  validation_level,
1009                                                  validation,
1010                                                  &r->out.validation.sam3);
1011                 TALLOC_FREE(validation);
1012                 if (!NT_STATUS_IS_OK(status)) {
1013                         return status;
1014                 }
1015                 return NT_STATUS_OK;
1016         case 6:
1017                 status = map_validation_to_info6(p->mem_ctx,
1018                                                  validation_level,
1019                                                  validation,
1020                                                  &r->out.validation.sam6);
1021                 TALLOC_FREE(validation);
1022                 if (!NT_STATUS_IS_OK(status)) {
1023                         return status;
1024                 }
1025                 return NT_STATUS_OK;
1026         }
1027
1028         smb_panic(__location__);
1029         return NT_STATUS_INTERNAL_ERROR;
1030 }
1031
1032 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1033                              struct winbindd_domain *domain,
1034                              struct winbind_LogonControl *r)
1035 {
1036         NTSTATUS status;
1037         struct rpc_pipe_client *netlogon_pipe = NULL;
1038         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1039         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1040         WERROR check_result = WERR_INTERNAL_ERROR;
1041
1042         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1043         if (info2 == NULL) {
1044                 return WERR_NOT_ENOUGH_MEMORY;
1045         }
1046
1047         if (domain->internal) {
1048                 check_result = WERR_OK;
1049                 goto check_return;
1050         }
1051
1052         /*
1053          * For now we just force a reconnect
1054          *
1055          * TODO: take care of the optional '\dcname'
1056          */
1057         invalidate_cm_connection(domain);
1058         domain->conn.netlogon_force_reauth = true;
1059         status = cm_connect_netlogon_secure(domain,
1060                                             &netlogon_pipe,
1061                                             &netlogon_creds_ctx);
1062         reset_cm_connection_on_error(domain, NULL, status);
1063         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1064                 status = NT_STATUS_NO_LOGON_SERVERS;
1065         }
1066         if (!NT_STATUS_IS_OK(status)) {
1067                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1068                           __func__, domain->name, domain->alt_name,
1069                           nt_errstr(status)));
1070                 /*
1071                  * Here we return a top level error!
1072                  * This is different than TC_QUERY or TC_VERIFY.
1073                  */
1074                 return ntstatus_to_werror(status);
1075         }
1076         check_result = WERR_OK;
1077
1078 check_return:
1079         info2->pdc_connection_status = WERR_OK;
1080         if (domain->dcname != NULL) {
1081                 info2->flags |= NETLOGON_HAS_IP;
1082                 info2->flags |= NETLOGON_HAS_TIMESERV;
1083                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1084                                                          domain->dcname);
1085                 if (info2->trusted_dc_name == NULL) {
1086                         return WERR_NOT_ENOUGH_MEMORY;
1087                 }
1088         } else {
1089                 info2->trusted_dc_name = talloc_strdup(info2, "");
1090                 if (info2->trusted_dc_name == NULL) {
1091                         return WERR_NOT_ENOUGH_MEMORY;
1092                 }
1093         }
1094         info2->tc_connection_status = check_result;
1095
1096         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1097                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1098                           "pdc_connection[%s] tc_connection[%s]\n",
1099                           __func__, domain->name, domain->alt_name,
1100                           domain->dcname,
1101                           win_errstr(info2->pdc_connection_status),
1102                           win_errstr(info2->tc_connection_status)));
1103         }
1104
1105         r->out.query->info2 = info2;
1106
1107         DEBUG(5, ("%s: succeeded.\n", __func__));
1108         return WERR_OK;
1109 }
1110
1111 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1112                              struct winbindd_domain *domain,
1113                              struct winbind_LogonControl *r)
1114 {
1115         NTSTATUS status;
1116         struct rpc_pipe_client *netlogon_pipe = NULL;
1117         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1118         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1119         WERROR check_result = WERR_INTERNAL_ERROR;
1120
1121         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1122         if (info2 == NULL) {
1123                 return WERR_NOT_ENOUGH_MEMORY;
1124         }
1125
1126         if (domain->internal) {
1127                 check_result = WERR_OK;
1128                 goto check_return;
1129         }
1130
1131         status = cm_connect_netlogon_secure(domain,
1132                                             &netlogon_pipe,
1133                                             &netlogon_creds_ctx);
1134         reset_cm_connection_on_error(domain, NULL, status);
1135         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1136                 status = NT_STATUS_NO_LOGON_SERVERS;
1137         }
1138         if (!NT_STATUS_IS_OK(status)) {
1139                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1140                           nt_errstr(status)));
1141                 check_result = ntstatus_to_werror(status);
1142                 goto check_return;
1143         }
1144         check_result = WERR_OK;
1145
1146 check_return:
1147         info2->pdc_connection_status = WERR_OK;
1148         if (domain->dcname != NULL) {
1149                 info2->flags |= NETLOGON_HAS_IP;
1150                 info2->flags |= NETLOGON_HAS_TIMESERV;
1151                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1152                                                          domain->dcname);
1153                 if (info2->trusted_dc_name == NULL) {
1154                         return WERR_NOT_ENOUGH_MEMORY;
1155                 }
1156         } else {
1157                 info2->trusted_dc_name = talloc_strdup(info2, "");
1158                 if (info2->trusted_dc_name == NULL) {
1159                         return WERR_NOT_ENOUGH_MEMORY;
1160                 }
1161         }
1162         info2->tc_connection_status = check_result;
1163
1164         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1165                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1166                           "pdc_connection[%s] tc_connection[%s]\n",
1167                           __func__, domain->name, domain->alt_name,
1168                           domain->dcname,
1169                           win_errstr(info2->pdc_connection_status),
1170                           win_errstr(info2->tc_connection_status)));
1171         }
1172
1173         r->out.query->info2 = info2;
1174
1175         DEBUG(5, ("%s: succeeded.\n", __func__));
1176         return WERR_OK;
1177 }
1178
1179 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1180                              struct winbindd_domain *domain,
1181                              struct winbind_LogonControl *r)
1182 {
1183         TALLOC_CTX *frame = talloc_stackframe();
1184         NTSTATUS status;
1185         NTSTATUS result;
1186         struct lsa_String trusted_domain_name = {};
1187         struct lsa_StringLarge trusted_domain_name_l = {};
1188         struct rpc_pipe_client *local_lsa_pipe = NULL;
1189         struct policy_handle local_lsa_policy = {};
1190         struct dcerpc_binding_handle *local_lsa = NULL;
1191         struct rpc_pipe_client *netlogon_pipe = NULL;
1192         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1193         struct cli_credentials *creds = NULL;
1194         struct samr_Password *cur_nt_hash = NULL;
1195         uint32_t trust_attributes = 0;
1196         struct samr_Password new_owf_password = {};
1197         int cmp_new = -1;
1198         struct samr_Password old_owf_password = {};
1199         int cmp_old = -1;
1200         const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1201         bool fetch_fti = false;
1202         struct lsa_ForestTrustInformation *new_fti = NULL;
1203         struct netr_TrustInfo *trust_info = NULL;
1204         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1205         struct dcerpc_binding_handle *b = NULL;
1206         WERROR check_result = WERR_INTERNAL_ERROR;
1207         WERROR verify_result = WERR_INTERNAL_ERROR;
1208         bool retry = false;
1209
1210         trusted_domain_name.string = domain->name;
1211         trusted_domain_name_l.string = domain->name;
1212
1213         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1214         if (info2 == NULL) {
1215                 TALLOC_FREE(frame);
1216                 return WERR_NOT_ENOUGH_MEMORY;
1217         }
1218
1219         if (domain->internal) {
1220                 check_result = WERR_OK;
1221                 goto check_return;
1222         }
1223
1224         status = pdb_get_trust_credentials(domain->name,
1225                                            domain->alt_name,
1226                                            frame,
1227                                            &creds);
1228         if (NT_STATUS_IS_OK(status)) {
1229                 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1230                 TALLOC_FREE(creds);
1231         }
1232
1233         if (!domain->primary) {
1234                 union lsa_TrustedDomainInfo *tdi = NULL;
1235
1236                 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1237                                                 &local_lsa_policy);
1238                 if (!NT_STATUS_IS_OK(status)) {
1239                         DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1240                                  __location__, __func__, nt_errstr(status)));
1241                         TALLOC_FREE(frame);
1242                         return WERR_INTERNAL_ERROR;
1243                 }
1244                 local_lsa = local_lsa_pipe->binding_handle;
1245
1246                 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1247                                                         &local_lsa_policy,
1248                                                         &trusted_domain_name,
1249                                                         LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1250                                                         &tdi, &result);
1251                 if (!NT_STATUS_IS_OK(status)) {
1252                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1253                                  __location__, __func__, domain->name, nt_errstr(status)));
1254                         TALLOC_FREE(frame);
1255                         return WERR_INTERNAL_ERROR;
1256                 }
1257                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1258                         DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1259                                  __location__, __func__, domain->name));
1260                         TALLOC_FREE(frame);
1261                         return WERR_NO_SUCH_DOMAIN;
1262                 }
1263                 if (!NT_STATUS_IS_OK(result)) {
1264                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1265                                  __location__, __func__, domain->name, nt_errstr(result)));
1266                         TALLOC_FREE(frame);
1267                         return WERR_INTERNAL_ERROR;
1268                 }
1269                 if (tdi == NULL) {
1270                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1271                                  "returned no trusted domain information\n",
1272                                  __location__, __func__));
1273                         TALLOC_FREE(frame);
1274                         return WERR_INTERNAL_ERROR;
1275                 }
1276
1277                 local_tdo = &tdi->info_ex;
1278                 trust_attributes = local_tdo->trust_attributes;
1279         }
1280
1281         if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1282                 struct lsa_ForestTrustInformation *old_fti = NULL;
1283
1284                 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1285                                                         &local_lsa_policy,
1286                                                         &trusted_domain_name,
1287                                                         LSA_FOREST_TRUST_DOMAIN_INFO,
1288                                                         &old_fti, &result);
1289                 if (!NT_STATUS_IS_OK(status)) {
1290                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1291                                  __location__, __func__, domain->name, nt_errstr(status)));
1292                         TALLOC_FREE(frame);
1293                         return WERR_INTERNAL_ERROR;
1294                 }
1295                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1296                         DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1297                                   __func__, domain->name));
1298                         old_fti = NULL;
1299                         fetch_fti = true;
1300                         result = NT_STATUS_OK;
1301                 }
1302                 if (!NT_STATUS_IS_OK(result)) {
1303                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1304                                  __location__, __func__, domain->name, nt_errstr(result)));
1305                         TALLOC_FREE(frame);
1306                         return WERR_INTERNAL_ERROR;
1307                 }
1308
1309                 TALLOC_FREE(old_fti);
1310         }
1311
1312 reconnect:
1313         status = cm_connect_netlogon_secure(domain,
1314                                             &netlogon_pipe,
1315                                             &netlogon_creds_ctx);
1316         reset_cm_connection_on_error(domain, NULL, status);
1317         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1318                 status = NT_STATUS_NO_LOGON_SERVERS;
1319         }
1320         if (!NT_STATUS_IS_OK(status)) {
1321                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1322                           nt_errstr(status)));
1323                 check_result = ntstatus_to_werror(status);
1324                 goto check_return;
1325         }
1326         check_result = WERR_OK;
1327         b = netlogon_pipe->binding_handle;
1328
1329         if (cur_nt_hash == NULL) {
1330                 verify_result = WERR_NO_TRUST_LSA_SECRET;
1331                 goto verify_return;
1332         }
1333
1334         if (fetch_fti) {
1335                 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1336                                                                       b, frame,
1337                                                                       &new_fti);
1338                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1339                         status = NT_STATUS_NOT_SUPPORTED;
1340                 }
1341                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1342                         new_fti = NULL;
1343                         status = NT_STATUS_OK;
1344                 }
1345                 if (!NT_STATUS_IS_OK(status)) {
1346                         if (!retry &&
1347                             reset_cm_connection_on_error(domain, b, status))
1348                         {
1349                                 retry = true;
1350                                 goto reconnect;
1351                         }
1352                         DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1353                                   "failed: %s\n",
1354                                   domain->name, nt_errstr(status)));
1355                         check_result = ntstatus_to_werror(status);
1356                         goto check_return;
1357                 }
1358         }
1359
1360         if (new_fti != NULL) {
1361                 struct lsa_ForestTrustInformation old_fti = {};
1362                 struct lsa_ForestTrustInformation *merged_fti = NULL;
1363                 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1364
1365                 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1366                                                       &old_fti, new_fti,
1367                                                       &merged_fti);
1368                 if (!NT_STATUS_IS_OK(status)) {
1369                         DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1370                                  __location__, __func__,
1371                                  domain->name, nt_errstr(status)));
1372                         TALLOC_FREE(frame);
1373                         return ntstatus_to_werror(status);
1374                 }
1375
1376                 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1377                                                 &local_lsa_policy,
1378                                                 &trusted_domain_name_l,
1379                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1380                                                 merged_fti,
1381                                                 0, /* check_only=0 => store it! */
1382                                                 &collision_info,
1383                                                 &result);
1384                 if (!NT_STATUS_IS_OK(status)) {
1385                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1386                                  __location__, __func__, domain->name, nt_errstr(status)));
1387                         TALLOC_FREE(frame);
1388                         return WERR_INTERNAL_ERROR;
1389                 }
1390                 if (!NT_STATUS_IS_OK(result)) {
1391                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1392                                  __location__, __func__, domain->name, nt_errstr(result)));
1393                         TALLOC_FREE(frame);
1394                         return ntstatus_to_werror(result);
1395                 }
1396         }
1397
1398         status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1399                                                        b, frame,
1400                                                        &new_owf_password,
1401                                                        &old_owf_password,
1402                                                        &trust_info);
1403         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1404                 status = NT_STATUS_NOT_SUPPORTED;
1405         }
1406         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1407                 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1408                         nt_errstr(status)));
1409                 verify_result = WERR_OK;
1410                 goto verify_return;
1411         }
1412         if (!NT_STATUS_IS_OK(status)) {
1413                 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1414                         retry = true;
1415                         goto reconnect;
1416                 }
1417                 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1418                         nt_errstr(status)));
1419
1420                 if (!dcerpc_binding_handle_is_connected(b)) {
1421                         check_result = ntstatus_to_werror(status);
1422                         goto check_return;
1423                 } else {
1424                         verify_result = ntstatus_to_werror(status);
1425                         goto verify_return;
1426                 }
1427         }
1428
1429         if (trust_info != NULL && trust_info->count >= 1) {
1430                 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1431
1432                 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1433                         verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1434                         goto verify_return;
1435                 }
1436         }
1437
1438         cmp_new = memcmp(new_owf_password.hash,
1439                          cur_nt_hash->hash,
1440                          sizeof(cur_nt_hash->hash));
1441         cmp_old = memcmp(old_owf_password.hash,
1442                          cur_nt_hash->hash,
1443                          sizeof(cur_nt_hash->hash));
1444         if (cmp_new != 0 && cmp_old != 0) {
1445                 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1446                          "any password known to dcname[%s]\n",
1447                          __func__, domain->name, domain->alt_name,
1448                          domain->dcname));
1449                 verify_result = WERR_WRONG_PASSWORD;
1450                 goto verify_return;
1451         }
1452
1453         if (cmp_new != 0) {
1454                 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1455                          "against the old password known to dcname[%s]\n",
1456                          __func__, domain->name, domain->alt_name,
1457                          domain->dcname));
1458         }
1459
1460         verify_result = WERR_OK;
1461         goto verify_return;
1462
1463 check_return:
1464         verify_result = check_result;
1465 verify_return:
1466         info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1467         info2->pdc_connection_status = verify_result;
1468         if (domain->dcname != NULL) {
1469                 info2->flags |= NETLOGON_HAS_IP;
1470                 info2->flags |= NETLOGON_HAS_TIMESERV;
1471                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1472                                                          domain->dcname);
1473                 if (info2->trusted_dc_name == NULL) {
1474                         TALLOC_FREE(frame);
1475                         return WERR_NOT_ENOUGH_MEMORY;
1476                 }
1477         } else {
1478                 info2->trusted_dc_name = talloc_strdup(info2, "");
1479                 if (info2->trusted_dc_name == NULL) {
1480                         TALLOC_FREE(frame);
1481                         return WERR_NOT_ENOUGH_MEMORY;
1482                 }
1483         }
1484         info2->tc_connection_status = check_result;
1485
1486         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1487                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1488                           "pdc_connection[%s] tc_connection[%s]\n",
1489                           __func__, domain->name, domain->alt_name,
1490                           domain->dcname,
1491                           win_errstr(info2->pdc_connection_status),
1492                           win_errstr(info2->tc_connection_status)));
1493         }
1494
1495         r->out.query->info2 = info2;
1496
1497         DEBUG(5, ("%s: succeeded.\n", __func__));
1498         TALLOC_FREE(frame);
1499         return WERR_OK;
1500 }
1501
1502 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1503                              struct winbindd_domain *domain,
1504                              struct winbind_LogonControl *r)
1505 {
1506         struct messaging_context *msg_ctx = global_messaging_context();
1507         NTSTATUS status;
1508         struct rpc_pipe_client *netlogon_pipe = NULL;
1509         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1510         struct cli_credentials *creds = NULL;
1511         struct samr_Password *cur_nt_hash = NULL;
1512         struct netr_NETLOGON_INFO_1 *info1 = NULL;
1513         struct dcerpc_binding_handle *b;
1514         WERROR change_result = WERR_OK;
1515         bool retry = false;
1516
1517         info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1518         if (info1 == NULL) {
1519                 return WERR_NOT_ENOUGH_MEMORY;
1520         }
1521
1522         if (domain->internal) {
1523                 return WERR_NOT_SUPPORTED;
1524         }
1525
1526         status = pdb_get_trust_credentials(domain->name,
1527                                            domain->alt_name,
1528                                            p->mem_ctx,
1529                                            &creds);
1530         if (NT_STATUS_IS_OK(status)) {
1531                 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1532                 TALLOC_FREE(creds);
1533         }
1534
1535 reconnect:
1536         status = cm_connect_netlogon_secure(domain,
1537                                             &netlogon_pipe,
1538                                             &netlogon_creds_ctx);
1539         reset_cm_connection_on_error(domain, NULL, status);
1540         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1541                 status = NT_STATUS_NO_LOGON_SERVERS;
1542         }
1543         if (!NT_STATUS_IS_OK(status)) {
1544                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1545                           __func__, domain->name, domain->alt_name,
1546                           nt_errstr(status)));
1547                 /*
1548                  * Here we return a top level error!
1549                  * This is different than TC_QUERY or TC_VERIFY.
1550                  */
1551                 return ntstatus_to_werror(status);
1552         }
1553         b = netlogon_pipe->binding_handle;
1554
1555         if (cur_nt_hash == NULL) {
1556                 change_result = WERR_NO_TRUST_LSA_SECRET;
1557                 goto change_return;
1558         }
1559         TALLOC_FREE(cur_nt_hash);
1560
1561         status = trust_pw_change(netlogon_creds_ctx,
1562                                  msg_ctx, b, domain->name,
1563                                  domain->dcname,
1564                                  true); /* force */
1565         if (!NT_STATUS_IS_OK(status)) {
1566                 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1567                         retry = true;
1568                         goto reconnect;
1569                 }
1570
1571                 DEBUG(1, ("trust_pw_change(%s): %s\n",
1572                           domain->name, nt_errstr(status)));
1573
1574                 change_result = ntstatus_to_werror(status);
1575                 goto change_return;
1576         }
1577
1578         change_result = WERR_OK;
1579
1580 change_return:
1581         info1->pdc_connection_status = change_result;
1582
1583         if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1584                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1585                           "pdc_connection[%s]\n",
1586                           __func__, domain->name, domain->alt_name,
1587                           domain->dcname,
1588                           win_errstr(info1->pdc_connection_status)));
1589         }
1590
1591         r->out.query->info1 = info1;
1592
1593         DEBUG(5, ("%s: succeeded.\n", __func__));
1594         return WERR_OK;
1595 }
1596
1597 WERROR _winbind_LogonControl(struct pipes_struct *p,
1598                              struct winbind_LogonControl *r)
1599 {
1600         struct winbindd_domain *domain;
1601
1602         domain = wb_child_domain();
1603         if (domain == NULL) {
1604                 return WERR_NO_SUCH_DOMAIN;
1605         }
1606
1607         switch (r->in.function_code) {
1608         case NETLOGON_CONTROL_REDISCOVER:
1609                 if (r->in.level != 2) {
1610                         return WERR_INVALID_PARAMETER;
1611                 }
1612                 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1613         case NETLOGON_CONTROL_TC_QUERY:
1614                 if (r->in.level != 2) {
1615                         return WERR_INVALID_PARAMETER;
1616                 }
1617                 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1618         case NETLOGON_CONTROL_TC_VERIFY:
1619                 if (r->in.level != 2) {
1620                         return WERR_INVALID_PARAMETER;
1621                 }
1622                 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1623         case NETLOGON_CONTROL_CHANGE_PASSWORD:
1624                 if (r->in.level != 1) {
1625                         return WERR_INVALID_PARAMETER;
1626                 }
1627                 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1628         default:
1629                 break;
1630         }
1631
1632         DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1633                   __func__, r->in.function_code));
1634         return WERR_NOT_SUPPORTED;
1635 }
1636
1637 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1638                              struct winbind_GetForestTrustInformation *r)
1639 {
1640         TALLOC_CTX *frame = talloc_stackframe();
1641         NTSTATUS status, result;
1642         struct winbindd_domain *domain;
1643         struct rpc_pipe_client *netlogon_pipe = NULL;
1644         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1645         struct dcerpc_binding_handle *b;
1646         bool retry = false;
1647         struct lsa_String trusted_domain_name = {};
1648         struct lsa_StringLarge trusted_domain_name_l = {};
1649         union lsa_TrustedDomainInfo *tdi = NULL;
1650         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1651         struct lsa_ForestTrustInformation _old_fti = {};
1652         struct lsa_ForestTrustInformation *old_fti = NULL;
1653         struct lsa_ForestTrustInformation *new_fti = NULL;
1654         struct lsa_ForestTrustInformation *merged_fti = NULL;
1655         struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1656         bool update_fti = false;
1657         struct rpc_pipe_client *local_lsa_pipe;
1658         struct policy_handle local_lsa_policy;
1659         struct dcerpc_binding_handle *local_lsa = NULL;
1660
1661         domain = wb_child_domain();
1662         if (domain == NULL) {
1663                 TALLOC_FREE(frame);
1664                 return WERR_NO_SUCH_DOMAIN;
1665         }
1666
1667         /*
1668          * checking for domain->internal and domain->primary
1669          * makes sure we only do some work when running as DC.
1670          */
1671
1672         if (domain->internal) {
1673                 TALLOC_FREE(frame);
1674                 return WERR_NO_SUCH_DOMAIN;
1675         }
1676
1677         if (domain->primary) {
1678                 TALLOC_FREE(frame);
1679                 return WERR_NO_SUCH_DOMAIN;
1680         }
1681
1682         trusted_domain_name.string = domain->name;
1683         trusted_domain_name_l.string = domain->name;
1684
1685         status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1686                                         &local_lsa_policy);
1687         if (!NT_STATUS_IS_OK(status)) {
1688                 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1689                          __location__, __func__, nt_errstr(status)));
1690                 TALLOC_FREE(frame);
1691                 return WERR_INTERNAL_ERROR;
1692         }
1693         local_lsa = local_lsa_pipe->binding_handle;
1694
1695         status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1696                                                 &local_lsa_policy,
1697                                                 &trusted_domain_name,
1698                                                 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1699                                                 &tdi, &result);
1700         if (!NT_STATUS_IS_OK(status)) {
1701                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1702                          __location__, __func__, domain->name, nt_errstr(status)));
1703                 TALLOC_FREE(frame);
1704                 return WERR_INTERNAL_ERROR;
1705         }
1706         if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1707                 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1708                          __location__, __func__, domain->name));
1709                 TALLOC_FREE(frame);
1710                 return WERR_NO_SUCH_DOMAIN;
1711         }
1712         if (!NT_STATUS_IS_OK(result)) {
1713                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1714                          __location__, __func__, domain->name, nt_errstr(result)));
1715                 TALLOC_FREE(frame);
1716                 return WERR_INTERNAL_ERROR;
1717         }
1718         if (tdi == NULL) {
1719                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1720                          "returned no trusted domain information\n",
1721                          __location__, __func__));
1722                 TALLOC_FREE(frame);
1723                 return WERR_INTERNAL_ERROR;
1724         }
1725
1726         tdo = &tdi->info_ex;
1727
1728         if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1729                 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1730                          __func__, tdo->netbios_name.string,
1731                          tdo->domain_name.string,
1732                          (unsigned)tdo->trust_attributes));
1733                 TALLOC_FREE(frame);
1734                 return WERR_NO_SUCH_DOMAIN;
1735         }
1736
1737         if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1738                 TALLOC_FREE(frame);
1739                 return WERR_INVALID_FLAGS;
1740         }
1741
1742 reconnect:
1743         status = cm_connect_netlogon_secure(domain,
1744                                             &netlogon_pipe,
1745                                             &netlogon_creds_ctx);
1746         reset_cm_connection_on_error(domain, NULL, status);
1747         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1748                 status = NT_STATUS_NO_LOGON_SERVERS;
1749         }
1750         if (!NT_STATUS_IS_OK(status)) {
1751                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1752                           nt_errstr(status)));
1753                 TALLOC_FREE(frame);
1754                 return ntstatus_to_werror(status);
1755         }
1756         b = netlogon_pipe->binding_handle;
1757
1758         status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1759                                                               b, p->mem_ctx,
1760                                                               &new_fti);
1761         if (!NT_STATUS_IS_OK(status)) {
1762                 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1763                         retry = true;
1764                         goto reconnect;
1765                 }
1766                 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1767                           domain->name, nt_errstr(status)));
1768                 TALLOC_FREE(frame);
1769                 return ntstatus_to_werror(status);
1770         }
1771
1772         *r->out.forest_trust_info = new_fti;
1773
1774         if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1775                 update_fti = true;
1776         }
1777
1778         status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1779                                                 &local_lsa_policy,
1780                                                 &trusted_domain_name,
1781                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1782                                                 &old_fti, &result);
1783         if (!NT_STATUS_IS_OK(status)) {
1784                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1785                          __location__, __func__, domain->name, nt_errstr(status)));
1786                 TALLOC_FREE(frame);
1787                 return WERR_INTERNAL_ERROR;
1788         }
1789         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1790                 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1791                           __func__, domain->name));
1792                 update_fti = true;
1793                 old_fti = &_old_fti;
1794                 result = NT_STATUS_OK;
1795         }
1796         if (!NT_STATUS_IS_OK(result)) {
1797                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1798                          __location__, __func__, domain->name, nt_errstr(result)));
1799                 TALLOC_FREE(frame);
1800                 return WERR_INTERNAL_ERROR;
1801         }
1802
1803         if (old_fti == NULL) {
1804                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1805                          "returned success without returning forest trust information\n",
1806                          __location__, __func__));
1807                 TALLOC_FREE(frame);
1808                 return WERR_INTERNAL_ERROR;
1809         }
1810
1811         if (!update_fti) {
1812                 goto done;
1813         }
1814
1815         status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1816                                               &merged_fti);
1817         if (!NT_STATUS_IS_OK(status)) {
1818                 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1819                          __location__, __func__, domain->name, nt_errstr(status)));
1820                 TALLOC_FREE(frame);
1821                 return ntstatus_to_werror(status);
1822         }
1823
1824         status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1825                                                 &local_lsa_policy,
1826                                                 &trusted_domain_name_l,
1827                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1828                                                 merged_fti,
1829                                                 0, /* check_only=0 => store it! */
1830                                                 &collision_info,
1831                                                 &result);
1832         if (!NT_STATUS_IS_OK(status)) {
1833                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1834                          __location__, __func__, domain->name, nt_errstr(status)));
1835                 TALLOC_FREE(frame);
1836                 return WERR_INTERNAL_ERROR;
1837         }
1838         if (!NT_STATUS_IS_OK(result)) {
1839                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1840                          __location__, __func__, domain->name, nt_errstr(result)));
1841                 TALLOC_FREE(frame);
1842                 return ntstatus_to_werror(result);
1843         }
1844
1845 done:
1846         DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1847         TALLOC_FREE(frame);
1848         return WERR_OK;
1849 }
1850
1851 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1852 {
1853         struct winbindd_domain *domain;
1854         NTSTATUS status;
1855         struct rpc_pipe_client *netlogon_pipe;
1856         struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1857         struct dcerpc_binding_handle *b = NULL;
1858         bool retry = false;
1859
1860         DEBUG(5, ("_winbind_SendToSam received\n"));
1861         domain = wb_child_domain();
1862         if (domain == NULL) {
1863                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1864         }
1865
1866 reconnect:
1867         status = cm_connect_netlogon_secure(domain,
1868                                             &netlogon_pipe,
1869                                             &netlogon_creds_ctx);
1870         reset_cm_connection_on_error(domain, NULL, status);
1871         if (!NT_STATUS_IS_OK(status)) {
1872                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1873                 return status;
1874         }
1875
1876         b = netlogon_pipe->binding_handle;
1877
1878         status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1879                                               b,
1880                                               &r->in.message);
1881         if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1882                 retry = true;
1883                 goto reconnect;
1884         }
1885
1886         return status;
1887 }