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 = 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)) {
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 = 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);
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
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;
136 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
138 DEBUG(10, ("idmap domain %s:%s not found\n",
139 d->name.string, sid_string_dbg(d->sid)));
145 for (j=0; j<r->in.ids->num_ids; j++) {
146 if (r->in.ids->ids[j].domain_index == i) {
151 ids = talloc_realloc(talloc_tos(), ids,
152 struct id_map, num_ids);
156 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
157 struct id_map *, num_ids+1);
158 if (id_ptrs == NULL) {
161 id_idx = talloc_realloc(talloc_tos(), id_idx,
163 if (id_idx == NULL) {
166 sids = talloc_realloc(talloc_tos(), sids,
167 struct dom_sid, num_ids);
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) {
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;
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",
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;
212 id->xid = ids[j].xid;
215 status = NT_STATUS_OK;
218 TALLOC_FREE(id_ptrs);
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)
239 status = idmap_allocate_uid(&xid);
240 if (!NT_STATUS_IS_OK(status)) {
243 *r->out.uid = xid.id;
247 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
252 status = idmap_allocate_gid(&xid);
253 if (!NT_STATUS_IS_OK(status)) {
256 *r->out.gid = xid.id;
260 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
262 struct winbindd_domain *domain = wb_child_domain();
265 if (domain == NULL) {
266 return NT_STATUS_REQUEST_NOT_ACCEPTED;
269 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
271 reset_cm_connection_on_error(domain, status);
275 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
276 struct wbint_LookupUserAliases *r)
278 struct winbindd_domain *domain = wb_child_domain();
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);
292 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
293 struct wbint_LookupUserGroups *r)
295 struct winbindd_domain *domain = wb_child_domain();
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);
309 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
310 struct wbint_QuerySequenceNumber *r)
312 struct winbindd_domain *domain = wb_child_domain();
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);
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;
331 uint32_t *name_types;
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)) {
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];
363 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
364 struct wbint_QueryUserList *r)
366 struct winbindd_domain *domain = wb_child_domain();
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);
380 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
381 struct wbint_QueryGroupList *r)
383 struct winbindd_domain *domain = wb_child_domain();
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;
390 uint64_t num_total = 0;
391 struct wbint_Principal *result;
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;
411 * We might include local groups in more
412 * setups later, but that requires more work
418 if (include_local_groups) {
419 status = domain->methods->enum_local_groups(domain, talloc_tos(),
422 reset_cm_connection_on_error(domain, status);
423 if (!NT_STATUS_IS_OK(status)) {
428 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
431 reset_cm_connection_on_error(domain, status);
432 if (!NT_STATUS_IS_OK(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,
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) {
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) {
473 TALLOC_FREE(dom_groups);
474 TALLOC_FREE(local_groups);
475 return NT_STATUS_NO_MEMORY;
479 TALLOC_FREE(dom_groups);
481 r->out.groups->num_principals = ti;
482 r->out.groups->principals = result;
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;
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 : "",
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"));
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)) {
528 if (reset_cm_connection_on_error(domain, status)) {
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"));
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;
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);
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",
573 if (!W_ERROR_IS_OK(werr)) {
574 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
576 status = werror_to_ntstatus(werr);
580 *r->out.dc_info = dc_info;
581 status = NT_STATUS_OK;
584 /* And restore our original timeout. */
585 rpccli_set_timeout(netlogon_pipe, orig_timeout);
590 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
592 struct winbindd_domain *domain = wb_child_domain();
595 enum lsa_SidType *types;
596 struct wbint_Principal *result;
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)) {
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]);
629 r->out.names->num_principals = r->in.rids->num_rids;
630 r->out.names->principals = result;
634 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
635 struct wbint_CheckMachineAccount *r)
637 struct winbindd_domain *domain;
641 domain = wb_child_domain();
642 if (domain == NULL) {
643 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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)) {
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
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"));
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)));
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;
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"));
706 status = trust_pw_change(domain->conn.netlogon_creds,
708 netlogon_pipe->binding_handle,
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"));
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)));
726 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
729 struct winbindd_domain *domain;
730 struct rpc_pipe_client *netlogon_pipe;
731 union netr_CONTROL_QUERY_INFORMATION info;
733 fstring logon_server;
734 struct dcerpc_binding_handle *b;
737 domain = wb_child_domain();
738 if (domain == NULL) {
739 return NT_STATUS_REQUEST_NOT_ACCEPTED;
743 status = cm_connect_netlogon(domain, &netlogon_pipe);
744 reset_cm_connection_on_error(domain, status);
745 if (!NT_STATUS_IS_OK(status)) {
746 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
751 b = netlogon_pipe->binding_handle;
753 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
754 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
755 if (*r->out.dcname == NULL) {
756 DEBUG(2, ("Could not allocate memory\n"));
757 return NT_STATUS_NO_MEMORY;
761 * This provokes a WERR_NOT_SUPPORTED error message. This is
762 * documented in the wspp docs. I could not get a successful
763 * call to work, but the main point here is testing that the
764 * netlogon pipe works.
766 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
767 logon_server, NETLOGON_CONTROL_QUERY,
770 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
771 DEBUG(10, ("Session might have expired. "
772 "Reconnect and retry once.\n"));
773 invalidate_cm_connection(domain);
778 reset_cm_connection_on_error(domain, status);
779 if (!NT_STATUS_IS_OK(status)) {
780 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
785 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
786 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
787 "WERR_NOT_SUPPORTED\n",
789 return werror_to_ntstatus(werr);
792 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
796 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
797 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
799 struct winbindd_domain *domain;
801 struct rpc_pipe_client *netlogon_pipe;
803 domain = wb_child_domain();
804 if (domain == NULL) {
805 return NT_STATUS_REQUEST_NOT_ACCEPTED;
808 status = cm_connect_netlogon(domain, &netlogon_pipe);
809 if (!NT_STATUS_IS_OK(status)) {
810 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
814 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
815 netlogon_pipe->binding_handle,
820 /* Pass back result code - zero for success, other values for
821 specific failures. */
823 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
824 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
827 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
828 ("Update of DNS records via RW DC %s returned %s\n",
829 domain->name, nt_errstr(status)));
834 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
835 struct winbind_SamLogon *r)
837 struct winbindd_domain *domain;
839 DATA_BLOB lm_response, nt_response;
840 domain = wb_child_domain();
841 if (domain == NULL) {
842 return NT_STATUS_REQUEST_NOT_ACCEPTED;
845 /* TODO: Handle interactive logons here */
846 if (r->in.validation_level != 3 ||
847 r->in.logon.network == NULL ||
848 (r->in.logon_level != NetlogonNetworkInformation
849 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
850 return NT_STATUS_REQUEST_NOT_ACCEPTED;
854 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
855 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
857 status = winbind_dual_SamLogon(domain, p->mem_ctx,
858 r->in.logon.network->identity_info.parameter_control,
859 r->in.logon.network->identity_info.account_name.string,
860 r->in.logon.network->identity_info.domain_name.string,
861 r->in.logon.network->identity_info.workstation.string,
862 r->in.logon.network->challenge,
863 lm_response, nt_response, &r->out.validation.sam3);
867 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
868 struct winbindd_domain *domain,
869 struct winbind_LogonControl *r)
872 struct rpc_pipe_client *netlogon_pipe = NULL;
873 struct netr_NETLOGON_INFO_2 *info2 = NULL;
874 WERROR check_result = WERR_INTERNAL_ERROR;
876 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
881 if (domain->internal) {
882 check_result = WERR_OK;
887 * For now we just force a reconnect
889 * TODO: take care of the optional '\dcname'
891 invalidate_cm_connection(domain);
892 domain->conn.netlogon_force_reauth = true;
893 status = cm_connect_netlogon(domain, &netlogon_pipe);
894 reset_cm_connection_on_error(domain, status);
895 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
896 status = NT_STATUS_NO_LOGON_SERVERS;
898 if (!NT_STATUS_IS_OK(status)) {
899 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
900 __func__, domain->name, domain->alt_name,
903 * Here we return a top level error!
904 * This is different than TC_QUERY or TC_VERIFY.
906 return ntstatus_to_werror(status);
908 check_result = WERR_OK;
911 info2->pdc_connection_status = WERR_OK;
912 if (domain->dcname != NULL) {
913 info2->flags |= NETLOGON_HAS_IP;
914 info2->flags |= NETLOGON_HAS_TIMESERV;
915 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
917 if (info2->trusted_dc_name == NULL) {
921 info2->trusted_dc_name = talloc_strdup(info2, "");
922 if (info2->trusted_dc_name == NULL) {
926 info2->tc_connection_status = check_result;
928 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
929 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
930 "pdc_connection[%s] tc_connection[%s]\n",
931 __func__, domain->name, domain->alt_name,
933 win_errstr(info2->pdc_connection_status),
934 win_errstr(info2->tc_connection_status)));
937 r->out.query->info2 = info2;
939 DEBUG(5, ("%s: succeeded.\n", __func__));
943 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
944 struct winbindd_domain *domain,
945 struct winbind_LogonControl *r)
948 struct rpc_pipe_client *netlogon_pipe = NULL;
949 struct netr_NETLOGON_INFO_2 *info2 = NULL;
950 WERROR check_result = WERR_INTERNAL_ERROR;
952 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
957 if (domain->internal) {
958 check_result = WERR_OK;
962 status = cm_connect_netlogon(domain, &netlogon_pipe);
963 reset_cm_connection_on_error(domain, status);
964 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
965 status = NT_STATUS_NO_LOGON_SERVERS;
967 if (!NT_STATUS_IS_OK(status)) {
968 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
970 check_result = ntstatus_to_werror(status);
973 check_result = WERR_OK;
976 info2->pdc_connection_status = WERR_OK;
977 if (domain->dcname != NULL) {
978 info2->flags |= NETLOGON_HAS_IP;
979 info2->flags |= NETLOGON_HAS_TIMESERV;
980 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
982 if (info2->trusted_dc_name == NULL) {
986 info2->trusted_dc_name = talloc_strdup(info2, "");
987 if (info2->trusted_dc_name == NULL) {
991 info2->tc_connection_status = check_result;
993 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
994 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
995 "pdc_connection[%s] tc_connection[%s]\n",
996 __func__, domain->name, domain->alt_name,
998 win_errstr(info2->pdc_connection_status),
999 win_errstr(info2->tc_connection_status)));
1002 r->out.query->info2 = info2;
1004 DEBUG(5, ("%s: succeeded.\n", __func__));
1008 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1009 struct winbindd_domain *domain,
1010 struct winbind_LogonControl *r)
1012 TALLOC_CTX *frame = talloc_stackframe();
1015 struct lsa_String trusted_domain_name = {};
1016 struct lsa_StringLarge trusted_domain_name_l = {};
1017 struct rpc_pipe_client *local_lsa_pipe = NULL;
1018 struct policy_handle local_lsa_policy = {};
1019 struct dcerpc_binding_handle *local_lsa = NULL;
1020 struct rpc_pipe_client *netlogon_pipe = NULL;
1021 struct cli_credentials *creds = NULL;
1022 struct samr_Password *cur_nt_hash = NULL;
1023 uint32_t trust_attributes = 0;
1024 struct samr_Password new_owf_password = {};
1026 struct samr_Password old_owf_password = {};
1028 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1029 bool fetch_fti = false;
1030 struct lsa_ForestTrustInformation *new_fti = NULL;
1031 struct netr_TrustInfo *trust_info = NULL;
1032 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1033 struct dcerpc_binding_handle *b = NULL;
1034 WERROR check_result = WERR_INTERNAL_ERROR;
1035 WERROR verify_result = WERR_INTERNAL_ERROR;
1038 trusted_domain_name.string = domain->name;
1039 trusted_domain_name_l.string = domain->name;
1041 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1042 if (info2 == NULL) {
1047 if (domain->internal) {
1048 check_result = WERR_OK;
1052 status = pdb_get_trust_credentials(domain->name,
1056 if (NT_STATUS_IS_OK(status)) {
1057 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1061 if (!domain->primary) {
1062 union lsa_TrustedDomainInfo *tdi = NULL;
1064 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1066 if (!NT_STATUS_IS_OK(status)) {
1067 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1068 __location__, __func__, nt_errstr(status)));
1070 return WERR_INTERNAL_ERROR;
1072 local_lsa = local_lsa_pipe->binding_handle;
1074 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1076 &trusted_domain_name,
1077 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1079 if (!NT_STATUS_IS_OK(status)) {
1080 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1081 __location__, __func__, domain->name, nt_errstr(status)));
1083 return WERR_INTERNAL_ERROR;
1085 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1086 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1087 __location__, __func__, domain->name));
1089 return WERR_NO_SUCH_DOMAIN;
1091 if (!NT_STATUS_IS_OK(result)) {
1092 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1093 __location__, __func__, domain->name, nt_errstr(result)));
1095 return WERR_INTERNAL_ERROR;
1098 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1099 "returned no trusted domain information\n",
1100 __location__, __func__));
1102 return WERR_INTERNAL_ERROR;
1105 local_tdo = &tdi->info_ex;
1106 trust_attributes = local_tdo->trust_attributes;
1109 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1110 struct lsa_ForestTrustInformation *old_fti = NULL;
1112 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1114 &trusted_domain_name,
1115 LSA_FOREST_TRUST_DOMAIN_INFO,
1117 if (!NT_STATUS_IS_OK(status)) {
1118 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1119 __location__, __func__, domain->name, nt_errstr(status)));
1121 return WERR_INTERNAL_ERROR;
1123 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1124 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1125 __func__, domain->name));
1128 result = NT_STATUS_OK;
1130 if (!NT_STATUS_IS_OK(result)) {
1131 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1132 __location__, __func__, domain->name, nt_errstr(result)));
1134 return WERR_INTERNAL_ERROR;
1137 TALLOC_FREE(old_fti);
1141 status = cm_connect_netlogon(domain, &netlogon_pipe);
1142 reset_cm_connection_on_error(domain, status);
1143 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1144 status = NT_STATUS_NO_LOGON_SERVERS;
1146 if (!NT_STATUS_IS_OK(status)) {
1147 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1148 nt_errstr(status)));
1149 check_result = ntstatus_to_werror(status);
1152 check_result = WERR_OK;
1153 b = netlogon_pipe->binding_handle;
1155 if (cur_nt_hash == NULL) {
1156 verify_result = WERR_NO_TRUST_LSA_SECRET;
1161 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1164 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1165 status = NT_STATUS_NOT_SUPPORTED;
1167 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1169 status = NT_STATUS_OK;
1171 if (!NT_STATUS_IS_OK(status)) {
1172 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1173 invalidate_cm_connection(domain);
1177 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1179 domain->name, nt_errstr(status)));
1180 check_result = ntstatus_to_werror(status);
1185 if (new_fti != NULL) {
1186 struct lsa_ForestTrustInformation old_fti = {};
1187 struct lsa_ForestTrustInformation *merged_fti = NULL;
1188 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1190 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1193 if (!NT_STATUS_IS_OK(status)) {
1194 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1195 __location__, __func__,
1196 domain->name, nt_errstr(status)));
1198 return ntstatus_to_werror(status);
1201 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1203 &trusted_domain_name_l,
1204 LSA_FOREST_TRUST_DOMAIN_INFO,
1206 0, /* check_only=0 => store it! */
1209 if (!NT_STATUS_IS_OK(status)) {
1210 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1211 __location__, __func__, domain->name, nt_errstr(status)));
1213 return WERR_INTERNAL_ERROR;
1215 if (!NT_STATUS_IS_OK(result)) {
1216 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1217 __location__, __func__, domain->name, nt_errstr(result)));
1219 return ntstatus_to_werror(result);
1223 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1228 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1229 status = NT_STATUS_NOT_SUPPORTED;
1231 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1232 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1233 nt_errstr(status)));
1234 verify_result = WERR_OK;
1237 if (!NT_STATUS_IS_OK(status)) {
1238 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1239 invalidate_cm_connection(domain);
1243 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1244 nt_errstr(status)));
1246 if (!dcerpc_binding_handle_is_connected(b)) {
1247 check_result = ntstatus_to_werror(status);
1250 verify_result = ntstatus_to_werror(status);
1255 if (trust_info != NULL && trust_info->count >= 1) {
1256 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1258 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1259 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1264 cmp_new = memcmp(new_owf_password.hash,
1266 sizeof(cur_nt_hash->hash));
1267 cmp_old = memcmp(old_owf_password.hash,
1269 sizeof(cur_nt_hash->hash));
1270 if (cmp_new != 0 && cmp_old != 0) {
1271 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1272 "any password known to dcname[%s]\n",
1273 __func__, domain->name, domain->alt_name,
1275 verify_result = WERR_WRONG_PASSWORD;
1280 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1281 "against the old password known to dcname[%s]\n",
1282 __func__, domain->name, domain->alt_name,
1286 verify_result = WERR_OK;
1290 verify_result = check_result;
1292 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1293 info2->pdc_connection_status = verify_result;
1294 if (domain->dcname != NULL) {
1295 info2->flags |= NETLOGON_HAS_IP;
1296 info2->flags |= NETLOGON_HAS_TIMESERV;
1297 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1299 if (info2->trusted_dc_name == NULL) {
1304 info2->trusted_dc_name = talloc_strdup(info2, "");
1305 if (info2->trusted_dc_name == NULL) {
1310 info2->tc_connection_status = check_result;
1312 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1313 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1314 "pdc_connection[%s] tc_connection[%s]\n",
1315 __func__, domain->name, domain->alt_name,
1317 win_errstr(info2->pdc_connection_status),
1318 win_errstr(info2->tc_connection_status)));
1321 r->out.query->info2 = info2;
1323 DEBUG(5, ("%s: succeeded.\n", __func__));
1328 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1329 struct winbindd_domain *domain,
1330 struct winbind_LogonControl *r)
1332 struct messaging_context *msg_ctx = winbind_messaging_context();
1334 struct rpc_pipe_client *netlogon_pipe;
1335 struct cli_credentials *creds = NULL;
1336 struct samr_Password *cur_nt_hash = NULL;
1337 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1338 struct dcerpc_binding_handle *b;
1339 WERROR change_result = WERR_OK;
1342 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1343 if (info1 == NULL) {
1347 if (domain->internal) {
1348 return WERR_NOT_SUPPORTED;
1351 status = pdb_get_trust_credentials(domain->name,
1355 if (NT_STATUS_IS_OK(status)) {
1356 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1361 status = cm_connect_netlogon(domain, &netlogon_pipe);
1362 reset_cm_connection_on_error(domain, status);
1363 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1364 status = NT_STATUS_NO_LOGON_SERVERS;
1366 if (!NT_STATUS_IS_OK(status)) {
1367 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1368 __func__, domain->name, domain->alt_name,
1369 nt_errstr(status)));
1371 * Here we return a top level error!
1372 * This is different than TC_QUERY or TC_VERIFY.
1374 return ntstatus_to_werror(status);
1376 b = netlogon_pipe->binding_handle;
1378 if (cur_nt_hash == NULL) {
1379 change_result = WERR_NO_TRUST_LSA_SECRET;
1382 TALLOC_FREE(cur_nt_hash);
1384 status = trust_pw_change(domain->conn.netlogon_creds,
1385 msg_ctx, b, domain->name,
1387 if (!NT_STATUS_IS_OK(status)) {
1388 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1389 invalidate_cm_connection(domain);
1394 DEBUG(1, ("trust_pw_change(%s): %s\n",
1395 domain->name, nt_errstr(status)));
1397 change_result = ntstatus_to_werror(status);
1401 change_result = WERR_OK;
1404 info1->pdc_connection_status = change_result;
1406 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1407 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1408 "pdc_connection[%s]\n",
1409 __func__, domain->name, domain->alt_name,
1411 win_errstr(info1->pdc_connection_status)));
1414 r->out.query->info1 = info1;
1416 DEBUG(5, ("%s: succeeded.\n", __func__));
1420 WERROR _winbind_LogonControl(struct pipes_struct *p,
1421 struct winbind_LogonControl *r)
1423 struct winbindd_domain *domain;
1425 domain = wb_child_domain();
1426 if (domain == NULL) {
1427 return WERR_NO_SUCH_DOMAIN;
1430 switch (r->in.function_code) {
1431 case NETLOGON_CONTROL_REDISCOVER:
1432 if (r->in.level != 2) {
1433 return WERR_INVALID_PARAMETER;
1435 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1436 case NETLOGON_CONTROL_TC_QUERY:
1437 if (r->in.level != 2) {
1438 return WERR_INVALID_PARAMETER;
1440 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1441 case NETLOGON_CONTROL_TC_VERIFY:
1442 if (r->in.level != 2) {
1443 return WERR_INVALID_PARAMETER;
1445 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1446 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1447 if (r->in.level != 1) {
1448 return WERR_INVALID_PARAMETER;
1450 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1455 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1456 __func__, r->in.function_code));
1457 return WERR_NOT_SUPPORTED;
1460 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1461 struct winbind_GetForestTrustInformation *r)
1463 TALLOC_CTX *frame = talloc_stackframe();
1464 NTSTATUS status, result;
1465 struct winbindd_domain *domain;
1466 struct rpc_pipe_client *netlogon_pipe;
1467 struct dcerpc_binding_handle *b;
1469 struct lsa_String trusted_domain_name = {};
1470 struct lsa_StringLarge trusted_domain_name_l = {};
1471 union lsa_TrustedDomainInfo *tdi = NULL;
1472 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1473 struct lsa_ForestTrustInformation _old_fti = {};
1474 struct lsa_ForestTrustInformation *old_fti = NULL;
1475 struct lsa_ForestTrustInformation *new_fti = NULL;
1476 struct lsa_ForestTrustInformation *merged_fti = NULL;
1477 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1478 bool update_fti = false;
1479 struct rpc_pipe_client *local_lsa_pipe;
1480 struct policy_handle local_lsa_policy;
1481 struct dcerpc_binding_handle *local_lsa = NULL;
1483 domain = wb_child_domain();
1484 if (domain == NULL) {
1486 return WERR_NO_SUCH_DOMAIN;
1490 * checking for domain->internal and domain->primary
1491 * makes sure we only do some work when running as DC.
1494 if (domain->internal) {
1496 return WERR_NO_SUCH_DOMAIN;
1499 if (domain->primary) {
1501 return WERR_NO_SUCH_DOMAIN;
1504 trusted_domain_name.string = domain->name;
1505 trusted_domain_name_l.string = domain->name;
1507 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1509 if (!NT_STATUS_IS_OK(status)) {
1510 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1511 __location__, __func__, nt_errstr(status)));
1513 return WERR_INTERNAL_ERROR;
1515 local_lsa = local_lsa_pipe->binding_handle;
1517 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1519 &trusted_domain_name,
1520 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1522 if (!NT_STATUS_IS_OK(status)) {
1523 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1524 __location__, __func__, domain->name, nt_errstr(status)));
1526 return WERR_INTERNAL_ERROR;
1528 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1529 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1530 __location__, __func__, domain->name));
1532 return WERR_NO_SUCH_DOMAIN;
1534 if (!NT_STATUS_IS_OK(result)) {
1535 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1536 __location__, __func__, domain->name, nt_errstr(result)));
1538 return WERR_INTERNAL_ERROR;
1541 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1542 "returned no trusted domain information\n",
1543 __location__, __func__));
1545 return WERR_INTERNAL_ERROR;
1548 tdo = &tdi->info_ex;
1550 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1551 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1552 __func__, tdo->netbios_name.string,
1553 tdo->domain_name.string,
1554 (unsigned)tdo->trust_attributes));
1556 return WERR_NO_SUCH_DOMAIN;
1559 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1561 return WERR_INVALID_FLAGS;
1565 status = cm_connect_netlogon(domain, &netlogon_pipe);
1566 reset_cm_connection_on_error(domain, status);
1567 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1568 status = NT_STATUS_NO_LOGON_SERVERS;
1570 if (!NT_STATUS_IS_OK(status)) {
1571 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1572 nt_errstr(status)));
1574 return ntstatus_to_werror(status);
1576 b = netlogon_pipe->binding_handle;
1578 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1581 if (!NT_STATUS_IS_OK(status)) {
1582 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1583 invalidate_cm_connection(domain);
1587 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1588 domain->name, nt_errstr(status)));
1590 return ntstatus_to_werror(status);
1593 *r->out.forest_trust_info = new_fti;
1595 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1599 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1601 &trusted_domain_name,
1602 LSA_FOREST_TRUST_DOMAIN_INFO,
1604 if (!NT_STATUS_IS_OK(status)) {
1605 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1606 __location__, __func__, domain->name, nt_errstr(status)));
1608 return WERR_INTERNAL_ERROR;
1610 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1611 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1612 __func__, domain->name));
1614 old_fti = &_old_fti;
1615 result = NT_STATUS_OK;
1617 if (!NT_STATUS_IS_OK(result)) {
1618 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1619 __location__, __func__, domain->name, nt_errstr(result)));
1621 return WERR_INTERNAL_ERROR;
1624 if (old_fti == NULL) {
1625 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1626 "returned success without returning forest trust information\n",
1627 __location__, __func__));
1629 return WERR_INTERNAL_ERROR;
1636 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1638 if (!NT_STATUS_IS_OK(status)) {
1639 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1640 __location__, __func__, domain->name, nt_errstr(status)));
1642 return ntstatus_to_werror(status);
1645 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1647 &trusted_domain_name_l,
1648 LSA_FOREST_TRUST_DOMAIN_INFO,
1650 0, /* check_only=0 => store it! */
1653 if (!NT_STATUS_IS_OK(status)) {
1654 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1655 __location__, __func__, domain->name, nt_errstr(status)));
1657 return WERR_INTERNAL_ERROR;
1659 if (!NT_STATUS_IS_OK(result)) {
1660 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1661 __location__, __func__, domain->name, nt_errstr(result)));
1663 return ntstatus_to_werror(result);
1667 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));