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