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