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/>.
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.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"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.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,
45 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
46 invalidate_cm_connection(domain);
47 /* We invalidated the connection. */
53 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
55 struct winbindd_domain *domain = wb_child_domain();
58 enum lsa_SidType type;
62 return NT_STATUS_REQUEST_NOT_ACCEPTED;
65 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
66 &dom_name, &name, &type);
67 reset_cm_connection_on_error(domain, status);
68 if (!NT_STATUS_IS_OK(status)) {
72 *r->out.domain = dom_name;
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;
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);
105 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
107 struct winbindd_domain *domain = wb_child_domain();
110 if (domain == NULL) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
114 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
115 r->in.name, r->in.flags,
116 r->out.sid, r->out.type);
117 reset_cm_connection_on_error(domain, status);
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
126 struct lsa_DomainInfo *d;
127 struct wbint_TransID *ids;
130 struct id_map **id_map_ptrs = NULL;
131 struct idmap_domain *dom;
132 NTSTATUS status = NT_STATUS_NO_MEMORY;
134 if (r->in.domains->count != 1) {
135 return NT_STATUS_INVALID_PARAMETER;
138 d = &r->in.domains->domains[0];
139 ids = r->in.ids->ids;
140 num_ids = r->in.ids->num_ids;
142 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
144 DEBUG(10, ("idmap domain %s:%s not found\n",
145 d->name.string, sid_string_dbg(d->sid)));
147 for (i=0; i<num_ids; i++) {
149 ids[i].xid = (struct unixid) {
151 .type = ID_TYPE_NOT_SPECIFIED
158 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
159 if (id_map_ptrs == NULL) {
164 * Convert the input data into a list of id_map structs
165 * suitable for handing in to the idmap sids_to_unixids
169 for (i=0; i<num_ids; i++) {
170 struct id_map *m = id_map_ptrs[i];
172 sid_compose(m->sid, d->sid, ids[i].rid);
173 m->status = ID_UNKNOWN;
174 m->xid = (struct unixid) { .type = ids[i].type };
177 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
179 if (!NT_STATUS_IS_OK(status)) {
180 DEBUG(10, ("sids_to_unixids returned %s\n",
186 * Extract the results for handing them back to the caller.
189 for (i=0; i<num_ids; i++) {
190 struct id_map *m = id_map_ptrs[i];
192 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
193 m->status = ID_UNMAPPED;
196 if (m->status == ID_MAPPED) {
199 ids[i].xid.id = UINT32_MAX;
200 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
206 status = NT_STATUS_NO_MEMORY;
208 TALLOC_FREE(id_map_ptrs);
212 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
213 struct wbint_UnixIDs2Sids *r)
215 struct id_map **maps;
219 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
221 return NT_STATUS_NO_MEMORY;
224 for (i=0; i<r->in.num_ids; i++) {
225 maps[i]->status = ID_UNKNOWN;
226 maps[i]->xid = r->in.xids[i];
229 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name);
230 if (!NT_STATUS_IS_OK(status)) {
235 for (i=0; i<r->in.num_ids; i++) {
236 r->out.xids[i] = maps[i]->xid;
237 sid_copy(&r->out.sids[i], maps[i]->sid);
245 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
250 status = idmap_allocate_uid(&xid);
251 if (!NT_STATUS_IS_OK(status)) {
254 *r->out.uid = xid.id;
258 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
263 status = idmap_allocate_gid(&xid);
264 if (!NT_STATUS_IS_OK(status)) {
267 *r->out.gid = xid.id;
271 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
273 struct idmap_domain *domain;
276 domain = idmap_find_domain(r->in.info->domain_name);
277 if ((domain == NULL) || (domain->query_user == NULL)) {
278 return NT_STATUS_REQUEST_NOT_ACCEPTED;
281 status = domain->query_user(domain, r->in.info);
285 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
286 struct wbint_LookupUserAliases *r)
288 struct winbindd_domain *domain = wb_child_domain();
291 if (domain == NULL) {
292 return NT_STATUS_REQUEST_NOT_ACCEPTED;
295 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
296 r->in.sids->num_sids,
298 &r->out.rids->num_rids,
300 reset_cm_connection_on_error(domain, status);
304 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
305 struct wbint_LookupUserGroups *r)
307 struct winbindd_domain *domain = wb_child_domain();
310 if (domain == NULL) {
311 return NT_STATUS_REQUEST_NOT_ACCEPTED;
314 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
315 &r->out.sids->num_sids,
317 reset_cm_connection_on_error(domain, status);
321 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
322 struct wbint_QuerySequenceNumber *r)
324 struct winbindd_domain *domain = wb_child_domain();
327 if (domain == NULL) {
328 return NT_STATUS_REQUEST_NOT_ACCEPTED;
331 status = wb_cache_sequence_number(domain, r->out.sequence);
332 reset_cm_connection_on_error(domain, status);
336 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
337 struct wbint_LookupGroupMembers *r)
339 struct winbindd_domain *domain = wb_child_domain();
340 uint32_t i, num_names;
341 struct dom_sid *sid_mem;
343 uint32_t *name_types;
346 if (domain == NULL) {
347 return NT_STATUS_REQUEST_NOT_ACCEPTED;
350 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
351 r->in.type, &num_names, &sid_mem,
352 &names, &name_types);
353 reset_cm_connection_on_error(domain, status);
354 if (!NT_STATUS_IS_OK(status)) {
358 r->out.members->num_principals = num_names;
359 r->out.members->principals = talloc_array(
360 r->out.members, struct wbint_Principal, num_names);
361 if (r->out.members->principals == NULL) {
362 return NT_STATUS_NO_MEMORY;
365 for (i=0; i<num_names; i++) {
366 struct wbint_Principal *m = &r->out.members->principals[i];
367 sid_copy(&m->sid, &sid_mem[i]);
368 m->name = talloc_move(r->out.members->principals, &names[i]);
369 m->type = (enum lsa_SidType)name_types[i];
375 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
376 struct wbint_QueryUserList *r)
378 struct winbindd_domain *domain = wb_child_domain();
381 if (domain == NULL) {
382 return NT_STATUS_REQUEST_NOT_ACCEPTED;
385 status = wb_cache_query_user_list(domain, p->mem_ctx,
386 &r->out.users->num_userinfos,
387 &r->out.users->userinfos);
388 reset_cm_connection_on_error(domain, status);
392 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
393 struct wbint_QueryGroupList *r)
395 struct winbindd_domain *domain = wb_child_domain();
397 uint32_t num_local_groups = 0;
398 struct wb_acct_info *local_groups = NULL;
399 uint32_t num_dom_groups = 0;
400 struct wb_acct_info *dom_groups = NULL;
402 uint64_t num_total = 0;
403 struct wbint_Principal *result;
405 bool include_local_groups = false;
407 if (domain == NULL) {
408 return NT_STATUS_REQUEST_NOT_ACCEPTED;
411 switch (lp_server_role()) {
412 case ROLE_ACTIVE_DIRECTORY_DC:
413 if (domain->internal) {
415 * we want to include local groups
416 * for BUILTIN and WORKGROUP
418 include_local_groups = true;
423 * We might include local groups in more
424 * setups later, but that requires more work
430 if (include_local_groups) {
431 status = wb_cache_enum_local_groups(domain, talloc_tos(),
434 reset_cm_connection_on_error(domain, status);
435 if (!NT_STATUS_IS_OK(status)) {
440 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
443 reset_cm_connection_on_error(domain, status);
444 if (!NT_STATUS_IS_OK(status)) {
448 num_total = num_local_groups + num_dom_groups;
449 if (num_total > UINT32_MAX) {
450 return NT_STATUS_INTERNAL_ERROR;
453 result = talloc_array(r->out.groups, struct wbint_Principal,
455 if (result == NULL) {
456 return NT_STATUS_NO_MEMORY;
459 for (i = 0; i < num_local_groups; i++) {
460 struct wb_acct_info *lg = &local_groups[i];
461 struct wbint_Principal *rg = &result[ti++];
463 sid_compose(&rg->sid, &domain->sid, lg->rid);
464 rg->type = SID_NAME_ALIAS;
465 rg->name = talloc_strdup(result, lg->acct_name);
466 if (rg->name == NULL) {
468 TALLOC_FREE(dom_groups);
469 TALLOC_FREE(local_groups);
470 return NT_STATUS_NO_MEMORY;
473 num_local_groups = 0;
474 TALLOC_FREE(local_groups);
476 for (i = 0; i < num_dom_groups; i++) {
477 struct wb_acct_info *dg = &dom_groups[i];
478 struct wbint_Principal *rg = &result[ti++];
480 sid_compose(&rg->sid, &domain->sid, dg->rid);
481 rg->type = SID_NAME_DOM_GRP;
482 rg->name = talloc_strdup(result, dg->acct_name);
483 if (rg->name == NULL) {
485 TALLOC_FREE(dom_groups);
486 TALLOC_FREE(local_groups);
487 return NT_STATUS_NO_MEMORY;
491 TALLOC_FREE(dom_groups);
493 r->out.groups->num_principals = ti;
494 r->out.groups->principals = result;
499 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
500 struct wbint_QueryUserRidList *r)
502 struct winbindd_domain *domain = wb_child_domain();
503 uint32_t i, num_userinfos;
504 struct wbint_userinfo *userinfos;
507 if (domain == NULL) {
508 return NT_STATUS_REQUEST_NOT_ACCEPTED;
512 * Right now this is overkill. We should add a backend call
513 * just querying the rids.
516 status = wb_cache_query_user_list(domain, p->mem_ctx,
517 &num_userinfos, &userinfos);
518 reset_cm_connection_on_error(domain, status);
520 if (!NT_STATUS_IS_OK(status)) {
524 r->out.rids->rids = talloc_array(r->out.rids, uint32_t, num_userinfos);
525 if (r->out.rids->rids == NULL) {
526 return NT_STATUS_NO_MEMORY;
529 for (i=0; i<num_userinfos; i++) {
530 struct wbint_userinfo *info = &userinfos[i];
532 if (!dom_sid_in_domain(&domain->sid, &info->user_sid)) {
533 fstring sidstr, domstr;
534 DBG_WARNING("Got sid %s in domain %s\n",
535 sid_to_fstring(sidstr, &info->user_sid),
536 sid_to_fstring(domstr, &domain->sid));
539 sid_split_rid(&info->user_sid,
540 &r->out.rids->rids[r->out.rids->num_rids++]);
546 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
548 struct winbindd_domain *domain = wb_child_domain();
549 struct rpc_pipe_client *netlogon_pipe;
550 struct netr_DsRGetDCNameInfo *dc_info;
553 unsigned int orig_timeout;
554 struct dcerpc_binding_handle *b;
556 if (domain == NULL) {
557 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
558 r->in.domain_name, r->in.domain_guid,
559 r->in.site_name ? r->in.site_name : "",
564 status = cm_connect_netlogon(domain, &netlogon_pipe);
566 reset_cm_connection_on_error(domain, status);
567 if (!NT_STATUS_IS_OK(status)) {
568 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
572 b = netlogon_pipe->binding_handle;
574 /* This call can take a long time - allow the server to time out.
575 35 seconds should do it. */
577 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
579 if (domain->active_directory) {
580 status = dcerpc_netr_DsRGetDCName(b,
581 p->mem_ctx, domain->dcname,
582 r->in.domain_name, NULL, r->in.domain_guid,
583 r->in.flags, r->out.dc_info, &werr);
584 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
587 if (reset_cm_connection_on_error(domain, status)) {
589 status = cm_connect_netlogon(domain, &netlogon_pipe);
591 reset_cm_connection_on_error(domain, status);
592 if (!NT_STATUS_IS_OK(status)) {
593 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
597 b = netlogon_pipe->binding_handle;
599 /* This call can take a long time - allow the server to time out.
600 35 seconds should do it. */
602 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
607 * Fallback to less capable methods
610 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
611 if (dc_info == NULL) {
612 status = NT_STATUS_NO_MEMORY;
616 if (r->in.flags & DS_PDC_REQUIRED) {
617 status = dcerpc_netr_GetDcName(b,
618 p->mem_ctx, domain->dcname,
619 r->in.domain_name, &dc_info->dc_unc, &werr);
621 status = dcerpc_netr_GetAnyDCName(b,
622 p->mem_ctx, domain->dcname,
623 r->in.domain_name, &dc_info->dc_unc, &werr);
626 reset_cm_connection_on_error(domain, status);
627 if (!NT_STATUS_IS_OK(status)) {
628 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
632 if (!W_ERROR_IS_OK(werr)) {
633 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
635 status = werror_to_ntstatus(werr);
639 *r->out.dc_info = dc_info;
640 status = NT_STATUS_OK;
643 /* And restore our original timeout. */
644 rpccli_set_timeout(netlogon_pipe, orig_timeout);
649 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
651 struct winbindd_domain *domain = wb_child_domain();
654 enum lsa_SidType *types;
655 struct wbint_Principal *result;
659 if (domain == NULL) {
660 return NT_STATUS_REQUEST_NOT_ACCEPTED;
663 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
664 r->in.rids->rids, r->in.rids->num_rids,
665 &domain_name, &names, &types);
666 reset_cm_connection_on_error(domain, status);
667 if (!NT_STATUS_IS_OK(status)) {
671 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
673 result = talloc_array(p->mem_ctx, struct wbint_Principal,
674 r->in.rids->num_rids);
675 if (result == NULL) {
676 return NT_STATUS_NO_MEMORY;
679 for (i=0; i<r->in.rids->num_rids; i++) {
680 sid_compose(&result[i].sid, r->in.domain_sid,
681 r->in.rids->rids[i]);
682 result[i].type = types[i];
683 result[i].name = talloc_move(result, &names[i]);
688 r->out.names->num_principals = r->in.rids->num_rids;
689 r->out.names->principals = result;
693 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
694 struct wbint_CheckMachineAccount *r)
696 struct winbindd_domain *domain;
700 domain = wb_child_domain();
701 if (domain == NULL) {
702 return NT_STATUS_REQUEST_NOT_ACCEPTED;
706 invalidate_cm_connection(domain);
707 domain->conn.netlogon_force_reauth = true;
710 struct rpc_pipe_client *netlogon_pipe;
711 status = cm_connect_netlogon(domain, &netlogon_pipe);
714 /* There is a race condition between fetching the trust account
715 password and the periodic machine password change. So it's
716 possible that the trust account password has been changed on us.
717 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
719 #define MAX_RETRIES 3
721 if ((num_retries < MAX_RETRIES)
722 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
727 if (!NT_STATUS_IS_OK(status)) {
728 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
732 /* Pass back result code - zero for success, other values for
733 specific failures. */
735 DEBUG(3,("domain %s secret is %s\n", domain->name,
736 NT_STATUS_IS_OK(status) ? "good" : "bad"));
739 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
740 ("Checking the trust account password for domain %s returned %s\n",
741 domain->name, nt_errstr(status)));
746 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
747 struct wbint_ChangeMachineAccount *r)
749 struct messaging_context *msg_ctx = winbind_messaging_context();
750 struct winbindd_domain *domain;
752 struct rpc_pipe_client *netlogon_pipe;
754 domain = wb_child_domain();
755 if (domain == NULL) {
756 return NT_STATUS_REQUEST_NOT_ACCEPTED;
759 status = cm_connect_netlogon(domain, &netlogon_pipe);
760 if (!NT_STATUS_IS_OK(status)) {
761 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
765 status = trust_pw_change(domain->conn.netlogon_creds,
767 netlogon_pipe->binding_handle,
771 /* Pass back result code - zero for success, other values for
772 specific failures. */
774 DEBUG(3,("domain %s secret %s\n", domain->name,
775 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
778 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
779 ("Changing the trust account password for domain %s returned %s\n",
780 domain->name, nt_errstr(status)));
785 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
788 struct winbindd_domain *domain;
789 struct rpc_pipe_client *netlogon_pipe;
790 union netr_CONTROL_QUERY_INFORMATION info;
792 fstring logon_server;
793 struct dcerpc_binding_handle *b;
796 domain = wb_child_domain();
797 if (domain == NULL) {
798 return NT_STATUS_REQUEST_NOT_ACCEPTED;
802 status = cm_connect_netlogon(domain, &netlogon_pipe);
803 reset_cm_connection_on_error(domain, status);
804 if (!NT_STATUS_IS_OK(status)) {
805 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
810 b = netlogon_pipe->binding_handle;
812 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
813 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
814 if (*r->out.dcname == NULL) {
815 DEBUG(2, ("Could not allocate memory\n"));
816 return NT_STATUS_NO_MEMORY;
820 * This provokes a WERR_NOT_SUPPORTED error message. This is
821 * documented in the wspp docs. I could not get a successful
822 * call to work, but the main point here is testing that the
823 * netlogon pipe works.
825 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
826 logon_server, NETLOGON_CONTROL_QUERY,
829 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
830 DEBUG(10, ("Session might have expired. "
831 "Reconnect and retry once.\n"));
832 invalidate_cm_connection(domain);
837 reset_cm_connection_on_error(domain, status);
838 if (!NT_STATUS_IS_OK(status)) {
839 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
844 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
845 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
846 "WERR_NOT_SUPPORTED\n",
848 return werror_to_ntstatus(werr);
851 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
855 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
856 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
858 struct winbindd_domain *domain;
860 struct rpc_pipe_client *netlogon_pipe;
862 domain = wb_child_domain();
863 if (domain == NULL) {
864 return NT_STATUS_REQUEST_NOT_ACCEPTED;
867 status = cm_connect_netlogon(domain, &netlogon_pipe);
868 if (!NT_STATUS_IS_OK(status)) {
869 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
873 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
874 netlogon_pipe->binding_handle,
879 /* Pass back result code - zero for success, other values for
880 specific failures. */
882 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
883 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
886 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
887 ("Update of DNS records via RW DC %s returned %s\n",
888 domain->name, nt_errstr(status)));
893 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
894 struct winbind_SamLogon *r)
896 struct winbindd_domain *domain;
898 DATA_BLOB lm_response, nt_response;
899 domain = wb_child_domain();
900 if (domain == NULL) {
901 return NT_STATUS_REQUEST_NOT_ACCEPTED;
904 /* TODO: Handle interactive logons here */
905 if (r->in.validation_level != 3 ||
906 r->in.logon.network == NULL ||
907 (r->in.logon_level != NetlogonNetworkInformation
908 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
909 return NT_STATUS_REQUEST_NOT_ACCEPTED;
913 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
914 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
916 status = winbind_dual_SamLogon(domain, p->mem_ctx,
917 r->in.logon.network->identity_info.parameter_control,
918 r->in.logon.network->identity_info.account_name.string,
919 r->in.logon.network->identity_info.domain_name.string,
920 r->in.logon.network->identity_info.workstation.string,
921 r->in.logon.network->challenge,
922 lm_response, nt_response, &r->out.validation.sam3);
926 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
927 struct winbindd_domain *domain,
928 struct winbind_LogonControl *r)
931 struct rpc_pipe_client *netlogon_pipe = NULL;
932 struct netr_NETLOGON_INFO_2 *info2 = NULL;
933 WERROR check_result = WERR_INTERNAL_ERROR;
935 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
937 return WERR_NOT_ENOUGH_MEMORY;
940 if (domain->internal) {
941 check_result = WERR_OK;
946 * For now we just force a reconnect
948 * TODO: take care of the optional '\dcname'
950 invalidate_cm_connection(domain);
951 domain->conn.netlogon_force_reauth = true;
952 status = cm_connect_netlogon(domain, &netlogon_pipe);
953 reset_cm_connection_on_error(domain, status);
954 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
955 status = NT_STATUS_NO_LOGON_SERVERS;
957 if (!NT_STATUS_IS_OK(status)) {
958 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
959 __func__, domain->name, domain->alt_name,
962 * Here we return a top level error!
963 * This is different than TC_QUERY or TC_VERIFY.
965 return ntstatus_to_werror(status);
967 check_result = WERR_OK;
970 info2->pdc_connection_status = WERR_OK;
971 if (domain->dcname != NULL) {
972 info2->flags |= NETLOGON_HAS_IP;
973 info2->flags |= NETLOGON_HAS_TIMESERV;
974 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
976 if (info2->trusted_dc_name == NULL) {
977 return WERR_NOT_ENOUGH_MEMORY;
980 info2->trusted_dc_name = talloc_strdup(info2, "");
981 if (info2->trusted_dc_name == NULL) {
982 return WERR_NOT_ENOUGH_MEMORY;
985 info2->tc_connection_status = check_result;
987 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
988 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
989 "pdc_connection[%s] tc_connection[%s]\n",
990 __func__, domain->name, domain->alt_name,
992 win_errstr(info2->pdc_connection_status),
993 win_errstr(info2->tc_connection_status)));
996 r->out.query->info2 = info2;
998 DEBUG(5, ("%s: succeeded.\n", __func__));
1002 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1003 struct winbindd_domain *domain,
1004 struct winbind_LogonControl *r)
1007 struct rpc_pipe_client *netlogon_pipe = NULL;
1008 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1009 WERROR check_result = WERR_INTERNAL_ERROR;
1011 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1012 if (info2 == NULL) {
1013 return WERR_NOT_ENOUGH_MEMORY;
1016 if (domain->internal) {
1017 check_result = WERR_OK;
1021 status = cm_connect_netlogon(domain, &netlogon_pipe);
1022 reset_cm_connection_on_error(domain, status);
1023 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1024 status = NT_STATUS_NO_LOGON_SERVERS;
1026 if (!NT_STATUS_IS_OK(status)) {
1027 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1028 nt_errstr(status)));
1029 check_result = ntstatus_to_werror(status);
1032 check_result = WERR_OK;
1035 info2->pdc_connection_status = WERR_OK;
1036 if (domain->dcname != NULL) {
1037 info2->flags |= NETLOGON_HAS_IP;
1038 info2->flags |= NETLOGON_HAS_TIMESERV;
1039 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1041 if (info2->trusted_dc_name == NULL) {
1042 return WERR_NOT_ENOUGH_MEMORY;
1045 info2->trusted_dc_name = talloc_strdup(info2, "");
1046 if (info2->trusted_dc_name == NULL) {
1047 return WERR_NOT_ENOUGH_MEMORY;
1050 info2->tc_connection_status = check_result;
1052 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1053 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1054 "pdc_connection[%s] tc_connection[%s]\n",
1055 __func__, domain->name, domain->alt_name,
1057 win_errstr(info2->pdc_connection_status),
1058 win_errstr(info2->tc_connection_status)));
1061 r->out.query->info2 = info2;
1063 DEBUG(5, ("%s: succeeded.\n", __func__));
1067 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1068 struct winbindd_domain *domain,
1069 struct winbind_LogonControl *r)
1071 TALLOC_CTX *frame = talloc_stackframe();
1074 struct lsa_String trusted_domain_name = {};
1075 struct lsa_StringLarge trusted_domain_name_l = {};
1076 struct rpc_pipe_client *local_lsa_pipe = NULL;
1077 struct policy_handle local_lsa_policy = {};
1078 struct dcerpc_binding_handle *local_lsa = NULL;
1079 struct rpc_pipe_client *netlogon_pipe = NULL;
1080 struct cli_credentials *creds = NULL;
1081 struct samr_Password *cur_nt_hash = NULL;
1082 uint32_t trust_attributes = 0;
1083 struct samr_Password new_owf_password = {};
1085 struct samr_Password old_owf_password = {};
1087 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1088 bool fetch_fti = false;
1089 struct lsa_ForestTrustInformation *new_fti = NULL;
1090 struct netr_TrustInfo *trust_info = NULL;
1091 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1092 struct dcerpc_binding_handle *b = NULL;
1093 WERROR check_result = WERR_INTERNAL_ERROR;
1094 WERROR verify_result = WERR_INTERNAL_ERROR;
1097 trusted_domain_name.string = domain->name;
1098 trusted_domain_name_l.string = domain->name;
1100 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1101 if (info2 == NULL) {
1103 return WERR_NOT_ENOUGH_MEMORY;
1106 if (domain->internal) {
1107 check_result = WERR_OK;
1111 status = pdb_get_trust_credentials(domain->name,
1115 if (NT_STATUS_IS_OK(status)) {
1116 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1120 if (!domain->primary) {
1121 union lsa_TrustedDomainInfo *tdi = NULL;
1123 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1125 if (!NT_STATUS_IS_OK(status)) {
1126 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1127 __location__, __func__, nt_errstr(status)));
1129 return WERR_INTERNAL_ERROR;
1131 local_lsa = local_lsa_pipe->binding_handle;
1133 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1135 &trusted_domain_name,
1136 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1138 if (!NT_STATUS_IS_OK(status)) {
1139 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1140 __location__, __func__, domain->name, nt_errstr(status)));
1142 return WERR_INTERNAL_ERROR;
1144 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1145 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1146 __location__, __func__, domain->name));
1148 return WERR_NO_SUCH_DOMAIN;
1150 if (!NT_STATUS_IS_OK(result)) {
1151 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1152 __location__, __func__, domain->name, nt_errstr(result)));
1154 return WERR_INTERNAL_ERROR;
1157 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1158 "returned no trusted domain information\n",
1159 __location__, __func__));
1161 return WERR_INTERNAL_ERROR;
1164 local_tdo = &tdi->info_ex;
1165 trust_attributes = local_tdo->trust_attributes;
1168 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1169 struct lsa_ForestTrustInformation *old_fti = NULL;
1171 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1173 &trusted_domain_name,
1174 LSA_FOREST_TRUST_DOMAIN_INFO,
1176 if (!NT_STATUS_IS_OK(status)) {
1177 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1178 __location__, __func__, domain->name, nt_errstr(status)));
1180 return WERR_INTERNAL_ERROR;
1182 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1183 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1184 __func__, domain->name));
1187 result = NT_STATUS_OK;
1189 if (!NT_STATUS_IS_OK(result)) {
1190 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1191 __location__, __func__, domain->name, nt_errstr(result)));
1193 return WERR_INTERNAL_ERROR;
1196 TALLOC_FREE(old_fti);
1200 status = cm_connect_netlogon(domain, &netlogon_pipe);
1201 reset_cm_connection_on_error(domain, status);
1202 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1203 status = NT_STATUS_NO_LOGON_SERVERS;
1205 if (!NT_STATUS_IS_OK(status)) {
1206 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1207 nt_errstr(status)));
1208 check_result = ntstatus_to_werror(status);
1211 check_result = WERR_OK;
1212 b = netlogon_pipe->binding_handle;
1214 if (cur_nt_hash == NULL) {
1215 verify_result = WERR_NO_TRUST_LSA_SECRET;
1220 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1223 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1224 status = NT_STATUS_NOT_SUPPORTED;
1226 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1228 status = NT_STATUS_OK;
1230 if (!NT_STATUS_IS_OK(status)) {
1231 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1232 invalidate_cm_connection(domain);
1236 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1238 domain->name, nt_errstr(status)));
1239 check_result = ntstatus_to_werror(status);
1244 if (new_fti != NULL) {
1245 struct lsa_ForestTrustInformation old_fti = {};
1246 struct lsa_ForestTrustInformation *merged_fti = NULL;
1247 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1249 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1252 if (!NT_STATUS_IS_OK(status)) {
1253 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1254 __location__, __func__,
1255 domain->name, nt_errstr(status)));
1257 return ntstatus_to_werror(status);
1260 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1262 &trusted_domain_name_l,
1263 LSA_FOREST_TRUST_DOMAIN_INFO,
1265 0, /* check_only=0 => store it! */
1268 if (!NT_STATUS_IS_OK(status)) {
1269 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1270 __location__, __func__, domain->name, nt_errstr(status)));
1272 return WERR_INTERNAL_ERROR;
1274 if (!NT_STATUS_IS_OK(result)) {
1275 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1276 __location__, __func__, domain->name, nt_errstr(result)));
1278 return ntstatus_to_werror(result);
1282 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1287 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1288 status = NT_STATUS_NOT_SUPPORTED;
1290 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1291 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1292 nt_errstr(status)));
1293 verify_result = WERR_OK;
1296 if (!NT_STATUS_IS_OK(status)) {
1297 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1298 invalidate_cm_connection(domain);
1302 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1303 nt_errstr(status)));
1305 if (!dcerpc_binding_handle_is_connected(b)) {
1306 check_result = ntstatus_to_werror(status);
1309 verify_result = ntstatus_to_werror(status);
1314 if (trust_info != NULL && trust_info->count >= 1) {
1315 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1317 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1318 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1323 cmp_new = memcmp(new_owf_password.hash,
1325 sizeof(cur_nt_hash->hash));
1326 cmp_old = memcmp(old_owf_password.hash,
1328 sizeof(cur_nt_hash->hash));
1329 if (cmp_new != 0 && cmp_old != 0) {
1330 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1331 "any password known to dcname[%s]\n",
1332 __func__, domain->name, domain->alt_name,
1334 verify_result = WERR_WRONG_PASSWORD;
1339 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1340 "against the old password known to dcname[%s]\n",
1341 __func__, domain->name, domain->alt_name,
1345 verify_result = WERR_OK;
1349 verify_result = check_result;
1351 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1352 info2->pdc_connection_status = verify_result;
1353 if (domain->dcname != NULL) {
1354 info2->flags |= NETLOGON_HAS_IP;
1355 info2->flags |= NETLOGON_HAS_TIMESERV;
1356 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1358 if (info2->trusted_dc_name == NULL) {
1360 return WERR_NOT_ENOUGH_MEMORY;
1363 info2->trusted_dc_name = talloc_strdup(info2, "");
1364 if (info2->trusted_dc_name == NULL) {
1366 return WERR_NOT_ENOUGH_MEMORY;
1369 info2->tc_connection_status = check_result;
1371 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1372 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1373 "pdc_connection[%s] tc_connection[%s]\n",
1374 __func__, domain->name, domain->alt_name,
1376 win_errstr(info2->pdc_connection_status),
1377 win_errstr(info2->tc_connection_status)));
1380 r->out.query->info2 = info2;
1382 DEBUG(5, ("%s: succeeded.\n", __func__));
1387 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1388 struct winbindd_domain *domain,
1389 struct winbind_LogonControl *r)
1391 struct messaging_context *msg_ctx = winbind_messaging_context();
1393 struct rpc_pipe_client *netlogon_pipe;
1394 struct cli_credentials *creds = NULL;
1395 struct samr_Password *cur_nt_hash = NULL;
1396 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1397 struct dcerpc_binding_handle *b;
1398 WERROR change_result = WERR_OK;
1401 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1402 if (info1 == NULL) {
1403 return WERR_NOT_ENOUGH_MEMORY;
1406 if (domain->internal) {
1407 return WERR_NOT_SUPPORTED;
1410 status = pdb_get_trust_credentials(domain->name,
1414 if (NT_STATUS_IS_OK(status)) {
1415 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1420 status = cm_connect_netlogon(domain, &netlogon_pipe);
1421 reset_cm_connection_on_error(domain, status);
1422 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1423 status = NT_STATUS_NO_LOGON_SERVERS;
1425 if (!NT_STATUS_IS_OK(status)) {
1426 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1427 __func__, domain->name, domain->alt_name,
1428 nt_errstr(status)));
1430 * Here we return a top level error!
1431 * This is different than TC_QUERY or TC_VERIFY.
1433 return ntstatus_to_werror(status);
1435 b = netlogon_pipe->binding_handle;
1437 if (cur_nt_hash == NULL) {
1438 change_result = WERR_NO_TRUST_LSA_SECRET;
1441 TALLOC_FREE(cur_nt_hash);
1443 status = trust_pw_change(domain->conn.netlogon_creds,
1444 msg_ctx, b, domain->name,
1446 if (!NT_STATUS_IS_OK(status)) {
1447 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1448 invalidate_cm_connection(domain);
1453 DEBUG(1, ("trust_pw_change(%s): %s\n",
1454 domain->name, nt_errstr(status)));
1456 change_result = ntstatus_to_werror(status);
1460 change_result = WERR_OK;
1463 info1->pdc_connection_status = change_result;
1465 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1466 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1467 "pdc_connection[%s]\n",
1468 __func__, domain->name, domain->alt_name,
1470 win_errstr(info1->pdc_connection_status)));
1473 r->out.query->info1 = info1;
1475 DEBUG(5, ("%s: succeeded.\n", __func__));
1479 WERROR _winbind_LogonControl(struct pipes_struct *p,
1480 struct winbind_LogonControl *r)
1482 struct winbindd_domain *domain;
1484 domain = wb_child_domain();
1485 if (domain == NULL) {
1486 return WERR_NO_SUCH_DOMAIN;
1489 switch (r->in.function_code) {
1490 case NETLOGON_CONTROL_REDISCOVER:
1491 if (r->in.level != 2) {
1492 return WERR_INVALID_PARAMETER;
1494 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1495 case NETLOGON_CONTROL_TC_QUERY:
1496 if (r->in.level != 2) {
1497 return WERR_INVALID_PARAMETER;
1499 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1500 case NETLOGON_CONTROL_TC_VERIFY:
1501 if (r->in.level != 2) {
1502 return WERR_INVALID_PARAMETER;
1504 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1505 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1506 if (r->in.level != 1) {
1507 return WERR_INVALID_PARAMETER;
1509 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1514 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1515 __func__, r->in.function_code));
1516 return WERR_NOT_SUPPORTED;
1519 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1520 struct winbind_GetForestTrustInformation *r)
1522 TALLOC_CTX *frame = talloc_stackframe();
1523 NTSTATUS status, result;
1524 struct winbindd_domain *domain;
1525 struct rpc_pipe_client *netlogon_pipe;
1526 struct dcerpc_binding_handle *b;
1528 struct lsa_String trusted_domain_name = {};
1529 struct lsa_StringLarge trusted_domain_name_l = {};
1530 union lsa_TrustedDomainInfo *tdi = NULL;
1531 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1532 struct lsa_ForestTrustInformation _old_fti = {};
1533 struct lsa_ForestTrustInformation *old_fti = NULL;
1534 struct lsa_ForestTrustInformation *new_fti = NULL;
1535 struct lsa_ForestTrustInformation *merged_fti = NULL;
1536 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1537 bool update_fti = false;
1538 struct rpc_pipe_client *local_lsa_pipe;
1539 struct policy_handle local_lsa_policy;
1540 struct dcerpc_binding_handle *local_lsa = NULL;
1542 domain = wb_child_domain();
1543 if (domain == NULL) {
1545 return WERR_NO_SUCH_DOMAIN;
1549 * checking for domain->internal and domain->primary
1550 * makes sure we only do some work when running as DC.
1553 if (domain->internal) {
1555 return WERR_NO_SUCH_DOMAIN;
1558 if (domain->primary) {
1560 return WERR_NO_SUCH_DOMAIN;
1563 trusted_domain_name.string = domain->name;
1564 trusted_domain_name_l.string = domain->name;
1566 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1568 if (!NT_STATUS_IS_OK(status)) {
1569 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1570 __location__, __func__, nt_errstr(status)));
1572 return WERR_INTERNAL_ERROR;
1574 local_lsa = local_lsa_pipe->binding_handle;
1576 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1578 &trusted_domain_name,
1579 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1581 if (!NT_STATUS_IS_OK(status)) {
1582 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1583 __location__, __func__, domain->name, nt_errstr(status)));
1585 return WERR_INTERNAL_ERROR;
1587 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1588 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1589 __location__, __func__, domain->name));
1591 return WERR_NO_SUCH_DOMAIN;
1593 if (!NT_STATUS_IS_OK(result)) {
1594 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1595 __location__, __func__, domain->name, nt_errstr(result)));
1597 return WERR_INTERNAL_ERROR;
1600 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1601 "returned no trusted domain information\n",
1602 __location__, __func__));
1604 return WERR_INTERNAL_ERROR;
1607 tdo = &tdi->info_ex;
1609 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1610 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1611 __func__, tdo->netbios_name.string,
1612 tdo->domain_name.string,
1613 (unsigned)tdo->trust_attributes));
1615 return WERR_NO_SUCH_DOMAIN;
1618 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1620 return WERR_INVALID_FLAGS;
1624 status = cm_connect_netlogon(domain, &netlogon_pipe);
1625 reset_cm_connection_on_error(domain, status);
1626 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1627 status = NT_STATUS_NO_LOGON_SERVERS;
1629 if (!NT_STATUS_IS_OK(status)) {
1630 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1631 nt_errstr(status)));
1633 return ntstatus_to_werror(status);
1635 b = netlogon_pipe->binding_handle;
1637 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1640 if (!NT_STATUS_IS_OK(status)) {
1641 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1642 invalidate_cm_connection(domain);
1646 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1647 domain->name, nt_errstr(status)));
1649 return ntstatus_to_werror(status);
1652 *r->out.forest_trust_info = new_fti;
1654 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1658 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1660 &trusted_domain_name,
1661 LSA_FOREST_TRUST_DOMAIN_INFO,
1663 if (!NT_STATUS_IS_OK(status)) {
1664 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1665 __location__, __func__, domain->name, nt_errstr(status)));
1667 return WERR_INTERNAL_ERROR;
1669 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1670 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1671 __func__, domain->name));
1673 old_fti = &_old_fti;
1674 result = NT_STATUS_OK;
1676 if (!NT_STATUS_IS_OK(result)) {
1677 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1678 __location__, __func__, domain->name, nt_errstr(result)));
1680 return WERR_INTERNAL_ERROR;
1683 if (old_fti == NULL) {
1684 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1685 "returned success without returning forest trust information\n",
1686 __location__, __func__));
1688 return WERR_INTERNAL_ERROR;
1695 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1697 if (!NT_STATUS_IS_OK(status)) {
1698 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1699 __location__, __func__, domain->name, nt_errstr(status)));
1701 return ntstatus_to_werror(status);
1704 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1706 &trusted_domain_name_l,
1707 LSA_FOREST_TRUST_DOMAIN_INFO,
1709 0, /* check_only=0 => store it! */
1712 if (!NT_STATUS_IS_OK(status)) {
1713 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1714 __location__, __func__, domain->name, nt_errstr(status)));
1716 return WERR_INTERNAL_ERROR;
1718 if (!NT_STATUS_IS_OK(result)) {
1719 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1720 __location__, __func__, domain->name, nt_errstr(result)));
1722 return ntstatus_to_werror(result);
1726 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));