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