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