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_QuerySequenceNumber(struct pipes_struct *p,
305 struct wbint_QuerySequenceNumber *r)
307 struct winbindd_domain *domain = wb_child_domain();
310 if (domain == NULL) {
311 return NT_STATUS_REQUEST_NOT_ACCEPTED;
314 status = wb_cache_sequence_number(domain, r->out.sequence);
315 reset_cm_connection_on_error(domain, status);
319 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
320 struct wbint_LookupGroupMembers *r)
322 struct winbindd_domain *domain = wb_child_domain();
323 uint32_t i, num_names;
324 struct dom_sid *sid_mem;
326 uint32_t *name_types;
329 if (domain == NULL) {
330 return NT_STATUS_REQUEST_NOT_ACCEPTED;
333 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
334 r->in.type, &num_names, &sid_mem,
335 &names, &name_types);
336 reset_cm_connection_on_error(domain, status);
337 if (!NT_STATUS_IS_OK(status)) {
341 r->out.members->num_principals = num_names;
342 r->out.members->principals = talloc_array(
343 r->out.members, struct wbint_Principal, num_names);
344 if (r->out.members->principals == NULL) {
345 return NT_STATUS_NO_MEMORY;
348 for (i=0; i<num_names; i++) {
349 struct wbint_Principal *m = &r->out.members->principals[i];
350 sid_copy(&m->sid, &sid_mem[i]);
351 m->name = talloc_move(r->out.members->principals, &names[i]);
352 m->type = (enum lsa_SidType)name_types[i];
358 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
359 struct wbint_QueryGroupList *r)
361 struct winbindd_domain *domain = wb_child_domain();
363 uint32_t num_local_groups = 0;
364 struct wb_acct_info *local_groups = NULL;
365 uint32_t num_dom_groups = 0;
366 struct wb_acct_info *dom_groups = NULL;
368 uint64_t num_total = 0;
369 struct wbint_Principal *result;
371 bool include_local_groups = false;
373 if (domain == NULL) {
374 return NT_STATUS_REQUEST_NOT_ACCEPTED;
377 switch (lp_server_role()) {
378 case ROLE_ACTIVE_DIRECTORY_DC:
379 if (domain->internal) {
381 * we want to include local groups
382 * for BUILTIN and WORKGROUP
384 include_local_groups = true;
389 * We might include local groups in more
390 * setups later, but that requires more work
396 if (include_local_groups) {
397 status = wb_cache_enum_local_groups(domain, talloc_tos(),
400 reset_cm_connection_on_error(domain, status);
401 if (!NT_STATUS_IS_OK(status)) {
406 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
409 reset_cm_connection_on_error(domain, status);
410 if (!NT_STATUS_IS_OK(status)) {
414 num_total = num_local_groups + num_dom_groups;
415 if (num_total > UINT32_MAX) {
416 return NT_STATUS_INTERNAL_ERROR;
419 result = talloc_array(r->out.groups, struct wbint_Principal,
421 if (result == NULL) {
422 return NT_STATUS_NO_MEMORY;
425 for (i = 0; i < num_local_groups; i++) {
426 struct wb_acct_info *lg = &local_groups[i];
427 struct wbint_Principal *rg = &result[ti++];
429 sid_compose(&rg->sid, &domain->sid, lg->rid);
430 rg->type = SID_NAME_ALIAS;
431 rg->name = talloc_strdup(result, lg->acct_name);
432 if (rg->name == NULL) {
434 TALLOC_FREE(dom_groups);
435 TALLOC_FREE(local_groups);
436 return NT_STATUS_NO_MEMORY;
439 num_local_groups = 0;
440 TALLOC_FREE(local_groups);
442 for (i = 0; i < num_dom_groups; i++) {
443 struct wb_acct_info *dg = &dom_groups[i];
444 struct wbint_Principal *rg = &result[ti++];
446 sid_compose(&rg->sid, &domain->sid, dg->rid);
447 rg->type = SID_NAME_DOM_GRP;
448 rg->name = talloc_strdup(result, dg->acct_name);
449 if (rg->name == NULL) {
451 TALLOC_FREE(dom_groups);
452 TALLOC_FREE(local_groups);
453 return NT_STATUS_NO_MEMORY;
457 TALLOC_FREE(dom_groups);
459 r->out.groups->num_principals = ti;
460 r->out.groups->principals = result;
465 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
466 struct wbint_QueryUserRidList *r)
468 struct winbindd_domain *domain = wb_child_domain();
471 if (domain == NULL) {
472 return NT_STATUS_REQUEST_NOT_ACCEPTED;
476 * Right now this is overkill. We should add a backend call
477 * just querying the rids.
480 status = wb_cache_query_user_list(domain, p->mem_ctx,
482 reset_cm_connection_on_error(domain, status);
484 if (!NT_STATUS_IS_OK(status)) {
488 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
493 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
495 struct winbindd_domain *domain = wb_child_domain();
496 struct rpc_pipe_client *netlogon_pipe;
497 struct netr_DsRGetDCNameInfo *dc_info;
500 unsigned int orig_timeout;
501 struct dcerpc_binding_handle *b;
503 if (domain == NULL) {
504 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
505 r->in.domain_name, r->in.domain_guid,
506 r->in.site_name ? r->in.site_name : "",
511 status = cm_connect_netlogon(domain, &netlogon_pipe);
513 reset_cm_connection_on_error(domain, status);
514 if (!NT_STATUS_IS_OK(status)) {
515 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
519 b = netlogon_pipe->binding_handle;
521 /* This call can take a long time - allow the server to time out.
522 35 seconds should do it. */
524 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
526 if (domain->active_directory) {
527 status = dcerpc_netr_DsRGetDCName(b,
528 p->mem_ctx, domain->dcname,
529 r->in.domain_name, NULL, r->in.domain_guid,
530 r->in.flags, r->out.dc_info, &werr);
531 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
534 if (reset_cm_connection_on_error(domain, status)) {
536 status = cm_connect_netlogon(domain, &netlogon_pipe);
538 reset_cm_connection_on_error(domain, status);
539 if (!NT_STATUS_IS_OK(status)) {
540 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
544 b = netlogon_pipe->binding_handle;
546 /* This call can take a long time - allow the server to time out.
547 35 seconds should do it. */
549 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
554 * Fallback to less capable methods
557 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
558 if (dc_info == NULL) {
559 status = NT_STATUS_NO_MEMORY;
563 if (r->in.flags & DS_PDC_REQUIRED) {
564 status = dcerpc_netr_GetDcName(b,
565 p->mem_ctx, domain->dcname,
566 r->in.domain_name, &dc_info->dc_unc, &werr);
568 status = dcerpc_netr_GetAnyDCName(b,
569 p->mem_ctx, domain->dcname,
570 r->in.domain_name, &dc_info->dc_unc, &werr);
573 reset_cm_connection_on_error(domain, status);
574 if (!NT_STATUS_IS_OK(status)) {
575 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
579 if (!W_ERROR_IS_OK(werr)) {
580 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
582 status = werror_to_ntstatus(werr);
586 *r->out.dc_info = dc_info;
587 status = NT_STATUS_OK;
590 /* And restore our original timeout. */
591 rpccli_set_timeout(netlogon_pipe, orig_timeout);
596 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
598 struct winbindd_domain *domain = wb_child_domain();
601 enum lsa_SidType *types;
602 struct wbint_Principal *result;
606 if (domain == NULL) {
607 return NT_STATUS_REQUEST_NOT_ACCEPTED;
610 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
611 r->in.rids->rids, r->in.rids->num_rids,
612 &domain_name, &names, &types);
613 reset_cm_connection_on_error(domain, status);
614 if (!NT_STATUS_IS_OK(status)) {
618 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
620 result = talloc_array(p->mem_ctx, struct wbint_Principal,
621 r->in.rids->num_rids);
622 if (result == NULL) {
623 return NT_STATUS_NO_MEMORY;
626 for (i=0; i<r->in.rids->num_rids; i++) {
627 sid_compose(&result[i].sid, r->in.domain_sid,
628 r->in.rids->rids[i]);
629 result[i].type = types[i];
630 result[i].name = talloc_move(result, &names[i]);
635 r->out.names->num_principals = r->in.rids->num_rids;
636 r->out.names->principals = result;
640 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
641 struct wbint_CheckMachineAccount *r)
643 struct winbindd_domain *domain;
647 domain = wb_child_domain();
648 if (domain == NULL) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED;
653 invalidate_cm_connection(domain);
654 domain->conn.netlogon_force_reauth = true;
657 struct rpc_pipe_client *netlogon_pipe;
658 status = cm_connect_netlogon(domain, &netlogon_pipe);
661 /* There is a race condition between fetching the trust account
662 password and the periodic machine password change. So it's
663 possible that the trust account password has been changed on us.
664 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
666 #define MAX_RETRIES 3
668 if ((num_retries < MAX_RETRIES)
669 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
674 if (!NT_STATUS_IS_OK(status)) {
675 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
679 /* Pass back result code - zero for success, other values for
680 specific failures. */
682 DEBUG(3,("domain %s secret is %s\n", domain->name,
683 NT_STATUS_IS_OK(status) ? "good" : "bad"));
686 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
687 ("Checking the trust account password for domain %s returned %s\n",
688 domain->name, nt_errstr(status)));
693 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
694 struct wbint_ChangeMachineAccount *r)
696 struct messaging_context *msg_ctx = winbind_messaging_context();
697 struct winbindd_domain *domain;
699 struct rpc_pipe_client *netlogon_pipe;
701 domain = wb_child_domain();
702 if (domain == NULL) {
703 return NT_STATUS_REQUEST_NOT_ACCEPTED;
706 status = cm_connect_netlogon(domain, &netlogon_pipe);
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
712 status = trust_pw_change(domain->conn.netlogon_creds,
714 netlogon_pipe->binding_handle,
718 /* Pass back result code - zero for success, other values for
719 specific failures. */
721 DEBUG(3,("domain %s secret %s\n", domain->name,
722 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
725 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
726 ("Changing the trust account password for domain %s returned %s\n",
727 domain->name, nt_errstr(status)));
732 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
735 struct winbindd_domain *domain;
736 struct rpc_pipe_client *netlogon_pipe;
737 union netr_CONTROL_QUERY_INFORMATION info;
739 fstring logon_server;
740 struct dcerpc_binding_handle *b;
743 domain = wb_child_domain();
744 if (domain == NULL) {
745 return NT_STATUS_REQUEST_NOT_ACCEPTED;
749 status = cm_connect_netlogon(domain, &netlogon_pipe);
750 reset_cm_connection_on_error(domain, status);
751 if (!NT_STATUS_IS_OK(status)) {
752 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
757 b = netlogon_pipe->binding_handle;
759 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
760 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
761 if (*r->out.dcname == NULL) {
762 DEBUG(2, ("Could not allocate memory\n"));
763 return NT_STATUS_NO_MEMORY;
767 * This provokes a WERR_NOT_SUPPORTED error message. This is
768 * documented in the wspp docs. I could not get a successful
769 * call to work, but the main point here is testing that the
770 * netlogon pipe works.
772 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
773 logon_server, NETLOGON_CONTROL_QUERY,
776 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
777 DEBUG(10, ("Session might have expired. "
778 "Reconnect and retry once.\n"));
779 invalidate_cm_connection(domain);
784 reset_cm_connection_on_error(domain, status);
785 if (!NT_STATUS_IS_OK(status)) {
786 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
791 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
792 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
793 "WERR_NOT_SUPPORTED\n",
795 return werror_to_ntstatus(werr);
798 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
802 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
803 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
805 struct winbindd_domain *domain;
807 struct rpc_pipe_client *netlogon_pipe;
809 domain = wb_child_domain();
810 if (domain == NULL) {
811 return NT_STATUS_REQUEST_NOT_ACCEPTED;
814 status = cm_connect_netlogon(domain, &netlogon_pipe);
815 if (!NT_STATUS_IS_OK(status)) {
816 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
820 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
821 netlogon_pipe->binding_handle,
826 /* Pass back result code - zero for success, other values for
827 specific failures. */
829 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
830 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
833 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
834 ("Update of DNS records via RW DC %s returned %s\n",
835 domain->name, nt_errstr(status)));
840 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
841 struct winbind_SamLogon *r)
843 struct winbindd_domain *domain;
845 DATA_BLOB lm_response, nt_response;
846 domain = wb_child_domain();
847 if (domain == NULL) {
848 return NT_STATUS_REQUEST_NOT_ACCEPTED;
851 /* TODO: Handle interactive logons here */
852 if (r->in.validation_level != 3 ||
853 r->in.logon.network == NULL ||
854 (r->in.logon_level != NetlogonNetworkInformation
855 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
856 return NT_STATUS_REQUEST_NOT_ACCEPTED;
860 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
861 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
863 status = winbind_dual_SamLogon(domain, p->mem_ctx,
864 r->in.logon.network->identity_info.parameter_control,
865 r->in.logon.network->identity_info.account_name.string,
866 r->in.logon.network->identity_info.domain_name.string,
867 r->in.logon.network->identity_info.workstation.string,
868 r->in.logon.network->challenge,
869 lm_response, nt_response, &r->out.validation.sam3);
873 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
874 struct winbindd_domain *domain,
875 struct winbind_LogonControl *r)
878 struct rpc_pipe_client *netlogon_pipe = NULL;
879 struct netr_NETLOGON_INFO_2 *info2 = NULL;
880 WERROR check_result = WERR_INTERNAL_ERROR;
882 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
884 return WERR_NOT_ENOUGH_MEMORY;
887 if (domain->internal) {
888 check_result = WERR_OK;
893 * For now we just force a reconnect
895 * TODO: take care of the optional '\dcname'
897 invalidate_cm_connection(domain);
898 domain->conn.netlogon_force_reauth = true;
899 status = cm_connect_netlogon(domain, &netlogon_pipe);
900 reset_cm_connection_on_error(domain, status);
901 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
902 status = NT_STATUS_NO_LOGON_SERVERS;
904 if (!NT_STATUS_IS_OK(status)) {
905 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
906 __func__, domain->name, domain->alt_name,
909 * Here we return a top level error!
910 * This is different than TC_QUERY or TC_VERIFY.
912 return ntstatus_to_werror(status);
914 check_result = WERR_OK;
917 info2->pdc_connection_status = WERR_OK;
918 if (domain->dcname != NULL) {
919 info2->flags |= NETLOGON_HAS_IP;
920 info2->flags |= NETLOGON_HAS_TIMESERV;
921 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
923 if (info2->trusted_dc_name == NULL) {
924 return WERR_NOT_ENOUGH_MEMORY;
927 info2->trusted_dc_name = talloc_strdup(info2, "");
928 if (info2->trusted_dc_name == NULL) {
929 return WERR_NOT_ENOUGH_MEMORY;
932 info2->tc_connection_status = check_result;
934 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
935 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
936 "pdc_connection[%s] tc_connection[%s]\n",
937 __func__, domain->name, domain->alt_name,
939 win_errstr(info2->pdc_connection_status),
940 win_errstr(info2->tc_connection_status)));
943 r->out.query->info2 = info2;
945 DEBUG(5, ("%s: succeeded.\n", __func__));
949 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
950 struct winbindd_domain *domain,
951 struct winbind_LogonControl *r)
954 struct rpc_pipe_client *netlogon_pipe = NULL;
955 struct netr_NETLOGON_INFO_2 *info2 = NULL;
956 WERROR check_result = WERR_INTERNAL_ERROR;
958 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
960 return WERR_NOT_ENOUGH_MEMORY;
963 if (domain->internal) {
964 check_result = WERR_OK;
968 status = cm_connect_netlogon(domain, &netlogon_pipe);
969 reset_cm_connection_on_error(domain, status);
970 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
971 status = NT_STATUS_NO_LOGON_SERVERS;
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
976 check_result = ntstatus_to_werror(status);
979 check_result = WERR_OK;
982 info2->pdc_connection_status = WERR_OK;
983 if (domain->dcname != NULL) {
984 info2->flags |= NETLOGON_HAS_IP;
985 info2->flags |= NETLOGON_HAS_TIMESERV;
986 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
988 if (info2->trusted_dc_name == NULL) {
989 return WERR_NOT_ENOUGH_MEMORY;
992 info2->trusted_dc_name = talloc_strdup(info2, "");
993 if (info2->trusted_dc_name == NULL) {
994 return WERR_NOT_ENOUGH_MEMORY;
997 info2->tc_connection_status = check_result;
999 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1000 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1001 "pdc_connection[%s] tc_connection[%s]\n",
1002 __func__, domain->name, domain->alt_name,
1004 win_errstr(info2->pdc_connection_status),
1005 win_errstr(info2->tc_connection_status)));
1008 r->out.query->info2 = info2;
1010 DEBUG(5, ("%s: succeeded.\n", __func__));
1014 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1015 struct winbindd_domain *domain,
1016 struct winbind_LogonControl *r)
1018 TALLOC_CTX *frame = talloc_stackframe();
1021 struct lsa_String trusted_domain_name = {};
1022 struct lsa_StringLarge trusted_domain_name_l = {};
1023 struct rpc_pipe_client *local_lsa_pipe = NULL;
1024 struct policy_handle local_lsa_policy = {};
1025 struct dcerpc_binding_handle *local_lsa = NULL;
1026 struct rpc_pipe_client *netlogon_pipe = NULL;
1027 struct cli_credentials *creds = NULL;
1028 struct samr_Password *cur_nt_hash = NULL;
1029 uint32_t trust_attributes = 0;
1030 struct samr_Password new_owf_password = {};
1032 struct samr_Password old_owf_password = {};
1034 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1035 bool fetch_fti = false;
1036 struct lsa_ForestTrustInformation *new_fti = NULL;
1037 struct netr_TrustInfo *trust_info = NULL;
1038 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1039 struct dcerpc_binding_handle *b = NULL;
1040 WERROR check_result = WERR_INTERNAL_ERROR;
1041 WERROR verify_result = WERR_INTERNAL_ERROR;
1044 trusted_domain_name.string = domain->name;
1045 trusted_domain_name_l.string = domain->name;
1047 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1048 if (info2 == NULL) {
1050 return WERR_NOT_ENOUGH_MEMORY;
1053 if (domain->internal) {
1054 check_result = WERR_OK;
1058 status = pdb_get_trust_credentials(domain->name,
1062 if (NT_STATUS_IS_OK(status)) {
1063 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1067 if (!domain->primary) {
1068 union lsa_TrustedDomainInfo *tdi = NULL;
1070 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1072 if (!NT_STATUS_IS_OK(status)) {
1073 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1074 __location__, __func__, nt_errstr(status)));
1076 return WERR_INTERNAL_ERROR;
1078 local_lsa = local_lsa_pipe->binding_handle;
1080 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1082 &trusted_domain_name,
1083 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1085 if (!NT_STATUS_IS_OK(status)) {
1086 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1087 __location__, __func__, domain->name, nt_errstr(status)));
1089 return WERR_INTERNAL_ERROR;
1091 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1092 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1093 __location__, __func__, domain->name));
1095 return WERR_NO_SUCH_DOMAIN;
1097 if (!NT_STATUS_IS_OK(result)) {
1098 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1099 __location__, __func__, domain->name, nt_errstr(result)));
1101 return WERR_INTERNAL_ERROR;
1104 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1105 "returned no trusted domain information\n",
1106 __location__, __func__));
1108 return WERR_INTERNAL_ERROR;
1111 local_tdo = &tdi->info_ex;
1112 trust_attributes = local_tdo->trust_attributes;
1115 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1116 struct lsa_ForestTrustInformation *old_fti = NULL;
1118 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1120 &trusted_domain_name,
1121 LSA_FOREST_TRUST_DOMAIN_INFO,
1123 if (!NT_STATUS_IS_OK(status)) {
1124 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1125 __location__, __func__, domain->name, nt_errstr(status)));
1127 return WERR_INTERNAL_ERROR;
1129 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1130 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1131 __func__, domain->name));
1134 result = NT_STATUS_OK;
1136 if (!NT_STATUS_IS_OK(result)) {
1137 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1138 __location__, __func__, domain->name, nt_errstr(result)));
1140 return WERR_INTERNAL_ERROR;
1143 TALLOC_FREE(old_fti);
1147 status = cm_connect_netlogon(domain, &netlogon_pipe);
1148 reset_cm_connection_on_error(domain, status);
1149 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1150 status = NT_STATUS_NO_LOGON_SERVERS;
1152 if (!NT_STATUS_IS_OK(status)) {
1153 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1154 nt_errstr(status)));
1155 check_result = ntstatus_to_werror(status);
1158 check_result = WERR_OK;
1159 b = netlogon_pipe->binding_handle;
1161 if (cur_nt_hash == NULL) {
1162 verify_result = WERR_NO_TRUST_LSA_SECRET;
1167 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1170 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1171 status = NT_STATUS_NOT_SUPPORTED;
1173 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1175 status = NT_STATUS_OK;
1177 if (!NT_STATUS_IS_OK(status)) {
1178 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1179 invalidate_cm_connection(domain);
1183 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1185 domain->name, nt_errstr(status)));
1186 check_result = ntstatus_to_werror(status);
1191 if (new_fti != NULL) {
1192 struct lsa_ForestTrustInformation old_fti = {};
1193 struct lsa_ForestTrustInformation *merged_fti = NULL;
1194 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1196 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1199 if (!NT_STATUS_IS_OK(status)) {
1200 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1201 __location__, __func__,
1202 domain->name, nt_errstr(status)));
1204 return ntstatus_to_werror(status);
1207 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1209 &trusted_domain_name_l,
1210 LSA_FOREST_TRUST_DOMAIN_INFO,
1212 0, /* check_only=0 => store it! */
1215 if (!NT_STATUS_IS_OK(status)) {
1216 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1217 __location__, __func__, domain->name, nt_errstr(status)));
1219 return WERR_INTERNAL_ERROR;
1221 if (!NT_STATUS_IS_OK(result)) {
1222 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1223 __location__, __func__, domain->name, nt_errstr(result)));
1225 return ntstatus_to_werror(result);
1229 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1234 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1235 status = NT_STATUS_NOT_SUPPORTED;
1237 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1238 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1239 nt_errstr(status)));
1240 verify_result = WERR_OK;
1243 if (!NT_STATUS_IS_OK(status)) {
1244 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1245 invalidate_cm_connection(domain);
1249 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1250 nt_errstr(status)));
1252 if (!dcerpc_binding_handle_is_connected(b)) {
1253 check_result = ntstatus_to_werror(status);
1256 verify_result = ntstatus_to_werror(status);
1261 if (trust_info != NULL && trust_info->count >= 1) {
1262 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1264 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1265 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1270 cmp_new = memcmp(new_owf_password.hash,
1272 sizeof(cur_nt_hash->hash));
1273 cmp_old = memcmp(old_owf_password.hash,
1275 sizeof(cur_nt_hash->hash));
1276 if (cmp_new != 0 && cmp_old != 0) {
1277 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1278 "any password known to dcname[%s]\n",
1279 __func__, domain->name, domain->alt_name,
1281 verify_result = WERR_WRONG_PASSWORD;
1286 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1287 "against the old password known to dcname[%s]\n",
1288 __func__, domain->name, domain->alt_name,
1292 verify_result = WERR_OK;
1296 verify_result = check_result;
1298 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1299 info2->pdc_connection_status = verify_result;
1300 if (domain->dcname != NULL) {
1301 info2->flags |= NETLOGON_HAS_IP;
1302 info2->flags |= NETLOGON_HAS_TIMESERV;
1303 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1305 if (info2->trusted_dc_name == NULL) {
1307 return WERR_NOT_ENOUGH_MEMORY;
1310 info2->trusted_dc_name = talloc_strdup(info2, "");
1311 if (info2->trusted_dc_name == NULL) {
1313 return WERR_NOT_ENOUGH_MEMORY;
1316 info2->tc_connection_status = check_result;
1318 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1319 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1320 "pdc_connection[%s] tc_connection[%s]\n",
1321 __func__, domain->name, domain->alt_name,
1323 win_errstr(info2->pdc_connection_status),
1324 win_errstr(info2->tc_connection_status)));
1327 r->out.query->info2 = info2;
1329 DEBUG(5, ("%s: succeeded.\n", __func__));
1334 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1335 struct winbindd_domain *domain,
1336 struct winbind_LogonControl *r)
1338 struct messaging_context *msg_ctx = winbind_messaging_context();
1340 struct rpc_pipe_client *netlogon_pipe;
1341 struct cli_credentials *creds = NULL;
1342 struct samr_Password *cur_nt_hash = NULL;
1343 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1344 struct dcerpc_binding_handle *b;
1345 WERROR change_result = WERR_OK;
1348 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1349 if (info1 == NULL) {
1350 return WERR_NOT_ENOUGH_MEMORY;
1353 if (domain->internal) {
1354 return WERR_NOT_SUPPORTED;
1357 status = pdb_get_trust_credentials(domain->name,
1361 if (NT_STATUS_IS_OK(status)) {
1362 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1367 status = cm_connect_netlogon(domain, &netlogon_pipe);
1368 reset_cm_connection_on_error(domain, status);
1369 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1370 status = NT_STATUS_NO_LOGON_SERVERS;
1372 if (!NT_STATUS_IS_OK(status)) {
1373 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1374 __func__, domain->name, domain->alt_name,
1375 nt_errstr(status)));
1377 * Here we return a top level error!
1378 * This is different than TC_QUERY or TC_VERIFY.
1380 return ntstatus_to_werror(status);
1382 b = netlogon_pipe->binding_handle;
1384 if (cur_nt_hash == NULL) {
1385 change_result = WERR_NO_TRUST_LSA_SECRET;
1388 TALLOC_FREE(cur_nt_hash);
1390 status = trust_pw_change(domain->conn.netlogon_creds,
1391 msg_ctx, b, domain->name,
1393 if (!NT_STATUS_IS_OK(status)) {
1394 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1395 invalidate_cm_connection(domain);
1400 DEBUG(1, ("trust_pw_change(%s): %s\n",
1401 domain->name, nt_errstr(status)));
1403 change_result = ntstatus_to_werror(status);
1407 change_result = WERR_OK;
1410 info1->pdc_connection_status = change_result;
1412 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1413 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1414 "pdc_connection[%s]\n",
1415 __func__, domain->name, domain->alt_name,
1417 win_errstr(info1->pdc_connection_status)));
1420 r->out.query->info1 = info1;
1422 DEBUG(5, ("%s: succeeded.\n", __func__));
1426 WERROR _winbind_LogonControl(struct pipes_struct *p,
1427 struct winbind_LogonControl *r)
1429 struct winbindd_domain *domain;
1431 domain = wb_child_domain();
1432 if (domain == NULL) {
1433 return WERR_NO_SUCH_DOMAIN;
1436 switch (r->in.function_code) {
1437 case NETLOGON_CONTROL_REDISCOVER:
1438 if (r->in.level != 2) {
1439 return WERR_INVALID_PARAMETER;
1441 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1442 case NETLOGON_CONTROL_TC_QUERY:
1443 if (r->in.level != 2) {
1444 return WERR_INVALID_PARAMETER;
1446 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1447 case NETLOGON_CONTROL_TC_VERIFY:
1448 if (r->in.level != 2) {
1449 return WERR_INVALID_PARAMETER;
1451 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1452 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1453 if (r->in.level != 1) {
1454 return WERR_INVALID_PARAMETER;
1456 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1461 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1462 __func__, r->in.function_code));
1463 return WERR_NOT_SUPPORTED;
1466 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1467 struct winbind_GetForestTrustInformation *r)
1469 TALLOC_CTX *frame = talloc_stackframe();
1470 NTSTATUS status, result;
1471 struct winbindd_domain *domain;
1472 struct rpc_pipe_client *netlogon_pipe;
1473 struct dcerpc_binding_handle *b;
1475 struct lsa_String trusted_domain_name = {};
1476 struct lsa_StringLarge trusted_domain_name_l = {};
1477 union lsa_TrustedDomainInfo *tdi = NULL;
1478 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1479 struct lsa_ForestTrustInformation _old_fti = {};
1480 struct lsa_ForestTrustInformation *old_fti = NULL;
1481 struct lsa_ForestTrustInformation *new_fti = NULL;
1482 struct lsa_ForestTrustInformation *merged_fti = NULL;
1483 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1484 bool update_fti = false;
1485 struct rpc_pipe_client *local_lsa_pipe;
1486 struct policy_handle local_lsa_policy;
1487 struct dcerpc_binding_handle *local_lsa = NULL;
1489 domain = wb_child_domain();
1490 if (domain == NULL) {
1492 return WERR_NO_SUCH_DOMAIN;
1496 * checking for domain->internal and domain->primary
1497 * makes sure we only do some work when running as DC.
1500 if (domain->internal) {
1502 return WERR_NO_SUCH_DOMAIN;
1505 if (domain->primary) {
1507 return WERR_NO_SUCH_DOMAIN;
1510 trusted_domain_name.string = domain->name;
1511 trusted_domain_name_l.string = domain->name;
1513 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1515 if (!NT_STATUS_IS_OK(status)) {
1516 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1517 __location__, __func__, nt_errstr(status)));
1519 return WERR_INTERNAL_ERROR;
1521 local_lsa = local_lsa_pipe->binding_handle;
1523 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1525 &trusted_domain_name,
1526 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1528 if (!NT_STATUS_IS_OK(status)) {
1529 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1530 __location__, __func__, domain->name, nt_errstr(status)));
1532 return WERR_INTERNAL_ERROR;
1534 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1535 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1536 __location__, __func__, domain->name));
1538 return WERR_NO_SUCH_DOMAIN;
1540 if (!NT_STATUS_IS_OK(result)) {
1541 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1542 __location__, __func__, domain->name, nt_errstr(result)));
1544 return WERR_INTERNAL_ERROR;
1547 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1548 "returned no trusted domain information\n",
1549 __location__, __func__));
1551 return WERR_INTERNAL_ERROR;
1554 tdo = &tdi->info_ex;
1556 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1557 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1558 __func__, tdo->netbios_name.string,
1559 tdo->domain_name.string,
1560 (unsigned)tdo->trust_attributes));
1562 return WERR_NO_SUCH_DOMAIN;
1565 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1567 return WERR_INVALID_FLAGS;
1571 status = cm_connect_netlogon(domain, &netlogon_pipe);
1572 reset_cm_connection_on_error(domain, status);
1573 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1574 status = NT_STATUS_NO_LOGON_SERVERS;
1576 if (!NT_STATUS_IS_OK(status)) {
1577 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1578 nt_errstr(status)));
1580 return ntstatus_to_werror(status);
1582 b = netlogon_pipe->binding_handle;
1584 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1587 if (!NT_STATUS_IS_OK(status)) {
1588 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1589 invalidate_cm_connection(domain);
1593 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1594 domain->name, nt_errstr(status)));
1596 return ntstatus_to_werror(status);
1599 *r->out.forest_trust_info = new_fti;
1601 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1605 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1607 &trusted_domain_name,
1608 LSA_FOREST_TRUST_DOMAIN_INFO,
1610 if (!NT_STATUS_IS_OK(status)) {
1611 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1612 __location__, __func__, domain->name, nt_errstr(status)));
1614 return WERR_INTERNAL_ERROR;
1616 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1617 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1618 __func__, domain->name));
1620 old_fti = &_old_fti;
1621 result = NT_STATUS_OK;
1623 if (!NT_STATUS_IS_OK(result)) {
1624 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1625 __location__, __func__, domain->name, nt_errstr(result)));
1627 return WERR_INTERNAL_ERROR;
1630 if (old_fti == NULL) {
1631 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1632 "returned success without returning forest trust information\n",
1633 __location__, __func__));
1635 return WERR_INTERNAL_ERROR;
1642 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1644 if (!NT_STATUS_IS_OK(status)) {
1645 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1646 __location__, __func__, domain->name, nt_errstr(status)));
1648 return ntstatus_to_werror(status);
1651 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1653 &trusted_domain_name_l,
1654 LSA_FOREST_TRUST_DOMAIN_INFO,
1656 0, /* check_only=0 => store it! */
1659 if (!NT_STATUS_IS_OK(status)) {
1660 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1661 __location__, __func__, domain->name, nt_errstr(status)));
1663 return WERR_INTERNAL_ERROR;
1665 if (!NT_STATUS_IS_OK(result)) {
1666 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1667 __location__, __func__, domain->name, nt_errstr(result)));
1669 return ntstatus_to_werror(result);
1673 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));