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