ff4c93d922186d9139907e710aa655c9164789d0
[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                         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 = 0;
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,
894                                        true,
895                                        &flags,
896                                        &r->out.validation.sam3);
897         return status;
898 }
899
900 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
901                              struct winbindd_domain *domain,
902                              struct winbind_LogonControl *r)
903 {
904         NTSTATUS status;
905         struct rpc_pipe_client *netlogon_pipe = NULL;
906         struct netr_NETLOGON_INFO_2 *info2 = NULL;
907         WERROR check_result = WERR_INTERNAL_ERROR;
908
909         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
910         if (info2 == NULL) {
911                 return WERR_NOT_ENOUGH_MEMORY;
912         }
913
914         if (domain->internal) {
915                 check_result = WERR_OK;
916                 goto check_return;
917         }
918
919         /*
920          * For now we just force a reconnect
921          *
922          * TODO: take care of the optional '\dcname'
923          */
924         invalidate_cm_connection(domain);
925         domain->conn.netlogon_force_reauth = true;
926         status = cm_connect_netlogon(domain, &netlogon_pipe);
927         reset_cm_connection_on_error(domain, status);
928         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
929                 status = NT_STATUS_NO_LOGON_SERVERS;
930         }
931         if (!NT_STATUS_IS_OK(status)) {
932                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
933                           __func__, domain->name, domain->alt_name,
934                           nt_errstr(status)));
935                 /*
936                  * Here we return a top level error!
937                  * This is different than TC_QUERY or TC_VERIFY.
938                  */
939                 return ntstatus_to_werror(status);
940         }
941         check_result = WERR_OK;
942
943 check_return:
944         info2->pdc_connection_status = WERR_OK;
945         if (domain->dcname != NULL) {
946                 info2->flags |= NETLOGON_HAS_IP;
947                 info2->flags |= NETLOGON_HAS_TIMESERV;
948                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
949                                                          domain->dcname);
950                 if (info2->trusted_dc_name == NULL) {
951                         return WERR_NOT_ENOUGH_MEMORY;
952                 }
953         } else {
954                 info2->trusted_dc_name = talloc_strdup(info2, "");
955                 if (info2->trusted_dc_name == NULL) {
956                         return WERR_NOT_ENOUGH_MEMORY;
957                 }
958         }
959         info2->tc_connection_status = check_result;
960
961         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
962                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
963                           "pdc_connection[%s] tc_connection[%s]\n",
964                           __func__, domain->name, domain->alt_name,
965                           domain->dcname,
966                           win_errstr(info2->pdc_connection_status),
967                           win_errstr(info2->tc_connection_status)));
968         }
969
970         r->out.query->info2 = info2;
971
972         DEBUG(5, ("%s: succeeded.\n", __func__));
973         return WERR_OK;
974 }
975
976 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
977                              struct winbindd_domain *domain,
978                              struct winbind_LogonControl *r)
979 {
980         NTSTATUS status;
981         struct rpc_pipe_client *netlogon_pipe = NULL;
982         struct netr_NETLOGON_INFO_2 *info2 = NULL;
983         WERROR check_result = WERR_INTERNAL_ERROR;
984
985         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
986         if (info2 == NULL) {
987                 return WERR_NOT_ENOUGH_MEMORY;
988         }
989
990         if (domain->internal) {
991                 check_result = WERR_OK;
992                 goto check_return;
993         }
994
995         status = cm_connect_netlogon(domain, &netlogon_pipe);
996         reset_cm_connection_on_error(domain, status);
997         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
998                 status = NT_STATUS_NO_LOGON_SERVERS;
999         }
1000         if (!NT_STATUS_IS_OK(status)) {
1001                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1002                           nt_errstr(status)));
1003                 check_result = ntstatus_to_werror(status);
1004                 goto check_return;
1005         }
1006         check_result = WERR_OK;
1007
1008 check_return:
1009         info2->pdc_connection_status = WERR_OK;
1010         if (domain->dcname != NULL) {
1011                 info2->flags |= NETLOGON_HAS_IP;
1012                 info2->flags |= NETLOGON_HAS_TIMESERV;
1013                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1014                                                          domain->dcname);
1015                 if (info2->trusted_dc_name == NULL) {
1016                         return WERR_NOT_ENOUGH_MEMORY;
1017                 }
1018         } else {
1019                 info2->trusted_dc_name = talloc_strdup(info2, "");
1020                 if (info2->trusted_dc_name == NULL) {
1021                         return WERR_NOT_ENOUGH_MEMORY;
1022                 }
1023         }
1024         info2->tc_connection_status = check_result;
1025
1026         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1027                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1028                           "pdc_connection[%s] tc_connection[%s]\n",
1029                           __func__, domain->name, domain->alt_name,
1030                           domain->dcname,
1031                           win_errstr(info2->pdc_connection_status),
1032                           win_errstr(info2->tc_connection_status)));
1033         }
1034
1035         r->out.query->info2 = info2;
1036
1037         DEBUG(5, ("%s: succeeded.\n", __func__));
1038         return WERR_OK;
1039 }
1040
1041 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1042                              struct winbindd_domain *domain,
1043                              struct winbind_LogonControl *r)
1044 {
1045         TALLOC_CTX *frame = talloc_stackframe();
1046         NTSTATUS status;
1047         NTSTATUS result;
1048         struct lsa_String trusted_domain_name = {};
1049         struct lsa_StringLarge trusted_domain_name_l = {};
1050         struct rpc_pipe_client *local_lsa_pipe = NULL;
1051         struct policy_handle local_lsa_policy = {};
1052         struct dcerpc_binding_handle *local_lsa = NULL;
1053         struct rpc_pipe_client *netlogon_pipe = NULL;
1054         struct cli_credentials *creds = NULL;
1055         struct samr_Password *cur_nt_hash = NULL;
1056         uint32_t trust_attributes = 0;
1057         struct samr_Password new_owf_password = {};
1058         int cmp_new = -1;
1059         struct samr_Password old_owf_password = {};
1060         int cmp_old = -1;
1061         const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1062         bool fetch_fti = false;
1063         struct lsa_ForestTrustInformation *new_fti = NULL;
1064         struct netr_TrustInfo *trust_info = NULL;
1065         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1066         struct dcerpc_binding_handle *b = NULL;
1067         WERROR check_result = WERR_INTERNAL_ERROR;
1068         WERROR verify_result = WERR_INTERNAL_ERROR;
1069         bool retry = false;
1070
1071         trusted_domain_name.string = domain->name;
1072         trusted_domain_name_l.string = domain->name;
1073
1074         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1075         if (info2 == NULL) {
1076                 TALLOC_FREE(frame);
1077                 return WERR_NOT_ENOUGH_MEMORY;
1078         }
1079
1080         if (domain->internal) {
1081                 check_result = WERR_OK;
1082                 goto check_return;
1083         }
1084
1085         status = pdb_get_trust_credentials(domain->name,
1086                                            domain->alt_name,
1087                                            frame,
1088                                            &creds);
1089         if (NT_STATUS_IS_OK(status)) {
1090                 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1091                 TALLOC_FREE(creds);
1092         }
1093
1094         if (!domain->primary) {
1095                 union lsa_TrustedDomainInfo *tdi = NULL;
1096
1097                 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1098                                                 &local_lsa_policy);
1099                 if (!NT_STATUS_IS_OK(status)) {
1100                         DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1101                                  __location__, __func__, nt_errstr(status)));
1102                         TALLOC_FREE(frame);
1103                         return WERR_INTERNAL_ERROR;
1104                 }
1105                 local_lsa = local_lsa_pipe->binding_handle;
1106
1107                 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1108                                                         &local_lsa_policy,
1109                                                         &trusted_domain_name,
1110                                                         LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1111                                                         &tdi, &result);
1112                 if (!NT_STATUS_IS_OK(status)) {
1113                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1114                                  __location__, __func__, domain->name, nt_errstr(status)));
1115                         TALLOC_FREE(frame);
1116                         return WERR_INTERNAL_ERROR;
1117                 }
1118                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1119                         DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1120                                  __location__, __func__, domain->name));
1121                         TALLOC_FREE(frame);
1122                         return WERR_NO_SUCH_DOMAIN;
1123                 }
1124                 if (!NT_STATUS_IS_OK(result)) {
1125                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1126                                  __location__, __func__, domain->name, nt_errstr(result)));
1127                         TALLOC_FREE(frame);
1128                         return WERR_INTERNAL_ERROR;
1129                 }
1130                 if (tdi == NULL) {
1131                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1132                                  "returned no trusted domain information\n",
1133                                  __location__, __func__));
1134                         TALLOC_FREE(frame);
1135                         return WERR_INTERNAL_ERROR;
1136                 }
1137
1138                 local_tdo = &tdi->info_ex;
1139                 trust_attributes = local_tdo->trust_attributes;
1140         }
1141
1142         if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1143                 struct lsa_ForestTrustInformation *old_fti = NULL;
1144
1145                 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1146                                                         &local_lsa_policy,
1147                                                         &trusted_domain_name,
1148                                                         LSA_FOREST_TRUST_DOMAIN_INFO,
1149                                                         &old_fti, &result);
1150                 if (!NT_STATUS_IS_OK(status)) {
1151                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1152                                  __location__, __func__, domain->name, nt_errstr(status)));
1153                         TALLOC_FREE(frame);
1154                         return WERR_INTERNAL_ERROR;
1155                 }
1156                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1157                         DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1158                                   __func__, domain->name));
1159                         old_fti = NULL;
1160                         fetch_fti = true;
1161                         result = NT_STATUS_OK;
1162                 }
1163                 if (!NT_STATUS_IS_OK(result)) {
1164                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1165                                  __location__, __func__, domain->name, nt_errstr(result)));
1166                         TALLOC_FREE(frame);
1167                         return WERR_INTERNAL_ERROR;
1168                 }
1169
1170                 TALLOC_FREE(old_fti);
1171         }
1172
1173 reconnect:
1174         status = cm_connect_netlogon(domain, &netlogon_pipe);
1175         reset_cm_connection_on_error(domain, status);
1176         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1177                 status = NT_STATUS_NO_LOGON_SERVERS;
1178         }
1179         if (!NT_STATUS_IS_OK(status)) {
1180                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1181                           nt_errstr(status)));
1182                 check_result = ntstatus_to_werror(status);
1183                 goto check_return;
1184         }
1185         check_result = WERR_OK;
1186         b = netlogon_pipe->binding_handle;
1187
1188         if (cur_nt_hash == NULL) {
1189                 verify_result = WERR_NO_TRUST_LSA_SECRET;
1190                 goto verify_return;
1191         }
1192
1193         if (fetch_fti) {
1194                 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1195                                                                       b, frame,
1196                                                                       &new_fti);
1197                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1198                         status = NT_STATUS_NOT_SUPPORTED;
1199                 }
1200                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1201                         new_fti = NULL;
1202                         status = NT_STATUS_OK;
1203                 }
1204                 if (!NT_STATUS_IS_OK(status)) {
1205                         if (!retry && dcerpc_binding_handle_is_connected(b)) {
1206                                 invalidate_cm_connection(domain);
1207                                 retry = true;
1208                                 goto reconnect;
1209                         }
1210                         DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1211                                   "failed: %s\n",
1212                                   domain->name, nt_errstr(status)));
1213                         check_result = ntstatus_to_werror(status);
1214                         goto check_return;
1215                 }
1216         }
1217
1218         if (new_fti != NULL) {
1219                 struct lsa_ForestTrustInformation old_fti = {};
1220                 struct lsa_ForestTrustInformation *merged_fti = NULL;
1221                 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1222
1223                 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1224                                                       &old_fti, new_fti,
1225                                                       &merged_fti);
1226                 if (!NT_STATUS_IS_OK(status)) {
1227                         DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1228                                  __location__, __func__,
1229                                  domain->name, nt_errstr(status)));
1230                         TALLOC_FREE(frame);
1231                         return ntstatus_to_werror(status);
1232                 }
1233
1234                 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1235                                                 &local_lsa_policy,
1236                                                 &trusted_domain_name_l,
1237                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1238                                                 merged_fti,
1239                                                 0, /* check_only=0 => store it! */
1240                                                 &collision_info,
1241                                                 &result);
1242                 if (!NT_STATUS_IS_OK(status)) {
1243                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1244                                  __location__, __func__, domain->name, nt_errstr(status)));
1245                         TALLOC_FREE(frame);
1246                         return WERR_INTERNAL_ERROR;
1247                 }
1248                 if (!NT_STATUS_IS_OK(result)) {
1249                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1250                                  __location__, __func__, domain->name, nt_errstr(result)));
1251                         TALLOC_FREE(frame);
1252                         return ntstatus_to_werror(result);
1253                 }
1254         }
1255
1256         status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1257                                                        b, frame,
1258                                                        &new_owf_password,
1259                                                        &old_owf_password,
1260                                                        &trust_info);
1261         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1262                 status = NT_STATUS_NOT_SUPPORTED;
1263         }
1264         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1265                 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1266                         nt_errstr(status)));
1267                 verify_result = WERR_OK;
1268                 goto verify_return;
1269         }
1270         if (!NT_STATUS_IS_OK(status)) {
1271                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1272                         invalidate_cm_connection(domain);
1273                         retry = true;
1274                         goto reconnect;
1275                 }
1276                 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1277                         nt_errstr(status)));
1278
1279                 if (!dcerpc_binding_handle_is_connected(b)) {
1280                         check_result = ntstatus_to_werror(status);
1281                         goto check_return;
1282                 } else {
1283                         verify_result = ntstatus_to_werror(status);
1284                         goto verify_return;
1285                 }
1286         }
1287
1288         if (trust_info != NULL && trust_info->count >= 1) {
1289                 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1290
1291                 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1292                         verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1293                         goto verify_return;
1294                 }
1295         }
1296
1297         cmp_new = memcmp(new_owf_password.hash,
1298                          cur_nt_hash->hash,
1299                          sizeof(cur_nt_hash->hash));
1300         cmp_old = memcmp(old_owf_password.hash,
1301                          cur_nt_hash->hash,
1302                          sizeof(cur_nt_hash->hash));
1303         if (cmp_new != 0 && cmp_old != 0) {
1304                 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1305                          "any password known to dcname[%s]\n",
1306                          __func__, domain->name, domain->alt_name,
1307                          domain->dcname));
1308                 verify_result = WERR_WRONG_PASSWORD;
1309                 goto verify_return;
1310         }
1311
1312         if (cmp_new != 0) {
1313                 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1314                          "against the old password known to dcname[%s]\n",
1315                          __func__, domain->name, domain->alt_name,
1316                          domain->dcname));
1317         }
1318
1319         verify_result = WERR_OK;
1320         goto verify_return;
1321
1322 check_return:
1323         verify_result = check_result;
1324 verify_return:
1325         info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1326         info2->pdc_connection_status = verify_result;
1327         if (domain->dcname != NULL) {
1328                 info2->flags |= NETLOGON_HAS_IP;
1329                 info2->flags |= NETLOGON_HAS_TIMESERV;
1330                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1331                                                          domain->dcname);
1332                 if (info2->trusted_dc_name == NULL) {
1333                         TALLOC_FREE(frame);
1334                         return WERR_NOT_ENOUGH_MEMORY;
1335                 }
1336         } else {
1337                 info2->trusted_dc_name = talloc_strdup(info2, "");
1338                 if (info2->trusted_dc_name == NULL) {
1339                         TALLOC_FREE(frame);
1340                         return WERR_NOT_ENOUGH_MEMORY;
1341                 }
1342         }
1343         info2->tc_connection_status = check_result;
1344
1345         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1346                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1347                           "pdc_connection[%s] tc_connection[%s]\n",
1348                           __func__, domain->name, domain->alt_name,
1349                           domain->dcname,
1350                           win_errstr(info2->pdc_connection_status),
1351                           win_errstr(info2->tc_connection_status)));
1352         }
1353
1354         r->out.query->info2 = info2;
1355
1356         DEBUG(5, ("%s: succeeded.\n", __func__));
1357         TALLOC_FREE(frame);
1358         return WERR_OK;
1359 }
1360
1361 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1362                              struct winbindd_domain *domain,
1363                              struct winbind_LogonControl *r)
1364 {
1365         struct messaging_context *msg_ctx = winbind_messaging_context();
1366         NTSTATUS status;
1367         struct rpc_pipe_client *netlogon_pipe;
1368         struct cli_credentials *creds = NULL;
1369         struct samr_Password *cur_nt_hash = NULL;
1370         struct netr_NETLOGON_INFO_1 *info1 = NULL;
1371         struct dcerpc_binding_handle *b;
1372         WERROR change_result = WERR_OK;
1373         bool retry = false;
1374
1375         info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1376         if (info1 == NULL) {
1377                 return WERR_NOT_ENOUGH_MEMORY;
1378         }
1379
1380         if (domain->internal) {
1381                 return WERR_NOT_SUPPORTED;
1382         }
1383
1384         status = pdb_get_trust_credentials(domain->name,
1385                                            domain->alt_name,
1386                                            p->mem_ctx,
1387                                            &creds);
1388         if (NT_STATUS_IS_OK(status)) {
1389                 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1390                 TALLOC_FREE(creds);
1391         }
1392
1393 reconnect:
1394         status = cm_connect_netlogon(domain, &netlogon_pipe);
1395         reset_cm_connection_on_error(domain, status);
1396         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1397                 status = NT_STATUS_NO_LOGON_SERVERS;
1398         }
1399         if (!NT_STATUS_IS_OK(status)) {
1400                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1401                           __func__, domain->name, domain->alt_name,
1402                           nt_errstr(status)));
1403                 /*
1404                  * Here we return a top level error!
1405                  * This is different than TC_QUERY or TC_VERIFY.
1406                  */
1407                 return ntstatus_to_werror(status);
1408         }
1409         b = netlogon_pipe->binding_handle;
1410
1411         if (cur_nt_hash == NULL) {
1412                 change_result = WERR_NO_TRUST_LSA_SECRET;
1413                 goto change_return;
1414         }
1415         TALLOC_FREE(cur_nt_hash);
1416
1417         status = trust_pw_change(domain->conn.netlogon_creds,
1418                                  msg_ctx, b, domain->name,
1419                                  true); /* force */
1420         if (!NT_STATUS_IS_OK(status)) {
1421                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1422                         invalidate_cm_connection(domain);
1423                         retry = true;
1424                         goto reconnect;
1425                 }
1426
1427                 DEBUG(1, ("trust_pw_change(%s): %s\n",
1428                           domain->name, nt_errstr(status)));
1429
1430                 change_result = ntstatus_to_werror(status);
1431                 goto change_return;
1432         }
1433
1434         change_result = WERR_OK;
1435
1436 change_return:
1437         info1->pdc_connection_status = change_result;
1438
1439         if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1440                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1441                           "pdc_connection[%s]\n",
1442                           __func__, domain->name, domain->alt_name,
1443                           domain->dcname,
1444                           win_errstr(info1->pdc_connection_status)));
1445         }
1446
1447         r->out.query->info1 = info1;
1448
1449         DEBUG(5, ("%s: succeeded.\n", __func__));
1450         return WERR_OK;
1451 }
1452
1453 WERROR _winbind_LogonControl(struct pipes_struct *p,
1454                              struct winbind_LogonControl *r)
1455 {
1456         struct winbindd_domain *domain;
1457
1458         domain = wb_child_domain();
1459         if (domain == NULL) {
1460                 return WERR_NO_SUCH_DOMAIN;
1461         }
1462
1463         switch (r->in.function_code) {
1464         case NETLOGON_CONTROL_REDISCOVER:
1465                 if (r->in.level != 2) {
1466                         return WERR_INVALID_PARAMETER;
1467                 }
1468                 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1469         case NETLOGON_CONTROL_TC_QUERY:
1470                 if (r->in.level != 2) {
1471                         return WERR_INVALID_PARAMETER;
1472                 }
1473                 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1474         case NETLOGON_CONTROL_TC_VERIFY:
1475                 if (r->in.level != 2) {
1476                         return WERR_INVALID_PARAMETER;
1477                 }
1478                 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1479         case NETLOGON_CONTROL_CHANGE_PASSWORD:
1480                 if (r->in.level != 1) {
1481                         return WERR_INVALID_PARAMETER;
1482                 }
1483                 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1484         default:
1485                 break;
1486         }
1487
1488         DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1489                   __func__, r->in.function_code));
1490         return WERR_NOT_SUPPORTED;
1491 }
1492
1493 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1494                              struct winbind_GetForestTrustInformation *r)
1495 {
1496         TALLOC_CTX *frame = talloc_stackframe();
1497         NTSTATUS status, result;
1498         struct winbindd_domain *domain;
1499         struct rpc_pipe_client *netlogon_pipe;
1500         struct dcerpc_binding_handle *b;
1501         bool retry = false;
1502         struct lsa_String trusted_domain_name = {};
1503         struct lsa_StringLarge trusted_domain_name_l = {};
1504         union lsa_TrustedDomainInfo *tdi = NULL;
1505         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1506         struct lsa_ForestTrustInformation _old_fti = {};
1507         struct lsa_ForestTrustInformation *old_fti = NULL;
1508         struct lsa_ForestTrustInformation *new_fti = NULL;
1509         struct lsa_ForestTrustInformation *merged_fti = NULL;
1510         struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1511         bool update_fti = false;
1512         struct rpc_pipe_client *local_lsa_pipe;
1513         struct policy_handle local_lsa_policy;
1514         struct dcerpc_binding_handle *local_lsa = NULL;
1515
1516         domain = wb_child_domain();
1517         if (domain == NULL) {
1518                 TALLOC_FREE(frame);
1519                 return WERR_NO_SUCH_DOMAIN;
1520         }
1521
1522         /*
1523          * checking for domain->internal and domain->primary
1524          * makes sure we only do some work when running as DC.
1525          */
1526
1527         if (domain->internal) {
1528                 TALLOC_FREE(frame);
1529                 return WERR_NO_SUCH_DOMAIN;
1530         }
1531
1532         if (domain->primary) {
1533                 TALLOC_FREE(frame);
1534                 return WERR_NO_SUCH_DOMAIN;
1535         }
1536
1537         trusted_domain_name.string = domain->name;
1538         trusted_domain_name_l.string = domain->name;
1539
1540         status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1541                                         &local_lsa_policy);
1542         if (!NT_STATUS_IS_OK(status)) {
1543                 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1544                          __location__, __func__, nt_errstr(status)));
1545                 TALLOC_FREE(frame);
1546                 return WERR_INTERNAL_ERROR;
1547         }
1548         local_lsa = local_lsa_pipe->binding_handle;
1549
1550         status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1551                                                 &local_lsa_policy,
1552                                                 &trusted_domain_name,
1553                                                 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1554                                                 &tdi, &result);
1555         if (!NT_STATUS_IS_OK(status)) {
1556                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1557                          __location__, __func__, domain->name, nt_errstr(status)));
1558                 TALLOC_FREE(frame);
1559                 return WERR_INTERNAL_ERROR;
1560         }
1561         if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1562                 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1563                          __location__, __func__, domain->name));
1564                 TALLOC_FREE(frame);
1565                 return WERR_NO_SUCH_DOMAIN;
1566         }
1567         if (!NT_STATUS_IS_OK(result)) {
1568                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1569                          __location__, __func__, domain->name, nt_errstr(result)));
1570                 TALLOC_FREE(frame);
1571                 return WERR_INTERNAL_ERROR;
1572         }
1573         if (tdi == NULL) {
1574                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1575                          "returned no trusted domain information\n",
1576                          __location__, __func__));
1577                 TALLOC_FREE(frame);
1578                 return WERR_INTERNAL_ERROR;
1579         }
1580
1581         tdo = &tdi->info_ex;
1582
1583         if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1584                 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1585                          __func__, tdo->netbios_name.string,
1586                          tdo->domain_name.string,
1587                          (unsigned)tdo->trust_attributes));
1588                 TALLOC_FREE(frame);
1589                 return WERR_NO_SUCH_DOMAIN;
1590         }
1591
1592         if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1593                 TALLOC_FREE(frame);
1594                 return WERR_INVALID_FLAGS;
1595         }
1596
1597 reconnect:
1598         status = cm_connect_netlogon(domain, &netlogon_pipe);
1599         reset_cm_connection_on_error(domain, status);
1600         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1601                 status = NT_STATUS_NO_LOGON_SERVERS;
1602         }
1603         if (!NT_STATUS_IS_OK(status)) {
1604                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1605                           nt_errstr(status)));
1606                 TALLOC_FREE(frame);
1607                 return ntstatus_to_werror(status);
1608         }
1609         b = netlogon_pipe->binding_handle;
1610
1611         status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1612                                                               b, p->mem_ctx,
1613                                                               &new_fti);
1614         if (!NT_STATUS_IS_OK(status)) {
1615                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1616                         invalidate_cm_connection(domain);
1617                         retry = true;
1618                         goto reconnect;
1619                 }
1620                 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1621                           domain->name, nt_errstr(status)));
1622                 TALLOC_FREE(frame);
1623                 return ntstatus_to_werror(status);
1624         }
1625
1626         *r->out.forest_trust_info = new_fti;
1627
1628         if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1629                 update_fti = true;
1630         }
1631
1632         status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1633                                                 &local_lsa_policy,
1634                                                 &trusted_domain_name,
1635                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1636                                                 &old_fti, &result);
1637         if (!NT_STATUS_IS_OK(status)) {
1638                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1639                          __location__, __func__, domain->name, nt_errstr(status)));
1640                 TALLOC_FREE(frame);
1641                 return WERR_INTERNAL_ERROR;
1642         }
1643         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1644                 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1645                           __func__, domain->name));
1646                 update_fti = true;
1647                 old_fti = &_old_fti;
1648                 result = NT_STATUS_OK;
1649         }
1650         if (!NT_STATUS_IS_OK(result)) {
1651                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1652                          __location__, __func__, domain->name, nt_errstr(result)));
1653                 TALLOC_FREE(frame);
1654                 return WERR_INTERNAL_ERROR;
1655         }
1656
1657         if (old_fti == NULL) {
1658                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1659                          "returned success without returning forest trust information\n",
1660                          __location__, __func__));
1661                 TALLOC_FREE(frame);
1662                 return WERR_INTERNAL_ERROR;
1663         }
1664
1665         if (!update_fti) {
1666                 goto done;
1667         }
1668
1669         status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1670                                               &merged_fti);
1671         if (!NT_STATUS_IS_OK(status)) {
1672                 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1673                          __location__, __func__, domain->name, nt_errstr(status)));
1674                 TALLOC_FREE(frame);
1675                 return ntstatus_to_werror(status);
1676         }
1677
1678         status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1679                                                 &local_lsa_policy,
1680                                                 &trusted_domain_name_l,
1681                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1682                                                 merged_fti,
1683                                                 0, /* check_only=0 => store it! */
1684                                                 &collision_info,
1685                                                 &result);
1686         if (!NT_STATUS_IS_OK(status)) {
1687                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1688                          __location__, __func__, domain->name, nt_errstr(status)));
1689                 TALLOC_FREE(frame);
1690                 return WERR_INTERNAL_ERROR;
1691         }
1692         if (!NT_STATUS_IS_OK(result)) {
1693                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1694                          __location__, __func__, domain->name, nt_errstr(result)));
1695                 TALLOC_FREE(frame);
1696                 return ntstatus_to_werror(result);
1697         }
1698
1699 done:
1700         DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1701         TALLOC_FREE(frame);
1702         return WERR_OK;
1703 }
1704
1705 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1706 {
1707         struct winbindd_domain *domain;
1708         NTSTATUS status;
1709         struct rpc_pipe_client *netlogon_pipe;
1710
1711         DEBUG(5, ("_winbind_SendToSam received\n"));
1712         domain = wb_child_domain();
1713         if (domain == NULL) {
1714                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1715         }
1716
1717         status = cm_connect_netlogon(domain, &netlogon_pipe);
1718         if (!NT_STATUS_IS_OK(status)) {
1719                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1720                 return status;
1721         }
1722
1723         status = netlogon_creds_cli_SendToSam(domain->conn.netlogon_creds,
1724                                               netlogon_pipe->binding_handle,
1725                                               &r->in.message);
1726
1727         return status;
1728 }