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