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 sid_copy(&r->out.sids[i], maps[i]->sid);
244 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
249 status = idmap_allocate_uid(&xid);
250 if (!NT_STATUS_IS_OK(status)) {
253 *r->out.uid = xid.id;
257 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
262 status = idmap_allocate_gid(&xid);
263 if (!NT_STATUS_IS_OK(status)) {
266 *r->out.gid = xid.id;
270 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
272 struct winbindd_domain *domain = wb_child_domain();
275 if (domain == NULL) {
276 return NT_STATUS_REQUEST_NOT_ACCEPTED;
279 status = wb_cache_query_user(domain, p->mem_ctx, r->in.sid,
281 reset_cm_connection_on_error(domain, status);
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_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
501 struct winbindd_domain *domain = wb_child_domain();
502 struct rpc_pipe_client *netlogon_pipe;
503 struct netr_DsRGetDCNameInfo *dc_info;
506 unsigned int orig_timeout;
507 struct dcerpc_binding_handle *b;
509 if (domain == NULL) {
510 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
511 r->in.domain_name, r->in.domain_guid,
512 r->in.site_name ? r->in.site_name : "",
517 status = cm_connect_netlogon(domain, &netlogon_pipe);
519 reset_cm_connection_on_error(domain, status);
520 if (!NT_STATUS_IS_OK(status)) {
521 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
525 b = netlogon_pipe->binding_handle;
527 /* This call can take a long time - allow the server to time out.
528 35 seconds should do it. */
530 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
532 if (domain->active_directory) {
533 status = dcerpc_netr_DsRGetDCName(b,
534 p->mem_ctx, domain->dcname,
535 r->in.domain_name, NULL, r->in.domain_guid,
536 r->in.flags, r->out.dc_info, &werr);
537 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
540 if (reset_cm_connection_on_error(domain, status)) {
542 status = cm_connect_netlogon(domain, &netlogon_pipe);
544 reset_cm_connection_on_error(domain, status);
545 if (!NT_STATUS_IS_OK(status)) {
546 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
550 b = netlogon_pipe->binding_handle;
552 /* This call can take a long time - allow the server to time out.
553 35 seconds should do it. */
555 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
560 * Fallback to less capable methods
563 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
564 if (dc_info == NULL) {
565 status = NT_STATUS_NO_MEMORY;
569 if (r->in.flags & DS_PDC_REQUIRED) {
570 status = dcerpc_netr_GetDcName(b,
571 p->mem_ctx, domain->dcname,
572 r->in.domain_name, &dc_info->dc_unc, &werr);
574 status = dcerpc_netr_GetAnyDCName(b,
575 p->mem_ctx, domain->dcname,
576 r->in.domain_name, &dc_info->dc_unc, &werr);
579 reset_cm_connection_on_error(domain, status);
580 if (!NT_STATUS_IS_OK(status)) {
581 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
585 if (!W_ERROR_IS_OK(werr)) {
586 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
588 status = werror_to_ntstatus(werr);
592 *r->out.dc_info = dc_info;
593 status = NT_STATUS_OK;
596 /* And restore our original timeout. */
597 rpccli_set_timeout(netlogon_pipe, orig_timeout);
602 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
604 struct winbindd_domain *domain = wb_child_domain();
607 enum lsa_SidType *types;
608 struct wbint_Principal *result;
612 if (domain == NULL) {
613 return NT_STATUS_REQUEST_NOT_ACCEPTED;
616 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
617 r->in.rids->rids, r->in.rids->num_rids,
618 &domain_name, &names, &types);
619 reset_cm_connection_on_error(domain, status);
620 if (!NT_STATUS_IS_OK(status)) {
624 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
626 result = talloc_array(p->mem_ctx, struct wbint_Principal,
627 r->in.rids->num_rids);
628 if (result == NULL) {
629 return NT_STATUS_NO_MEMORY;
632 for (i=0; i<r->in.rids->num_rids; i++) {
633 sid_compose(&result[i].sid, r->in.domain_sid,
634 r->in.rids->rids[i]);
635 result[i].type = types[i];
636 result[i].name = talloc_move(result, &names[i]);
641 r->out.names->num_principals = r->in.rids->num_rids;
642 r->out.names->principals = result;
646 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
647 struct wbint_CheckMachineAccount *r)
649 struct winbindd_domain *domain;
653 domain = wb_child_domain();
654 if (domain == NULL) {
655 return NT_STATUS_REQUEST_NOT_ACCEPTED;
659 invalidate_cm_connection(domain);
660 domain->conn.netlogon_force_reauth = true;
663 struct rpc_pipe_client *netlogon_pipe;
664 status = cm_connect_netlogon(domain, &netlogon_pipe);
667 /* There is a race condition between fetching the trust account
668 password and the periodic machine password change. So it's
669 possible that the trust account password has been changed on us.
670 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
672 #define MAX_RETRIES 3
674 if ((num_retries < MAX_RETRIES)
675 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
680 if (!NT_STATUS_IS_OK(status)) {
681 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
685 /* Pass back result code - zero for success, other values for
686 specific failures. */
688 DEBUG(3,("domain %s secret is %s\n", domain->name,
689 NT_STATUS_IS_OK(status) ? "good" : "bad"));
692 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
693 ("Checking the trust account password for domain %s returned %s\n",
694 domain->name, nt_errstr(status)));
699 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
700 struct wbint_ChangeMachineAccount *r)
702 struct messaging_context *msg_ctx = winbind_messaging_context();
703 struct winbindd_domain *domain;
705 struct rpc_pipe_client *netlogon_pipe;
707 domain = wb_child_domain();
708 if (domain == NULL) {
709 return NT_STATUS_REQUEST_NOT_ACCEPTED;
712 status = cm_connect_netlogon(domain, &netlogon_pipe);
713 if (!NT_STATUS_IS_OK(status)) {
714 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
718 status = trust_pw_change(domain->conn.netlogon_creds,
720 netlogon_pipe->binding_handle,
724 /* Pass back result code - zero for success, other values for
725 specific failures. */
727 DEBUG(3,("domain %s secret %s\n", domain->name,
728 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
731 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
732 ("Changing the trust account password for domain %s returned %s\n",
733 domain->name, nt_errstr(status)));
738 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
741 struct winbindd_domain *domain;
742 struct rpc_pipe_client *netlogon_pipe;
743 union netr_CONTROL_QUERY_INFORMATION info;
745 fstring logon_server;
746 struct dcerpc_binding_handle *b;
749 domain = wb_child_domain();
750 if (domain == NULL) {
751 return NT_STATUS_REQUEST_NOT_ACCEPTED;
755 status = cm_connect_netlogon(domain, &netlogon_pipe);
756 reset_cm_connection_on_error(domain, status);
757 if (!NT_STATUS_IS_OK(status)) {
758 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
763 b = netlogon_pipe->binding_handle;
765 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
766 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
767 if (*r->out.dcname == NULL) {
768 DEBUG(2, ("Could not allocate memory\n"));
769 return NT_STATUS_NO_MEMORY;
773 * This provokes a WERR_NOT_SUPPORTED error message. This is
774 * documented in the wspp docs. I could not get a successful
775 * call to work, but the main point here is testing that the
776 * netlogon pipe works.
778 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
779 logon_server, NETLOGON_CONTROL_QUERY,
782 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
783 DEBUG(10, ("Session might have expired. "
784 "Reconnect and retry once.\n"));
785 invalidate_cm_connection(domain);
790 reset_cm_connection_on_error(domain, status);
791 if (!NT_STATUS_IS_OK(status)) {
792 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
797 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
798 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
799 "WERR_NOT_SUPPORTED\n",
801 return werror_to_ntstatus(werr);
804 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
808 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
809 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
811 struct winbindd_domain *domain;
813 struct rpc_pipe_client *netlogon_pipe;
815 domain = wb_child_domain();
816 if (domain == NULL) {
817 return NT_STATUS_REQUEST_NOT_ACCEPTED;
820 status = cm_connect_netlogon(domain, &netlogon_pipe);
821 if (!NT_STATUS_IS_OK(status)) {
822 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
826 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
827 netlogon_pipe->binding_handle,
832 /* Pass back result code - zero for success, other values for
833 specific failures. */
835 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
836 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
839 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
840 ("Update of DNS records via RW DC %s returned %s\n",
841 domain->name, nt_errstr(status)));
846 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
847 struct winbind_SamLogon *r)
849 struct winbindd_domain *domain;
851 DATA_BLOB lm_response, nt_response;
852 domain = wb_child_domain();
853 if (domain == NULL) {
854 return NT_STATUS_REQUEST_NOT_ACCEPTED;
857 /* TODO: Handle interactive logons here */
858 if (r->in.validation_level != 3 ||
859 r->in.logon.network == NULL ||
860 (r->in.logon_level != NetlogonNetworkInformation
861 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
862 return NT_STATUS_REQUEST_NOT_ACCEPTED;
866 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
867 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
869 status = winbind_dual_SamLogon(domain, p->mem_ctx,
870 r->in.logon.network->identity_info.parameter_control,
871 r->in.logon.network->identity_info.account_name.string,
872 r->in.logon.network->identity_info.domain_name.string,
873 r->in.logon.network->identity_info.workstation.string,
874 r->in.logon.network->challenge,
875 lm_response, nt_response, &r->out.validation.sam3);
879 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
880 struct winbindd_domain *domain,
881 struct winbind_LogonControl *r)
884 struct rpc_pipe_client *netlogon_pipe = NULL;
885 struct netr_NETLOGON_INFO_2 *info2 = NULL;
886 WERROR check_result = WERR_INTERNAL_ERROR;
888 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
890 return WERR_NOT_ENOUGH_MEMORY;
893 if (domain->internal) {
894 check_result = WERR_OK;
899 * For now we just force a reconnect
901 * TODO: take care of the optional '\dcname'
903 invalidate_cm_connection(domain);
904 domain->conn.netlogon_force_reauth = true;
905 status = cm_connect_netlogon(domain, &netlogon_pipe);
906 reset_cm_connection_on_error(domain, status);
907 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
908 status = NT_STATUS_NO_LOGON_SERVERS;
910 if (!NT_STATUS_IS_OK(status)) {
911 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
912 __func__, domain->name, domain->alt_name,
915 * Here we return a top level error!
916 * This is different than TC_QUERY or TC_VERIFY.
918 return ntstatus_to_werror(status);
920 check_result = WERR_OK;
923 info2->pdc_connection_status = WERR_OK;
924 if (domain->dcname != NULL) {
925 info2->flags |= NETLOGON_HAS_IP;
926 info2->flags |= NETLOGON_HAS_TIMESERV;
927 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
929 if (info2->trusted_dc_name == NULL) {
930 return WERR_NOT_ENOUGH_MEMORY;
933 info2->trusted_dc_name = talloc_strdup(info2, "");
934 if (info2->trusted_dc_name == NULL) {
935 return WERR_NOT_ENOUGH_MEMORY;
938 info2->tc_connection_status = check_result;
940 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
941 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
942 "pdc_connection[%s] tc_connection[%s]\n",
943 __func__, domain->name, domain->alt_name,
945 win_errstr(info2->pdc_connection_status),
946 win_errstr(info2->tc_connection_status)));
949 r->out.query->info2 = info2;
951 DEBUG(5, ("%s: succeeded.\n", __func__));
955 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
956 struct winbindd_domain *domain,
957 struct winbind_LogonControl *r)
960 struct rpc_pipe_client *netlogon_pipe = NULL;
961 struct netr_NETLOGON_INFO_2 *info2 = NULL;
962 WERROR check_result = WERR_INTERNAL_ERROR;
964 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
966 return WERR_NOT_ENOUGH_MEMORY;
969 if (domain->internal) {
970 check_result = WERR_OK;
974 status = cm_connect_netlogon(domain, &netlogon_pipe);
975 reset_cm_connection_on_error(domain, status);
976 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
977 status = NT_STATUS_NO_LOGON_SERVERS;
979 if (!NT_STATUS_IS_OK(status)) {
980 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
982 check_result = ntstatus_to_werror(status);
985 check_result = WERR_OK;
988 info2->pdc_connection_status = WERR_OK;
989 if (domain->dcname != NULL) {
990 info2->flags |= NETLOGON_HAS_IP;
991 info2->flags |= NETLOGON_HAS_TIMESERV;
992 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
994 if (info2->trusted_dc_name == NULL) {
995 return WERR_NOT_ENOUGH_MEMORY;
998 info2->trusted_dc_name = talloc_strdup(info2, "");
999 if (info2->trusted_dc_name == NULL) {
1000 return WERR_NOT_ENOUGH_MEMORY;
1003 info2->tc_connection_status = check_result;
1005 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1006 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1007 "pdc_connection[%s] tc_connection[%s]\n",
1008 __func__, domain->name, domain->alt_name,
1010 win_errstr(info2->pdc_connection_status),
1011 win_errstr(info2->tc_connection_status)));
1014 r->out.query->info2 = info2;
1016 DEBUG(5, ("%s: succeeded.\n", __func__));
1020 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1021 struct winbindd_domain *domain,
1022 struct winbind_LogonControl *r)
1024 TALLOC_CTX *frame = talloc_stackframe();
1027 struct lsa_String trusted_domain_name = {};
1028 struct lsa_StringLarge trusted_domain_name_l = {};
1029 struct rpc_pipe_client *local_lsa_pipe = NULL;
1030 struct policy_handle local_lsa_policy = {};
1031 struct dcerpc_binding_handle *local_lsa = NULL;
1032 struct rpc_pipe_client *netlogon_pipe = NULL;
1033 struct cli_credentials *creds = NULL;
1034 struct samr_Password *cur_nt_hash = NULL;
1035 uint32_t trust_attributes = 0;
1036 struct samr_Password new_owf_password = {};
1038 struct samr_Password old_owf_password = {};
1040 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1041 bool fetch_fti = false;
1042 struct lsa_ForestTrustInformation *new_fti = NULL;
1043 struct netr_TrustInfo *trust_info = NULL;
1044 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1045 struct dcerpc_binding_handle *b = NULL;
1046 WERROR check_result = WERR_INTERNAL_ERROR;
1047 WERROR verify_result = WERR_INTERNAL_ERROR;
1050 trusted_domain_name.string = domain->name;
1051 trusted_domain_name_l.string = domain->name;
1053 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1054 if (info2 == NULL) {
1056 return WERR_NOT_ENOUGH_MEMORY;
1059 if (domain->internal) {
1060 check_result = WERR_OK;
1064 status = pdb_get_trust_credentials(domain->name,
1068 if (NT_STATUS_IS_OK(status)) {
1069 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1073 if (!domain->primary) {
1074 union lsa_TrustedDomainInfo *tdi = NULL;
1076 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1078 if (!NT_STATUS_IS_OK(status)) {
1079 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1080 __location__, __func__, nt_errstr(status)));
1082 return WERR_INTERNAL_ERROR;
1084 local_lsa = local_lsa_pipe->binding_handle;
1086 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1088 &trusted_domain_name,
1089 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1091 if (!NT_STATUS_IS_OK(status)) {
1092 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1093 __location__, __func__, domain->name, nt_errstr(status)));
1095 return WERR_INTERNAL_ERROR;
1097 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1098 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1099 __location__, __func__, domain->name));
1101 return WERR_NO_SUCH_DOMAIN;
1103 if (!NT_STATUS_IS_OK(result)) {
1104 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1105 __location__, __func__, domain->name, nt_errstr(result)));
1107 return WERR_INTERNAL_ERROR;
1110 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1111 "returned no trusted domain information\n",
1112 __location__, __func__));
1114 return WERR_INTERNAL_ERROR;
1117 local_tdo = &tdi->info_ex;
1118 trust_attributes = local_tdo->trust_attributes;
1121 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1122 struct lsa_ForestTrustInformation *old_fti = NULL;
1124 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1126 &trusted_domain_name,
1127 LSA_FOREST_TRUST_DOMAIN_INFO,
1129 if (!NT_STATUS_IS_OK(status)) {
1130 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1131 __location__, __func__, domain->name, nt_errstr(status)));
1133 return WERR_INTERNAL_ERROR;
1135 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1136 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1137 __func__, domain->name));
1140 result = NT_STATUS_OK;
1142 if (!NT_STATUS_IS_OK(result)) {
1143 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1144 __location__, __func__, domain->name, nt_errstr(result)));
1146 return WERR_INTERNAL_ERROR;
1149 TALLOC_FREE(old_fti);
1153 status = cm_connect_netlogon(domain, &netlogon_pipe);
1154 reset_cm_connection_on_error(domain, status);
1155 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1156 status = NT_STATUS_NO_LOGON_SERVERS;
1158 if (!NT_STATUS_IS_OK(status)) {
1159 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1160 nt_errstr(status)));
1161 check_result = ntstatus_to_werror(status);
1164 check_result = WERR_OK;
1165 b = netlogon_pipe->binding_handle;
1167 if (cur_nt_hash == NULL) {
1168 verify_result = WERR_NO_TRUST_LSA_SECRET;
1173 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1176 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1177 status = NT_STATUS_NOT_SUPPORTED;
1179 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1181 status = NT_STATUS_OK;
1183 if (!NT_STATUS_IS_OK(status)) {
1184 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1185 invalidate_cm_connection(domain);
1189 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1191 domain->name, nt_errstr(status)));
1192 check_result = ntstatus_to_werror(status);
1197 if (new_fti != NULL) {
1198 struct lsa_ForestTrustInformation old_fti = {};
1199 struct lsa_ForestTrustInformation *merged_fti = NULL;
1200 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1202 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1205 if (!NT_STATUS_IS_OK(status)) {
1206 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1207 __location__, __func__,
1208 domain->name, nt_errstr(status)));
1210 return ntstatus_to_werror(status);
1213 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1215 &trusted_domain_name_l,
1216 LSA_FOREST_TRUST_DOMAIN_INFO,
1218 0, /* check_only=0 => store it! */
1221 if (!NT_STATUS_IS_OK(status)) {
1222 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1223 __location__, __func__, domain->name, nt_errstr(status)));
1225 return WERR_INTERNAL_ERROR;
1227 if (!NT_STATUS_IS_OK(result)) {
1228 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1229 __location__, __func__, domain->name, nt_errstr(result)));
1231 return ntstatus_to_werror(result);
1235 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1240 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1241 status = NT_STATUS_NOT_SUPPORTED;
1243 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1244 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1245 nt_errstr(status)));
1246 verify_result = WERR_OK;
1249 if (!NT_STATUS_IS_OK(status)) {
1250 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1251 invalidate_cm_connection(domain);
1255 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1256 nt_errstr(status)));
1258 if (!dcerpc_binding_handle_is_connected(b)) {
1259 check_result = ntstatus_to_werror(status);
1262 verify_result = ntstatus_to_werror(status);
1267 if (trust_info != NULL && trust_info->count >= 1) {
1268 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1270 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1271 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1276 cmp_new = memcmp(new_owf_password.hash,
1278 sizeof(cur_nt_hash->hash));
1279 cmp_old = memcmp(old_owf_password.hash,
1281 sizeof(cur_nt_hash->hash));
1282 if (cmp_new != 0 && cmp_old != 0) {
1283 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1284 "any password known to dcname[%s]\n",
1285 __func__, domain->name, domain->alt_name,
1287 verify_result = WERR_WRONG_PASSWORD;
1292 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1293 "against the old password known to dcname[%s]\n",
1294 __func__, domain->name, domain->alt_name,
1298 verify_result = WERR_OK;
1302 verify_result = check_result;
1304 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1305 info2->pdc_connection_status = verify_result;
1306 if (domain->dcname != NULL) {
1307 info2->flags |= NETLOGON_HAS_IP;
1308 info2->flags |= NETLOGON_HAS_TIMESERV;
1309 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1311 if (info2->trusted_dc_name == NULL) {
1313 return WERR_NOT_ENOUGH_MEMORY;
1316 info2->trusted_dc_name = talloc_strdup(info2, "");
1317 if (info2->trusted_dc_name == NULL) {
1319 return WERR_NOT_ENOUGH_MEMORY;
1322 info2->tc_connection_status = check_result;
1324 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1325 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1326 "pdc_connection[%s] tc_connection[%s]\n",
1327 __func__, domain->name, domain->alt_name,
1329 win_errstr(info2->pdc_connection_status),
1330 win_errstr(info2->tc_connection_status)));
1333 r->out.query->info2 = info2;
1335 DEBUG(5, ("%s: succeeded.\n", __func__));
1340 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1341 struct winbindd_domain *domain,
1342 struct winbind_LogonControl *r)
1344 struct messaging_context *msg_ctx = winbind_messaging_context();
1346 struct rpc_pipe_client *netlogon_pipe;
1347 struct cli_credentials *creds = NULL;
1348 struct samr_Password *cur_nt_hash = NULL;
1349 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1350 struct dcerpc_binding_handle *b;
1351 WERROR change_result = WERR_OK;
1354 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1355 if (info1 == NULL) {
1356 return WERR_NOT_ENOUGH_MEMORY;
1359 if (domain->internal) {
1360 return WERR_NOT_SUPPORTED;
1363 status = pdb_get_trust_credentials(domain->name,
1367 if (NT_STATUS_IS_OK(status)) {
1368 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1373 status = cm_connect_netlogon(domain, &netlogon_pipe);
1374 reset_cm_connection_on_error(domain, status);
1375 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1376 status = NT_STATUS_NO_LOGON_SERVERS;
1378 if (!NT_STATUS_IS_OK(status)) {
1379 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1380 __func__, domain->name, domain->alt_name,
1381 nt_errstr(status)));
1383 * Here we return a top level error!
1384 * This is different than TC_QUERY or TC_VERIFY.
1386 return ntstatus_to_werror(status);
1388 b = netlogon_pipe->binding_handle;
1390 if (cur_nt_hash == NULL) {
1391 change_result = WERR_NO_TRUST_LSA_SECRET;
1394 TALLOC_FREE(cur_nt_hash);
1396 status = trust_pw_change(domain->conn.netlogon_creds,
1397 msg_ctx, b, domain->name,
1399 if (!NT_STATUS_IS_OK(status)) {
1400 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1401 invalidate_cm_connection(domain);
1406 DEBUG(1, ("trust_pw_change(%s): %s\n",
1407 domain->name, nt_errstr(status)));
1409 change_result = ntstatus_to_werror(status);
1413 change_result = WERR_OK;
1416 info1->pdc_connection_status = change_result;
1418 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1419 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1420 "pdc_connection[%s]\n",
1421 __func__, domain->name, domain->alt_name,
1423 win_errstr(info1->pdc_connection_status)));
1426 r->out.query->info1 = info1;
1428 DEBUG(5, ("%s: succeeded.\n", __func__));
1432 WERROR _winbind_LogonControl(struct pipes_struct *p,
1433 struct winbind_LogonControl *r)
1435 struct winbindd_domain *domain;
1437 domain = wb_child_domain();
1438 if (domain == NULL) {
1439 return WERR_NO_SUCH_DOMAIN;
1442 switch (r->in.function_code) {
1443 case NETLOGON_CONTROL_REDISCOVER:
1444 if (r->in.level != 2) {
1445 return WERR_INVALID_PARAMETER;
1447 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1448 case NETLOGON_CONTROL_TC_QUERY:
1449 if (r->in.level != 2) {
1450 return WERR_INVALID_PARAMETER;
1452 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1453 case NETLOGON_CONTROL_TC_VERIFY:
1454 if (r->in.level != 2) {
1455 return WERR_INVALID_PARAMETER;
1457 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1458 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1459 if (r->in.level != 1) {
1460 return WERR_INVALID_PARAMETER;
1462 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1467 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1468 __func__, r->in.function_code));
1469 return WERR_NOT_SUPPORTED;
1472 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1473 struct winbind_GetForestTrustInformation *r)
1475 TALLOC_CTX *frame = talloc_stackframe();
1476 NTSTATUS status, result;
1477 struct winbindd_domain *domain;
1478 struct rpc_pipe_client *netlogon_pipe;
1479 struct dcerpc_binding_handle *b;
1481 struct lsa_String trusted_domain_name = {};
1482 struct lsa_StringLarge trusted_domain_name_l = {};
1483 union lsa_TrustedDomainInfo *tdi = NULL;
1484 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1485 struct lsa_ForestTrustInformation _old_fti = {};
1486 struct lsa_ForestTrustInformation *old_fti = NULL;
1487 struct lsa_ForestTrustInformation *new_fti = NULL;
1488 struct lsa_ForestTrustInformation *merged_fti = NULL;
1489 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1490 bool update_fti = false;
1491 struct rpc_pipe_client *local_lsa_pipe;
1492 struct policy_handle local_lsa_policy;
1493 struct dcerpc_binding_handle *local_lsa = NULL;
1495 domain = wb_child_domain();
1496 if (domain == NULL) {
1498 return WERR_NO_SUCH_DOMAIN;
1502 * checking for domain->internal and domain->primary
1503 * makes sure we only do some work when running as DC.
1506 if (domain->internal) {
1508 return WERR_NO_SUCH_DOMAIN;
1511 if (domain->primary) {
1513 return WERR_NO_SUCH_DOMAIN;
1516 trusted_domain_name.string = domain->name;
1517 trusted_domain_name_l.string = domain->name;
1519 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1521 if (!NT_STATUS_IS_OK(status)) {
1522 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1523 __location__, __func__, nt_errstr(status)));
1525 return WERR_INTERNAL_ERROR;
1527 local_lsa = local_lsa_pipe->binding_handle;
1529 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1531 &trusted_domain_name,
1532 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1534 if (!NT_STATUS_IS_OK(status)) {
1535 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1536 __location__, __func__, domain->name, nt_errstr(status)));
1538 return WERR_INTERNAL_ERROR;
1540 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1541 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1542 __location__, __func__, domain->name));
1544 return WERR_NO_SUCH_DOMAIN;
1546 if (!NT_STATUS_IS_OK(result)) {
1547 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1548 __location__, __func__, domain->name, nt_errstr(result)));
1550 return WERR_INTERNAL_ERROR;
1553 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1554 "returned no trusted domain information\n",
1555 __location__, __func__));
1557 return WERR_INTERNAL_ERROR;
1560 tdo = &tdi->info_ex;
1562 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1563 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1564 __func__, tdo->netbios_name.string,
1565 tdo->domain_name.string,
1566 (unsigned)tdo->trust_attributes));
1568 return WERR_NO_SUCH_DOMAIN;
1571 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1573 return WERR_INVALID_FLAGS;
1577 status = cm_connect_netlogon(domain, &netlogon_pipe);
1578 reset_cm_connection_on_error(domain, status);
1579 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1580 status = NT_STATUS_NO_LOGON_SERVERS;
1582 if (!NT_STATUS_IS_OK(status)) {
1583 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1584 nt_errstr(status)));
1586 return ntstatus_to_werror(status);
1588 b = netlogon_pipe->binding_handle;
1590 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1593 if (!NT_STATUS_IS_OK(status)) {
1594 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1595 invalidate_cm_connection(domain);
1599 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1600 domain->name, nt_errstr(status)));
1602 return ntstatus_to_werror(status);
1605 *r->out.forest_trust_info = new_fti;
1607 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1611 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1613 &trusted_domain_name,
1614 LSA_FOREST_TRUST_DOMAIN_INFO,
1616 if (!NT_STATUS_IS_OK(status)) {
1617 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1618 __location__, __func__, domain->name, nt_errstr(status)));
1620 return WERR_INTERNAL_ERROR;
1622 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1623 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1624 __func__, domain->name));
1626 old_fti = &_old_fti;
1627 result = NT_STATUS_OK;
1629 if (!NT_STATUS_IS_OK(result)) {
1630 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1631 __location__, __func__, domain->name, nt_errstr(result)));
1633 return WERR_INTERNAL_ERROR;
1636 if (old_fti == NULL) {
1637 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1638 "returned success without returning forest trust information\n",
1639 __location__, __func__));
1641 return WERR_INTERNAL_ERROR;
1648 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1650 if (!NT_STATUS_IS_OK(status)) {
1651 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1652 __location__, __func__, domain->name, nt_errstr(status)));
1654 return ntstatus_to_werror(status);
1657 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1659 &trusted_domain_name_l,
1660 LSA_FOREST_TRUST_DOMAIN_INFO,
1662 0, /* check_only=0 => store it! */
1665 if (!NT_STATUS_IS_OK(status)) {
1666 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1667 __location__, __func__, domain->name, nt_errstr(status)));
1669 return WERR_INTERNAL_ERROR;
1671 if (!NT_STATUS_IS_OK(result)) {
1672 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1673 __location__, __func__, domain->name, nt_errstr(result)));
1675 return ntstatus_to_werror(result);
1679 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));