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