44e4842ec22e25a94f2f1c16e48405358d737bb3
[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         if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
745                 /*
746                  * Retry to open new connection with new kerberos ticket.
747                  */
748                 invalidate_cm_connection(domain);
749                 status = cm_connect_netlogon(domain, &netlogon_pipe);
750         }
751
752         reset_cm_connection_on_error(domain, status);
753         if (!NT_STATUS_IS_OK(status)) {
754                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
755                           nt_errstr(status)));
756                 return status;
757         }
758
759         b = netlogon_pipe->binding_handle;
760
761         fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
762         *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
763         if (*r->out.dcname == NULL) {
764                 DEBUG(2, ("Could not allocate memory\n"));
765                 return NT_STATUS_NO_MEMORY;
766         }
767
768         /*
769          * This provokes a WERR_NOT_SUPPORTED error message. This is
770          * documented in the wspp docs. I could not get a successful
771          * call to work, but the main point here is testing that the
772          * netlogon pipe works.
773          */
774         status = dcerpc_netr_LogonControl(b, p->mem_ctx,
775                                           logon_server, NETLOGON_CONTROL_QUERY,
776                                           2, &info, &werr);
777
778         if (!dcerpc_binding_handle_is_connected(b) && !retry) {
779                 DEBUG(10, ("Session might have expired. "
780                            "Reconnect and retry once.\n"));
781                 invalidate_cm_connection(domain);
782                 retry = true;
783                 goto reconnect;
784         }
785
786         reset_cm_connection_on_error(domain, status);
787         if (!NT_STATUS_IS_OK(status)) {
788                 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
789                         nt_errstr(status)));
790                 return status;
791         }
792
793         if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
794                 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
795                           "WERR_NOT_SUPPORTED\n",
796                           win_errstr(werr)));
797                 return werror_to_ntstatus(werr);
798         }
799
800         DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
801         return NT_STATUS_OK;
802 }
803
804 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
805                                                     struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
806 {
807         struct winbindd_domain *domain;
808         NTSTATUS status;
809         struct rpc_pipe_client *netlogon_pipe;
810
811         domain = wb_child_domain();
812         if (domain == NULL) {
813                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
814         }
815
816         status = cm_connect_netlogon(domain, &netlogon_pipe);
817         if (!NT_STATUS_IS_OK(status)) {
818                 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
819                 goto done;
820         }
821
822         status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
823                                                                       netlogon_pipe->binding_handle,
824                                                                       r->in.site_name,
825                                                                       r->in.dns_ttl,
826                                                                       r->in.dns_names);
827
828         /* Pass back result code - zero for success, other values for
829            specific failures. */
830
831         DEBUG(3,("DNS records for domain %s %s\n", domain->name,
832                 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
833
834  done:
835         DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
836               ("Update of DNS records via RW DC %s returned %s\n",
837                domain->name, nt_errstr(status)));
838
839         return status;
840 }
841
842 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
843                         struct winbind_SamLogon *r)
844 {
845         struct winbindd_domain *domain;
846         NTSTATUS status;
847         DATA_BLOB lm_response, nt_response;
848         domain = wb_child_domain();
849         if (domain == NULL) {
850                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
851         }
852
853         /* TODO: Handle interactive logons here */
854         if (r->in.validation_level != 3 ||
855             r->in.logon.network == NULL ||
856             (r->in.logon_level != NetlogonNetworkInformation
857              && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
858                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
859         }
860
861
862         lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
863         nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
864
865         status = winbind_dual_SamLogon(domain, p->mem_ctx,
866                                        r->in.logon.network->identity_info.parameter_control,
867                                        r->in.logon.network->identity_info.account_name.string,
868                                        r->in.logon.network->identity_info.domain_name.string,
869                                        r->in.logon.network->identity_info.workstation.string,
870                                        r->in.logon.network->challenge,
871                                        lm_response, nt_response, &r->out.validation.sam3);
872         return status;
873 }
874
875 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
876                              struct winbindd_domain *domain,
877                              struct winbind_LogonControl *r)
878 {
879         NTSTATUS status;
880         struct rpc_pipe_client *netlogon_pipe = NULL;
881         struct netr_NETLOGON_INFO_2 *info2 = NULL;
882         WERROR check_result = WERR_INTERNAL_ERROR;
883
884         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
885         if (info2 == NULL) {
886                 return WERR_NOMEM;
887         }
888
889         if (domain->internal) {
890                 check_result = WERR_OK;
891                 goto check_return;
892         }
893
894         /*
895          * For now we just force a reconnect
896          *
897          * TODO: take care of the optional '\dcname'
898          */
899         invalidate_cm_connection(domain);
900         domain->conn.netlogon_force_reauth = true;
901         status = cm_connect_netlogon(domain, &netlogon_pipe);
902         reset_cm_connection_on_error(domain, status);
903         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
904                 status = NT_STATUS_NO_LOGON_SERVERS;
905         }
906         if (!NT_STATUS_IS_OK(status)) {
907                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
908                           __func__, domain->name, domain->alt_name,
909                           nt_errstr(status)));
910                 /*
911                  * Here we return a top level error!
912                  * This is different than TC_QUERY or TC_VERIFY.
913                  */
914                 return ntstatus_to_werror(status);
915         }
916         check_result = WERR_OK;
917
918 check_return:
919         info2->pdc_connection_status = WERR_OK;
920         if (domain->dcname != NULL) {
921                 info2->flags |= NETLOGON_HAS_IP;
922                 info2->flags |= NETLOGON_HAS_TIMESERV;
923                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
924                                                          domain->dcname);
925                 if (info2->trusted_dc_name == NULL) {
926                         return WERR_NOMEM;
927                 }
928         } else {
929                 info2->trusted_dc_name = talloc_strdup(info2, "");
930                 if (info2->trusted_dc_name == NULL) {
931                         return WERR_NOMEM;
932                 }
933         }
934         info2->tc_connection_status = check_result;
935
936         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
937                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
938                           "pdc_connection[%s] tc_connection[%s]\n",
939                           __func__, domain->name, domain->alt_name,
940                           domain->dcname,
941                           win_errstr(info2->pdc_connection_status),
942                           win_errstr(info2->tc_connection_status)));
943         }
944
945         r->out.query->info2 = info2;
946
947         DEBUG(5, ("%s: succeeded.\n", __func__));
948         return WERR_OK;
949 }
950
951 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
952                              struct winbindd_domain *domain,
953                              struct winbind_LogonControl *r)
954 {
955         NTSTATUS status;
956         struct rpc_pipe_client *netlogon_pipe = NULL;
957         struct netr_NETLOGON_INFO_2 *info2 = NULL;
958         WERROR check_result = WERR_INTERNAL_ERROR;
959
960         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
961         if (info2 == NULL) {
962                 return WERR_NOMEM;
963         }
964
965         if (domain->internal) {
966                 check_result = WERR_OK;
967                 goto check_return;
968         }
969
970         status = cm_connect_netlogon(domain, &netlogon_pipe);
971         reset_cm_connection_on_error(domain, status);
972         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
973                 status = NT_STATUS_NO_LOGON_SERVERS;
974         }
975         if (!NT_STATUS_IS_OK(status)) {
976                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
977                           nt_errstr(status)));
978                 check_result = ntstatus_to_werror(status);
979                 goto check_return;
980         }
981         check_result = WERR_OK;
982
983 check_return:
984         info2->pdc_connection_status = WERR_OK;
985         if (domain->dcname != NULL) {
986                 info2->flags |= NETLOGON_HAS_IP;
987                 info2->flags |= NETLOGON_HAS_TIMESERV;
988                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
989                                                          domain->dcname);
990                 if (info2->trusted_dc_name == NULL) {
991                         return WERR_NOMEM;
992                 }
993         } else {
994                 info2->trusted_dc_name = talloc_strdup(info2, "");
995                 if (info2->trusted_dc_name == NULL) {
996                         return WERR_NOMEM;
997                 }
998         }
999         info2->tc_connection_status = check_result;
1000
1001         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1002                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1003                           "pdc_connection[%s] tc_connection[%s]\n",
1004                           __func__, domain->name, domain->alt_name,
1005                           domain->dcname,
1006                           win_errstr(info2->pdc_connection_status),
1007                           win_errstr(info2->tc_connection_status)));
1008         }
1009
1010         r->out.query->info2 = info2;
1011
1012         DEBUG(5, ("%s: succeeded.\n", __func__));
1013         return WERR_OK;
1014 }
1015
1016 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1017                              struct winbindd_domain *domain,
1018                              struct winbind_LogonControl *r)
1019 {
1020         TALLOC_CTX *frame = talloc_stackframe();
1021         NTSTATUS status;
1022         NTSTATUS result;
1023         struct lsa_String trusted_domain_name = {};
1024         struct lsa_StringLarge trusted_domain_name_l = {};
1025         struct rpc_pipe_client *local_lsa_pipe = NULL;
1026         struct policy_handle local_lsa_policy = {};
1027         struct dcerpc_binding_handle *local_lsa = NULL;
1028         struct rpc_pipe_client *netlogon_pipe = NULL;
1029         struct cli_credentials *creds = NULL;
1030         struct samr_Password *cur_nt_hash = NULL;
1031         uint32_t trust_attributes = 0;
1032         struct samr_Password new_owf_password = {};
1033         int cmp_new = -1;
1034         struct samr_Password old_owf_password = {};
1035         int cmp_old = -1;
1036         const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1037         bool fetch_fti = false;
1038         struct lsa_ForestTrustInformation *new_fti = NULL;
1039         struct netr_TrustInfo *trust_info = NULL;
1040         struct netr_NETLOGON_INFO_2 *info2 = NULL;
1041         struct dcerpc_binding_handle *b = NULL;
1042         WERROR check_result = WERR_INTERNAL_ERROR;
1043         WERROR verify_result = WERR_INTERNAL_ERROR;
1044         bool retry = false;
1045
1046         trusted_domain_name.string = domain->name;
1047         trusted_domain_name_l.string = domain->name;
1048
1049         info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1050         if (info2 == NULL) {
1051                 TALLOC_FREE(frame);
1052                 return WERR_NOMEM;
1053         }
1054
1055         if (domain->internal) {
1056                 check_result = WERR_OK;
1057                 goto check_return;
1058         }
1059
1060         status = pdb_get_trust_credentials(domain->name,
1061                                            domain->alt_name,
1062                                            frame,
1063                                            &creds);
1064         if (NT_STATUS_IS_OK(status)) {
1065                 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1066                 TALLOC_FREE(creds);
1067         }
1068
1069         if (!domain->primary) {
1070                 union lsa_TrustedDomainInfo *tdi = NULL;
1071
1072                 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1073                                                 &local_lsa_policy);
1074                 if (!NT_STATUS_IS_OK(status)) {
1075                         DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1076                                  __location__, __func__, nt_errstr(status)));
1077                         TALLOC_FREE(frame);
1078                         return WERR_INTERNAL_ERROR;
1079                 }
1080                 local_lsa = local_lsa_pipe->binding_handle;
1081
1082                 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1083                                                         &local_lsa_policy,
1084                                                         &trusted_domain_name,
1085                                                         LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1086                                                         &tdi, &result);
1087                 if (!NT_STATUS_IS_OK(status)) {
1088                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1089                                  __location__, __func__, domain->name, nt_errstr(status)));
1090                         TALLOC_FREE(frame);
1091                         return WERR_INTERNAL_ERROR;
1092                 }
1093                 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1094                         DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1095                                  __location__, __func__, domain->name));
1096                         TALLOC_FREE(frame);
1097                         return WERR_NO_SUCH_DOMAIN;
1098                 }
1099                 if (!NT_STATUS_IS_OK(result)) {
1100                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1101                                  __location__, __func__, domain->name, nt_errstr(result)));
1102                         TALLOC_FREE(frame);
1103                         return WERR_INTERNAL_ERROR;
1104                 }
1105                 if (tdi == NULL) {
1106                         DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1107                                  "returned no trusted domain information\n",
1108                                  __location__, __func__));
1109                         TALLOC_FREE(frame);
1110                         return WERR_INTERNAL_ERROR;
1111                 }
1112
1113                 local_tdo = &tdi->info_ex;
1114                 trust_attributes = local_tdo->trust_attributes;
1115         }
1116
1117         if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1118                 struct lsa_ForestTrustInformation *old_fti = NULL;
1119
1120                 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1121                                                         &local_lsa_policy,
1122                                                         &trusted_domain_name,
1123                                                         LSA_FOREST_TRUST_DOMAIN_INFO,
1124                                                         &old_fti, &result);
1125                 if (!NT_STATUS_IS_OK(status)) {
1126                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1127                                  __location__, __func__, domain->name, nt_errstr(status)));
1128                         TALLOC_FREE(frame);
1129                         return WERR_INTERNAL_ERROR;
1130                 }
1131                 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1132                         DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1133                                   __func__, domain->name));
1134                         old_fti = NULL;
1135                         fetch_fti = true;
1136                         result = NT_STATUS_OK;
1137                 }
1138                 if (!NT_STATUS_IS_OK(result)) {
1139                         DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1140                                  __location__, __func__, domain->name, nt_errstr(result)));
1141                         TALLOC_FREE(frame);
1142                         return WERR_INTERNAL_ERROR;
1143                 }
1144
1145                 TALLOC_FREE(old_fti);
1146         }
1147
1148 reconnect:
1149         status = cm_connect_netlogon(domain, &netlogon_pipe);
1150         reset_cm_connection_on_error(domain, status);
1151         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1152                 status = NT_STATUS_NO_LOGON_SERVERS;
1153         }
1154         if (!NT_STATUS_IS_OK(status)) {
1155                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1156                           nt_errstr(status)));
1157                 check_result = ntstatus_to_werror(status);
1158                 goto check_return;
1159         }
1160         check_result = WERR_OK;
1161         b = netlogon_pipe->binding_handle;
1162
1163         if (cur_nt_hash == NULL) {
1164                 verify_result = WERR_NO_TRUST_LSA_SECRET;
1165                 goto verify_return;
1166         }
1167
1168         if (fetch_fti) {
1169                 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1170                                                                       b, frame,
1171                                                                       &new_fti);
1172                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1173                         status = NT_STATUS_NOT_SUPPORTED;
1174                 }
1175                 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1176                         new_fti = NULL;
1177                         status = NT_STATUS_OK;
1178                 }
1179                 if (!NT_STATUS_IS_OK(status)) {
1180                         if (!retry && dcerpc_binding_handle_is_connected(b)) {
1181                                 invalidate_cm_connection(domain);
1182                                 retry = true;
1183                                 goto reconnect;
1184                         }
1185                         DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1186                                   "failed: %s\n",
1187                                   domain->name, nt_errstr(status)));
1188                         check_result = ntstatus_to_werror(status);
1189                         goto check_return;
1190                 }
1191         }
1192
1193         if (new_fti != NULL) {
1194                 struct lsa_ForestTrustInformation old_fti = {};
1195                 struct lsa_ForestTrustInformation *merged_fti = NULL;
1196                 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1197
1198                 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1199                                                       &old_fti, new_fti,
1200                                                       &merged_fti);
1201                 if (!NT_STATUS_IS_OK(status)) {
1202                         DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1203                                  __location__, __func__,
1204                                  domain->name, nt_errstr(status)));
1205                         TALLOC_FREE(frame);
1206                         return ntstatus_to_werror(status);
1207                 }
1208
1209                 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1210                                                 &local_lsa_policy,
1211                                                 &trusted_domain_name_l,
1212                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1213                                                 merged_fti,
1214                                                 0, /* check_only=0 => store it! */
1215                                                 &collision_info,
1216                                                 &result);
1217                 if (!NT_STATUS_IS_OK(status)) {
1218                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1219                                  __location__, __func__, domain->name, nt_errstr(status)));
1220                         TALLOC_FREE(frame);
1221                         return WERR_INTERNAL_ERROR;
1222                 }
1223                 if (!NT_STATUS_IS_OK(result)) {
1224                         DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1225                                  __location__, __func__, domain->name, nt_errstr(result)));
1226                         TALLOC_FREE(frame);
1227                         return ntstatus_to_werror(result);
1228                 }
1229         }
1230
1231         status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1232                                                        b, frame,
1233                                                        &new_owf_password,
1234                                                        &old_owf_password,
1235                                                        &trust_info);
1236         if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1237                 status = NT_STATUS_NOT_SUPPORTED;
1238         }
1239         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1240                 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1241                         nt_errstr(status)));
1242                 verify_result = WERR_OK;
1243                 goto verify_return;
1244         }
1245         if (!NT_STATUS_IS_OK(status)) {
1246                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1247                         invalidate_cm_connection(domain);
1248                         retry = true;
1249                         goto reconnect;
1250                 }
1251                 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1252                         nt_errstr(status)));
1253
1254                 if (!dcerpc_binding_handle_is_connected(b)) {
1255                         check_result = ntstatus_to_werror(status);
1256                         goto check_return;
1257                 } else {
1258                         verify_result = ntstatus_to_werror(status);
1259                         goto verify_return;
1260                 }
1261         }
1262
1263         if (trust_info != NULL && trust_info->count >= 1) {
1264                 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1265
1266                 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1267                         verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1268                         goto verify_return;
1269                 }
1270         }
1271
1272         cmp_new = memcmp(new_owf_password.hash,
1273                          cur_nt_hash->hash,
1274                          sizeof(cur_nt_hash->hash));
1275         cmp_old = memcmp(old_owf_password.hash,
1276                          cur_nt_hash->hash,
1277                          sizeof(cur_nt_hash->hash));
1278         if (cmp_new != 0 && cmp_old != 0) {
1279                 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1280                          "any password known to dcname[%s]\n",
1281                          __func__, domain->name, domain->alt_name,
1282                          domain->dcname));
1283                 verify_result = WERR_WRONG_PASSWORD;
1284                 goto verify_return;
1285         }
1286
1287         if (cmp_new != 0) {
1288                 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1289                          "against the old password known to dcname[%s]\n",
1290                          __func__, domain->name, domain->alt_name,
1291                          domain->dcname));
1292         }
1293
1294         verify_result = WERR_OK;
1295         goto verify_return;
1296
1297 check_return:
1298         verify_result = check_result;
1299 verify_return:
1300         info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1301         info2->pdc_connection_status = verify_result;
1302         if (domain->dcname != NULL) {
1303                 info2->flags |= NETLOGON_HAS_IP;
1304                 info2->flags |= NETLOGON_HAS_TIMESERV;
1305                 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1306                                                          domain->dcname);
1307                 if (info2->trusted_dc_name == NULL) {
1308                         TALLOC_FREE(frame);
1309                         return WERR_NOMEM;
1310                 }
1311         } else {
1312                 info2->trusted_dc_name = talloc_strdup(info2, "");
1313                 if (info2->trusted_dc_name == NULL) {
1314                         TALLOC_FREE(frame);
1315                         return WERR_NOMEM;
1316                 }
1317         }
1318         info2->tc_connection_status = check_result;
1319
1320         if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1321                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1322                           "pdc_connection[%s] tc_connection[%s]\n",
1323                           __func__, domain->name, domain->alt_name,
1324                           domain->dcname,
1325                           win_errstr(info2->pdc_connection_status),
1326                           win_errstr(info2->tc_connection_status)));
1327         }
1328
1329         r->out.query->info2 = info2;
1330
1331         DEBUG(5, ("%s: succeeded.\n", __func__));
1332         TALLOC_FREE(frame);
1333         return WERR_OK;
1334 }
1335
1336 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1337                              struct winbindd_domain *domain,
1338                              struct winbind_LogonControl *r)
1339 {
1340         struct messaging_context *msg_ctx = winbind_messaging_context();
1341         NTSTATUS status;
1342         struct rpc_pipe_client *netlogon_pipe;
1343         struct cli_credentials *creds = NULL;
1344         struct samr_Password *cur_nt_hash = NULL;
1345         struct netr_NETLOGON_INFO_1 *info1 = NULL;
1346         struct dcerpc_binding_handle *b;
1347         WERROR change_result = WERR_OK;
1348         bool retry = false;
1349
1350         info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1351         if (info1 == NULL) {
1352                 return WERR_NOMEM;
1353         }
1354
1355         if (domain->internal) {
1356                 return WERR_NOT_SUPPORTED;
1357         }
1358
1359         status = pdb_get_trust_credentials(domain->name,
1360                                            domain->alt_name,
1361                                            p->mem_ctx,
1362                                            &creds);
1363         if (NT_STATUS_IS_OK(status)) {
1364                 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1365                 TALLOC_FREE(creds);
1366         }
1367
1368 reconnect:
1369         status = cm_connect_netlogon(domain, &netlogon_pipe);
1370         reset_cm_connection_on_error(domain, status);
1371         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1372                 status = NT_STATUS_NO_LOGON_SERVERS;
1373         }
1374         if (!NT_STATUS_IS_OK(status)) {
1375                 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1376                           __func__, domain->name, domain->alt_name,
1377                           nt_errstr(status)));
1378                 /*
1379                  * Here we return a top level error!
1380                  * This is different than TC_QUERY or TC_VERIFY.
1381                  */
1382                 return ntstatus_to_werror(status);
1383         }
1384         b = netlogon_pipe->binding_handle;
1385
1386         if (cur_nt_hash == NULL) {
1387                 change_result = WERR_NO_TRUST_LSA_SECRET;
1388                 goto change_return;
1389         }
1390         TALLOC_FREE(cur_nt_hash);
1391
1392         status = trust_pw_change(domain->conn.netlogon_creds,
1393                                  msg_ctx, b, domain->name,
1394                                  true); /* force */
1395         if (!NT_STATUS_IS_OK(status)) {
1396                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1397                         invalidate_cm_connection(domain);
1398                         retry = true;
1399                         goto reconnect;
1400                 }
1401
1402                 DEBUG(1, ("trust_pw_change(%s): %s\n",
1403                           domain->name, nt_errstr(status)));
1404
1405                 change_result = ntstatus_to_werror(status);
1406                 goto change_return;
1407         }
1408
1409         change_result = WERR_OK;
1410
1411 change_return:
1412         info1->pdc_connection_status = change_result;
1413
1414         if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1415                 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1416                           "pdc_connection[%s]\n",
1417                           __func__, domain->name, domain->alt_name,
1418                           domain->dcname,
1419                           win_errstr(info1->pdc_connection_status)));
1420         }
1421
1422         r->out.query->info1 = info1;
1423
1424         DEBUG(5, ("%s: succeeded.\n", __func__));
1425         return WERR_OK;
1426 }
1427
1428 WERROR _winbind_LogonControl(struct pipes_struct *p,
1429                              struct winbind_LogonControl *r)
1430 {
1431         struct winbindd_domain *domain;
1432
1433         domain = wb_child_domain();
1434         if (domain == NULL) {
1435                 return WERR_NO_SUCH_DOMAIN;
1436         }
1437
1438         switch (r->in.function_code) {
1439         case NETLOGON_CONTROL_REDISCOVER:
1440                 if (r->in.level != 2) {
1441                         return WERR_INVALID_PARAMETER;
1442                 }
1443                 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1444         case NETLOGON_CONTROL_TC_QUERY:
1445                 if (r->in.level != 2) {
1446                         return WERR_INVALID_PARAMETER;
1447                 }
1448                 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1449         case NETLOGON_CONTROL_TC_VERIFY:
1450                 if (r->in.level != 2) {
1451                         return WERR_INVALID_PARAMETER;
1452                 }
1453                 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1454         case NETLOGON_CONTROL_CHANGE_PASSWORD:
1455                 if (r->in.level != 1) {
1456                         return WERR_INVALID_PARAMETER;
1457                 }
1458                 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1459         default:
1460                 break;
1461         }
1462
1463         DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1464                   __func__, r->in.function_code));
1465         return WERR_NOT_SUPPORTED;
1466 }
1467
1468 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1469                              struct winbind_GetForestTrustInformation *r)
1470 {
1471         TALLOC_CTX *frame = talloc_stackframe();
1472         NTSTATUS status, result;
1473         struct winbindd_domain *domain;
1474         struct rpc_pipe_client *netlogon_pipe;
1475         struct dcerpc_binding_handle *b;
1476         bool retry = false;
1477         struct lsa_String trusted_domain_name = {};
1478         struct lsa_StringLarge trusted_domain_name_l = {};
1479         union lsa_TrustedDomainInfo *tdi = NULL;
1480         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1481         struct lsa_ForestTrustInformation _old_fti = {};
1482         struct lsa_ForestTrustInformation *old_fti = NULL;
1483         struct lsa_ForestTrustInformation *new_fti = NULL;
1484         struct lsa_ForestTrustInformation *merged_fti = NULL;
1485         struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1486         bool update_fti = false;
1487         struct rpc_pipe_client *local_lsa_pipe;
1488         struct policy_handle local_lsa_policy;
1489         struct dcerpc_binding_handle *local_lsa = NULL;
1490
1491         domain = wb_child_domain();
1492         if (domain == NULL) {
1493                 TALLOC_FREE(frame);
1494                 return WERR_NO_SUCH_DOMAIN;
1495         }
1496
1497         /*
1498          * checking for domain->internal and domain->primary
1499          * makes sure we only do some work when running as DC.
1500          */
1501
1502         if (domain->internal) {
1503                 TALLOC_FREE(frame);
1504                 return WERR_NO_SUCH_DOMAIN;
1505         }
1506
1507         if (domain->primary) {
1508                 TALLOC_FREE(frame);
1509                 return WERR_NO_SUCH_DOMAIN;
1510         }
1511
1512         trusted_domain_name.string = domain->name;
1513         trusted_domain_name_l.string = domain->name;
1514
1515         status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1516                                         &local_lsa_policy);
1517         if (!NT_STATUS_IS_OK(status)) {
1518                 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1519                          __location__, __func__, nt_errstr(status)));
1520                 TALLOC_FREE(frame);
1521                 return WERR_INTERNAL_ERROR;
1522         }
1523         local_lsa = local_lsa_pipe->binding_handle;
1524
1525         status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1526                                                 &local_lsa_policy,
1527                                                 &trusted_domain_name,
1528                                                 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1529                                                 &tdi, &result);
1530         if (!NT_STATUS_IS_OK(status)) {
1531                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1532                          __location__, __func__, domain->name, nt_errstr(status)));
1533                 TALLOC_FREE(frame);
1534                 return WERR_INTERNAL_ERROR;
1535         }
1536         if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1537                 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1538                          __location__, __func__, domain->name));
1539                 TALLOC_FREE(frame);
1540                 return WERR_NO_SUCH_DOMAIN;
1541         }
1542         if (!NT_STATUS_IS_OK(result)) {
1543                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1544                          __location__, __func__, domain->name, nt_errstr(result)));
1545                 TALLOC_FREE(frame);
1546                 return WERR_INTERNAL_ERROR;
1547         }
1548         if (tdi == NULL) {
1549                 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1550                          "returned no trusted domain information\n",
1551                          __location__, __func__));
1552                 TALLOC_FREE(frame);
1553                 return WERR_INTERNAL_ERROR;
1554         }
1555
1556         tdo = &tdi->info_ex;
1557
1558         if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1559                 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1560                          __func__, tdo->netbios_name.string,
1561                          tdo->domain_name.string,
1562                          (unsigned)tdo->trust_attributes));
1563                 TALLOC_FREE(frame);
1564                 return WERR_NO_SUCH_DOMAIN;
1565         }
1566
1567         if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1568                 TALLOC_FREE(frame);
1569                 return WERR_INVALID_FLAGS;
1570         }
1571
1572 reconnect:
1573         status = cm_connect_netlogon(domain, &netlogon_pipe);
1574         reset_cm_connection_on_error(domain, status);
1575         if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1576                 status = NT_STATUS_NO_LOGON_SERVERS;
1577         }
1578         if (!NT_STATUS_IS_OK(status)) {
1579                 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1580                           nt_errstr(status)));
1581                 TALLOC_FREE(frame);
1582                 return ntstatus_to_werror(status);
1583         }
1584         b = netlogon_pipe->binding_handle;
1585
1586         status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1587                                                               b, p->mem_ctx,
1588                                                               &new_fti);
1589         if (!NT_STATUS_IS_OK(status)) {
1590                 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1591                         invalidate_cm_connection(domain);
1592                         retry = true;
1593                         goto reconnect;
1594                 }
1595                 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1596                           domain->name, nt_errstr(status)));
1597                 TALLOC_FREE(frame);
1598                 return ntstatus_to_werror(status);
1599         }
1600
1601         *r->out.forest_trust_info = new_fti;
1602
1603         if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1604                 update_fti = true;
1605         }
1606
1607         status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1608                                                 &local_lsa_policy,
1609                                                 &trusted_domain_name,
1610                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1611                                                 &old_fti, &result);
1612         if (!NT_STATUS_IS_OK(status)) {
1613                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1614                          __location__, __func__, domain->name, nt_errstr(status)));
1615                 TALLOC_FREE(frame);
1616                 return WERR_INTERNAL_ERROR;
1617         }
1618         if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1619                 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1620                           __func__, domain->name));
1621                 update_fti = true;
1622                 old_fti = &_old_fti;
1623                 result = NT_STATUS_OK;
1624         }
1625         if (!NT_STATUS_IS_OK(result)) {
1626                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1627                          __location__, __func__, domain->name, nt_errstr(result)));
1628                 TALLOC_FREE(frame);
1629                 return WERR_INTERNAL_ERROR;
1630         }
1631
1632         if (old_fti == NULL) {
1633                 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1634                          "returned success without returning forest trust information\n",
1635                          __location__, __func__));
1636                 TALLOC_FREE(frame);
1637                 return WERR_INTERNAL_ERROR;
1638         }
1639
1640         if (!update_fti) {
1641                 goto done;
1642         }
1643
1644         status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1645                                               &merged_fti);
1646         if (!NT_STATUS_IS_OK(status)) {
1647                 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1648                          __location__, __func__, domain->name, nt_errstr(status)));
1649                 TALLOC_FREE(frame);
1650                 return ntstatus_to_werror(status);
1651         }
1652
1653         status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1654                                                 &local_lsa_policy,
1655                                                 &trusted_domain_name_l,
1656                                                 LSA_FOREST_TRUST_DOMAIN_INFO,
1657                                                 merged_fti,
1658                                                 0, /* check_only=0 => store it! */
1659                                                 &collision_info,
1660                                                 &result);
1661         if (!NT_STATUS_IS_OK(status)) {
1662                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1663                          __location__, __func__, domain->name, nt_errstr(status)));
1664                 TALLOC_FREE(frame);
1665                 return WERR_INTERNAL_ERROR;
1666         }
1667         if (!NT_STATUS_IS_OK(result)) {
1668                 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1669                          __location__, __func__, domain->name, nt_errstr(result)));
1670                 TALLOC_FREE(frame);
1671                 return ntstatus_to_werror(result);
1672         }
1673
1674 done:
1675         DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1676         TALLOC_FREE(frame);
1677         return WERR_OK;
1678 }