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