libdns: Small cleanup
[Samba.git] / source3 / winbindd / winbindd_dual_srv.c
blob44e4842ec22e25a94f2f1c16e48405358d737bb3
1 /*
2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
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.
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.
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/>.
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"
37 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
39 *r->out.out_data = r->in.in_data;
42 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
43 NTSTATUS status)
45 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
46 invalidate_cm_connection(domain);
47 /* We invalidated the connection. */
48 return true;
50 return false;
53 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
55 struct winbindd_domain *domain = wb_child_domain();
56 char *dom_name;
57 char *name;
58 enum lsa_SidType type;
59 NTSTATUS status;
61 if (domain == NULL) {
62 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
72 *r->out.domain = dom_name;
73 *r->out.name = name;
74 *r->out.type = type;
75 return NT_STATUS_OK;
78 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
80 struct winbindd_domain *domain = wb_child_domain();
81 struct lsa_RefDomainList *domains = r->out.domains;
82 NTSTATUS status;
84 if (domain == NULL) {
85 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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.
94 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
95 &domains, &r->out.names);
97 if (domains != NULL) {
98 r->out.domains = domains;
101 reset_cm_connection_on_error(domain, status);
102 return status;
105 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
107 struct winbindd_domain *domain = wb_child_domain();
108 NTSTATUS status;
110 if (domain == NULL) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
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;
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;
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;
143 num_ids = 0;
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;
151 ids = talloc_realloc(talloc_tos(), ids,
152 struct id_map, num_ids);
153 if (ids == NULL) {
154 goto nomem;
156 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
157 struct id_map *, num_ids+1);
158 if (id_ptrs == NULL) {
159 goto nomem;
161 id_idx = talloc_realloc(talloc_tos(), id_idx,
162 uint32_t, num_ids);
163 if (id_idx == NULL) {
164 goto nomem;
166 sids = talloc_realloc(talloc_tos(), sids,
167 struct dom_sid, num_ids);
168 if (sids == NULL) {
169 goto nomem;
172 num_ids = 0;
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.
179 for (j=0; j<r->in.ids->num_ids; j++) {
180 struct wbint_TransID *id = &r->in.ids->ids[j];
182 if (id->domain_index != i) {
183 continue;
185 id_idx[num_ids] = j;
186 id_ptrs[num_ids] = &ids[num_ids];
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;
194 id_ptrs[num_ids] = NULL;
196 status = dom->methods->sids_to_unixids(dom, id_ptrs);
197 DEBUG(10, ("sids_to_unixids returned %s\n",
198 nt_errstr(status)));
201 * Extract the results for handing them back to the caller.
203 for (j=0; j<num_ids; j++) {
204 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
206 if (ids[j].status != ID_MAPPED) {
207 id->xid.id = UINT32_MAX;
208 id->xid.type = ID_TYPE_NOT_SPECIFIED;
209 continue;
212 id->xid = ids[j].xid;
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;
224 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
226 return idmap_uid_to_sid(r->out.sid, r->in.uid);
229 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
231 return idmap_gid_to_sid(r->out.sid, r->in.gid);
234 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
236 struct unixid xid;
237 NTSTATUS status;
239 status = idmap_allocate_uid(&xid);
240 if (!NT_STATUS_IS_OK(status)) {
241 return status;
243 *r->out.uid = xid.id;
244 return NT_STATUS_OK;
247 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
249 struct unixid xid;
250 NTSTATUS status;
252 status = idmap_allocate_gid(&xid);
253 if (!NT_STATUS_IS_OK(status)) {
254 return status;
256 *r->out.gid = xid.id;
257 return NT_STATUS_OK;
260 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
262 struct winbindd_domain *domain = wb_child_domain();
263 NTSTATUS status;
265 if (domain == NULL) {
266 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
275 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
276 struct wbint_LookupUserAliases *r)
278 struct winbindd_domain *domain = wb_child_domain();
279 NTSTATUS status;
281 if (domain == NULL) {
282 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
292 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
293 struct wbint_LookupUserGroups *r)
295 struct winbindd_domain *domain = wb_child_domain();
296 NTSTATUS status;
298 if (domain == NULL) {
299 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
309 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
310 struct wbint_QuerySequenceNumber *r)
312 struct winbindd_domain *domain = wb_child_domain();
313 NTSTATUS status;
315 if (domain == NULL) {
316 return NT_STATUS_REQUEST_NOT_ACCEPTED;
319 status = domain->methods->sequence_number(domain, r->out.sequence);
320 reset_cm_connection_on_error(domain, status);
321 return status;
324 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
325 struct wbint_LookupGroupMembers *r)
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;
334 if (domain == NULL) {
335 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
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;
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];
360 return NT_STATUS_OK;
363 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
364 struct wbint_QueryUserList *r)
366 struct winbindd_domain *domain = wb_child_domain();
367 NTSTATUS status;
369 if (domain == NULL) {
370 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
380 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
381 struct wbint_QueryGroupList *r)
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;
395 if (domain == NULL) {
396 return NT_STATUS_REQUEST_NOT_ACCEPTED;
399 switch (lp_server_role()) {
400 case ROLE_ACTIVE_DIRECTORY_DC:
401 if (domain->internal) {
403 * we want to include local groups
404 * for BUILTIN and WORKGROUP
406 include_local_groups = true;
408 break;
409 default:
411 * We might include local groups in more
412 * setups later, but that requires more work
413 * elsewhere.
415 break;
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;
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;
436 num_total = num_local_groups + num_dom_groups;
437 if (num_total > UINT32_MAX) {
438 return NT_STATUS_INTERNAL_ERROR;
441 result = talloc_array(r->out.groups, struct wbint_Principal,
442 num_total);
443 if (result == NULL) {
444 return NT_STATUS_NO_MEMORY;
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++];
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;
461 num_local_groups = 0;
462 TALLOC_FREE(local_groups);
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++];
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;
478 num_dom_groups = 0;
479 TALLOC_FREE(dom_groups);
481 r->out.groups->num_principals = ti;
482 r->out.groups->principals = result;
484 return NT_STATUS_OK;
487 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
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;
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);
505 status = cm_connect_netlogon(domain, &netlogon_pipe);
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;
513 b = netlogon_pipe->binding_handle;
515 /* This call can take a long time - allow the server to time out.
516 35 seconds should do it. */
518 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
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;
528 if (reset_cm_connection_on_error(domain, status)) {
529 /* Re-initialize. */
530 status = cm_connect_netlogon(domain, &netlogon_pipe);
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;
538 b = netlogon_pipe->binding_handle;
540 /* This call can take a long time - allow the server to time out.
541 35 seconds should do it. */
543 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
548 * Fallback to less capable methods
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;
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);
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;
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;
580 *r->out.dc_info = dc_info;
581 status = NT_STATUS_OK;
583 done:
584 /* And restore our original timeout. */
585 rpccli_set_timeout(netlogon_pipe, orig_timeout);
587 return status;
590 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
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;
600 if (domain == NULL) {
601 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
612 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
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;
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]);
626 TALLOC_FREE(types);
627 TALLOC_FREE(names);
629 r->out.names->num_principals = r->in.rids->num_rids;
630 r->out.names->principals = result;
631 return NT_STATUS_OK;
634 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
635 struct wbint_CheckMachineAccount *r)
637 struct winbindd_domain *domain;
638 int num_retries = 0;
639 NTSTATUS status;
641 domain = wb_child_domain();
642 if (domain == NULL) {
643 return NT_STATUS_REQUEST_NOT_ACCEPTED;
646 again:
647 invalidate_cm_connection(domain);
648 domain->conn.netlogon_force_reauth = true;
651 struct rpc_pipe_client *netlogon_pipe;
652 status = cm_connect_netlogon(domain, &netlogon_pipe);
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. */
660 #define MAX_RETRIES 3
662 if ((num_retries < MAX_RETRIES)
663 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
664 num_retries++;
665 goto again;
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
670 goto done;
673 /* Pass back result code - zero for success, other values for
674 specific failures. */
676 DEBUG(3,("domain %s secret is %s\n", domain->name,
677 NT_STATUS_IS_OK(status) ? "good" : "bad"));
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)));
684 return status;
687 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
688 struct wbint_ChangeMachineAccount *r)
690 struct messaging_context *msg_ctx = winbind_messaging_context();
691 struct winbindd_domain *domain;
692 NTSTATUS status;
693 struct rpc_pipe_client *netlogon_pipe;
695 domain = wb_child_domain();
696 if (domain == NULL) {
697 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
706 status = trust_pw_change(domain->conn.netlogon_creds,
707 msg_ctx,
708 netlogon_pipe->binding_handle,
709 domain->name,
710 true); /* force */
712 /* Pass back result code - zero for success, other values for
713 specific failures. */
715 DEBUG(3,("domain %s secret %s\n", domain->name,
716 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
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)));
723 return status;
726 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
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;
737 domain = wb_child_domain();
738 if (domain == NULL) {
739 return NT_STATUS_REQUEST_NOT_ACCEPTED;
742 reconnect:
743 status = cm_connect_netlogon(domain, &netlogon_pipe);
744 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
746 * Retry to open new connection with new kerberos ticket.
748 invalidate_cm_connection(domain);
749 status = cm_connect_netlogon(domain, &netlogon_pipe);
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;
759 b = netlogon_pipe->binding_handle;
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;
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.
774 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
775 logon_server, NETLOGON_CONTROL_QUERY,
776 2, &info, &werr);
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;
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;
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);
800 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
801 return NT_STATUS_OK;
804 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
805 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
807 struct winbindd_domain *domain;
808 NTSTATUS status;
809 struct rpc_pipe_client *netlogon_pipe;
811 domain = wb_child_domain();
812 if (domain == NULL) {
813 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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;
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);
828 /* Pass back result code - zero for success, other values for
829 specific failures. */
831 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
832 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
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)));
839 return status;
842 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
843 struct winbind_SamLogon *r)
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;
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;
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);
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;
875 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
876 struct winbindd_domain *domain,
877 struct winbind_LogonControl *r)
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;
884 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
885 if (info2 == NULL) {
886 return WERR_NOMEM;
889 if (domain->internal) {
890 check_result = WERR_OK;
891 goto check_return;
895 * For now we just force a reconnect
897 * TODO: take care of the optional '\dcname'
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;
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)));
911 * Here we return a top level error!
912 * This is different than TC_QUERY or TC_VERIFY.
914 return ntstatus_to_werror(status);
916 check_result = WERR_OK;
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;
928 } else {
929 info2->trusted_dc_name = talloc_strdup(info2, "");
930 if (info2->trusted_dc_name == NULL) {
931 return WERR_NOMEM;
934 info2->tc_connection_status = check_result;
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)));
945 r->out.query->info2 = info2;
947 DEBUG(5, ("%s: succeeded.\n", __func__));
948 return WERR_OK;
951 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
952 struct winbindd_domain *domain,
953 struct winbind_LogonControl *r)
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;
960 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
961 if (info2 == NULL) {
962 return WERR_NOMEM;
965 if (domain->internal) {
966 check_result = WERR_OK;
967 goto check_return;
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;
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;
981 check_result = WERR_OK;
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;
993 } else {
994 info2->trusted_dc_name = talloc_strdup(info2, "");
995 if (info2->trusted_dc_name == NULL) {
996 return WERR_NOMEM;
999 info2->tc_connection_status = check_result;
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)));
1010 r->out.query->info2 = info2;
1012 DEBUG(5, ("%s: succeeded.\n", __func__));
1013 return WERR_OK;
1016 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1017 struct winbindd_domain *domain,
1018 struct winbind_LogonControl *r)
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;
1046 trusted_domain_name.string = domain->name;
1047 trusted_domain_name_l.string = domain->name;
1049 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1050 if (info2 == NULL) {
1051 TALLOC_FREE(frame);
1052 return WERR_NOMEM;
1055 if (domain->internal) {
1056 check_result = WERR_OK;
1057 goto check_return;
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);
1069 if (!domain->primary) {
1070 union lsa_TrustedDomainInfo *tdi = NULL;
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;
1080 local_lsa = local_lsa_pipe->binding_handle;
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;
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;
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;
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;
1113 local_tdo = &tdi->info_ex;
1114 trust_attributes = local_tdo->trust_attributes;
1117 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1118 struct lsa_ForestTrustInformation *old_fti = NULL;
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;
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;
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;
1145 TALLOC_FREE(old_fti);
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;
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;
1160 check_result = WERR_OK;
1161 b = netlogon_pipe->binding_handle;
1163 if (cur_nt_hash == NULL) {
1164 verify_result = WERR_NO_TRUST_LSA_SECRET;
1165 goto verify_return;
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;
1175 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1176 new_fti = NULL;
1177 status = NT_STATUS_OK;
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;
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;
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;
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);
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;
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);
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;
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;
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;
1251 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1252 nt_errstr(status)));
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;
1263 if (trust_info != NULL && trust_info->count >= 1) {
1264 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1266 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1267 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1268 goto verify_return;
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;
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));
1294 verify_result = WERR_OK;
1295 goto verify_return;
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;
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;
1318 info2->tc_connection_status = check_result;
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)));
1329 r->out.query->info2 = info2;
1331 DEBUG(5, ("%s: succeeded.\n", __func__));
1332 TALLOC_FREE(frame);
1333 return WERR_OK;
1336 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1337 struct winbindd_domain *domain,
1338 struct winbind_LogonControl *r)
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;
1350 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1351 if (info1 == NULL) {
1352 return WERR_NOMEM;
1355 if (domain->internal) {
1356 return WERR_NOT_SUPPORTED;
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);
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;
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)));
1379 * Here we return a top level error!
1380 * This is different than TC_QUERY or TC_VERIFY.
1382 return ntstatus_to_werror(status);
1384 b = netlogon_pipe->binding_handle;
1386 if (cur_nt_hash == NULL) {
1387 change_result = WERR_NO_TRUST_LSA_SECRET;
1388 goto change_return;
1390 TALLOC_FREE(cur_nt_hash);
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;
1402 DEBUG(1, ("trust_pw_change(%s): %s\n",
1403 domain->name, nt_errstr(status)));
1405 change_result = ntstatus_to_werror(status);
1406 goto change_return;
1409 change_result = WERR_OK;
1411 change_return:
1412 info1->pdc_connection_status = change_result;
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)));
1422 r->out.query->info1 = info1;
1424 DEBUG(5, ("%s: succeeded.\n", __func__));
1425 return WERR_OK;
1428 WERROR _winbind_LogonControl(struct pipes_struct *p,
1429 struct winbind_LogonControl *r)
1431 struct winbindd_domain *domain;
1433 domain = wb_child_domain();
1434 if (domain == NULL) {
1435 return WERR_NO_SUCH_DOMAIN;
1438 switch (r->in.function_code) {
1439 case NETLOGON_CONTROL_REDISCOVER:
1440 if (r->in.level != 2) {
1441 return WERR_INVALID_PARAMETER;
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;
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;
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;
1458 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1459 default:
1460 break;
1463 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1464 __func__, r->in.function_code));
1465 return WERR_NOT_SUPPORTED;
1468 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1469 struct winbind_GetForestTrustInformation *r)
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;
1491 domain = wb_child_domain();
1492 if (domain == NULL) {
1493 TALLOC_FREE(frame);
1494 return WERR_NO_SUCH_DOMAIN;
1498 * checking for domain->internal and domain->primary
1499 * makes sure we only do some work when running as DC.
1502 if (domain->internal) {
1503 TALLOC_FREE(frame);
1504 return WERR_NO_SUCH_DOMAIN;
1507 if (domain->primary) {
1508 TALLOC_FREE(frame);
1509 return WERR_NO_SUCH_DOMAIN;
1512 trusted_domain_name.string = domain->name;
1513 trusted_domain_name_l.string = domain->name;
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;
1523 local_lsa = local_lsa_pipe->binding_handle;
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;
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;
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;
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;
1556 tdo = &tdi->info_ex;
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;
1567 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1568 TALLOC_FREE(frame);
1569 return WERR_INVALID_FLAGS;
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;
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);
1584 b = netlogon_pipe->binding_handle;
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;
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);
1601 *r->out.forest_trust_info = new_fti;
1603 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1604 update_fti = true;
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;
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;
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;
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;
1640 if (!update_fti) {
1641 goto done;
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);
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;
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);
1674 done:
1675 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1676 TALLOC_FREE(frame);
1677 return WERR_OK;