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 DBG_DEBUG("id %"PRIu32" is out of range "
194 "%"PRIu32"-%"PRIu32" for domain %s\n",
195 m->xid.id, dom->low_id, dom->high_id,
197 m->status = ID_UNMAPPED;
200 if (m->status == ID_MAPPED) {
203 ids[i].xid.id = UINT32_MAX;
204 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
210 status = NT_STATUS_NO_MEMORY;
212 TALLOC_FREE(id_map_ptrs);
216 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
217 struct wbint_UnixIDs2Sids *r)
219 struct id_map **maps;
223 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
225 return NT_STATUS_NO_MEMORY;
228 for (i=0; i<r->in.num_ids; i++) {
229 maps[i]->status = ID_UNKNOWN;
230 maps[i]->xid = r->in.xids[i];
233 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name);
234 if (!NT_STATUS_IS_OK(status)) {
239 for (i=0; i<r->in.num_ids; i++) {
240 r->out.xids[i] = maps[i]->xid;
241 sid_copy(&r->out.sids[i], maps[i]->sid);
249 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
254 status = idmap_allocate_uid(&xid);
255 if (!NT_STATUS_IS_OK(status)) {
258 *r->out.uid = xid.id;
262 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
267 status = idmap_allocate_gid(&xid);
268 if (!NT_STATUS_IS_OK(status)) {
271 *r->out.gid = xid.id;
275 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
277 struct idmap_domain *domain;
280 domain = idmap_find_domain(r->in.info->domain_name);
281 if ((domain == NULL) || (domain->query_user == NULL)) {
282 return NT_STATUS_REQUEST_NOT_ACCEPTED;
285 status = domain->query_user(domain, r->in.info);
289 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
290 struct wbint_LookupUserAliases *r)
292 struct winbindd_domain *domain = wb_child_domain();
295 if (domain == NULL) {
296 return NT_STATUS_REQUEST_NOT_ACCEPTED;
299 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
300 r->in.sids->num_sids,
302 &r->out.rids->num_rids,
304 reset_cm_connection_on_error(domain, status);
308 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
309 struct wbint_LookupUserGroups *r)
311 struct winbindd_domain *domain = wb_child_domain();
314 if (domain == NULL) {
315 return NT_STATUS_REQUEST_NOT_ACCEPTED;
318 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
319 &r->out.sids->num_sids,
321 reset_cm_connection_on_error(domain, status);
325 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
326 struct wbint_QuerySequenceNumber *r)
328 struct winbindd_domain *domain = wb_child_domain();
331 if (domain == NULL) {
332 return NT_STATUS_REQUEST_NOT_ACCEPTED;
335 status = wb_cache_sequence_number(domain, r->out.sequence);
336 reset_cm_connection_on_error(domain, status);
340 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
341 struct wbint_LookupGroupMembers *r)
343 struct winbindd_domain *domain = wb_child_domain();
344 uint32_t i, num_names;
345 struct dom_sid *sid_mem;
347 uint32_t *name_types;
350 if (domain == NULL) {
351 return NT_STATUS_REQUEST_NOT_ACCEPTED;
354 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
355 r->in.type, &num_names, &sid_mem,
356 &names, &name_types);
357 reset_cm_connection_on_error(domain, status);
358 if (!NT_STATUS_IS_OK(status)) {
362 r->out.members->num_principals = num_names;
363 r->out.members->principals = talloc_array(
364 r->out.members, struct wbint_Principal, num_names);
365 if (r->out.members->principals == NULL) {
366 return NT_STATUS_NO_MEMORY;
369 for (i=0; i<num_names; i++) {
370 struct wbint_Principal *m = &r->out.members->principals[i];
371 sid_copy(&m->sid, &sid_mem[i]);
372 m->name = talloc_move(r->out.members->principals, &names[i]);
373 m->type = (enum lsa_SidType)name_types[i];
379 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
380 struct wbint_QueryGroupList *r)
382 struct winbindd_domain *domain = wb_child_domain();
384 uint32_t num_local_groups = 0;
385 struct wb_acct_info *local_groups = NULL;
386 uint32_t num_dom_groups = 0;
387 struct wb_acct_info *dom_groups = NULL;
389 uint64_t num_total = 0;
390 struct wbint_Principal *result;
392 bool include_local_groups = false;
394 if (domain == NULL) {
395 return NT_STATUS_REQUEST_NOT_ACCEPTED;
398 switch (lp_server_role()) {
399 case ROLE_ACTIVE_DIRECTORY_DC:
400 if (domain->internal) {
402 * we want to include local groups
403 * for BUILTIN and WORKGROUP
405 include_local_groups = true;
410 * We might include local groups in more
411 * setups later, but that requires more work
417 if (include_local_groups) {
418 status = wb_cache_enum_local_groups(domain, talloc_tos(),
421 reset_cm_connection_on_error(domain, status);
422 if (!NT_STATUS_IS_OK(status)) {
427 status = wb_cache_enum_dom_groups(domain, talloc_tos(),
430 reset_cm_connection_on_error(domain, status);
431 if (!NT_STATUS_IS_OK(status)) {
435 num_total = num_local_groups + num_dom_groups;
436 if (num_total > UINT32_MAX) {
437 return NT_STATUS_INTERNAL_ERROR;
440 result = talloc_array(r->out.groups, struct wbint_Principal,
442 if (result == NULL) {
443 return NT_STATUS_NO_MEMORY;
446 for (i = 0; i < num_local_groups; i++) {
447 struct wb_acct_info *lg = &local_groups[i];
448 struct wbint_Principal *rg = &result[ti++];
450 sid_compose(&rg->sid, &domain->sid, lg->rid);
451 rg->type = SID_NAME_ALIAS;
452 rg->name = talloc_strdup(result, lg->acct_name);
453 if (rg->name == NULL) {
455 TALLOC_FREE(dom_groups);
456 TALLOC_FREE(local_groups);
457 return NT_STATUS_NO_MEMORY;
460 num_local_groups = 0;
461 TALLOC_FREE(local_groups);
463 for (i = 0; i < num_dom_groups; i++) {
464 struct wb_acct_info *dg = &dom_groups[i];
465 struct wbint_Principal *rg = &result[ti++];
467 sid_compose(&rg->sid, &domain->sid, dg->rid);
468 rg->type = SID_NAME_DOM_GRP;
469 rg->name = talloc_strdup(result, dg->acct_name);
470 if (rg->name == NULL) {
472 TALLOC_FREE(dom_groups);
473 TALLOC_FREE(local_groups);
474 return NT_STATUS_NO_MEMORY;
478 TALLOC_FREE(dom_groups);
480 r->out.groups->num_principals = ti;
481 r->out.groups->principals = result;
486 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
487 struct wbint_QueryUserRidList *r)
489 struct winbindd_domain *domain = wb_child_domain();
492 if (domain == NULL) {
493 return NT_STATUS_REQUEST_NOT_ACCEPTED;
497 * Right now this is overkill. We should add a backend call
498 * just querying the rids.
501 status = wb_cache_query_user_list(domain, p->mem_ctx,
503 reset_cm_connection_on_error(domain, status);
505 if (!NT_STATUS_IS_OK(status)) {
509 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
514 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
516 struct winbindd_domain *domain = wb_child_domain();
517 struct rpc_pipe_client *netlogon_pipe;
518 struct netr_DsRGetDCNameInfo *dc_info;
521 unsigned int orig_timeout;
522 struct dcerpc_binding_handle *b;
524 if (domain == NULL) {
525 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
526 r->in.domain_name, r->in.domain_guid,
527 r->in.site_name ? r->in.site_name : "",
532 status = cm_connect_netlogon(domain, &netlogon_pipe);
534 reset_cm_connection_on_error(domain, status);
535 if (!NT_STATUS_IS_OK(status)) {
536 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
540 b = netlogon_pipe->binding_handle;
542 /* This call can take a long time - allow the server to time out.
543 35 seconds should do it. */
545 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
547 if (domain->active_directory) {
548 status = dcerpc_netr_DsRGetDCName(b,
549 p->mem_ctx, domain->dcname,
550 r->in.domain_name, NULL, r->in.domain_guid,
551 r->in.flags, r->out.dc_info, &werr);
552 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
555 if (reset_cm_connection_on_error(domain, status)) {
557 status = cm_connect_netlogon(domain, &netlogon_pipe);
559 reset_cm_connection_on_error(domain, status);
560 if (!NT_STATUS_IS_OK(status)) {
561 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
565 b = netlogon_pipe->binding_handle;
567 /* This call can take a long time - allow the server to time out.
568 35 seconds should do it. */
570 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
575 * Fallback to less capable methods
578 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
579 if (dc_info == NULL) {
580 status = NT_STATUS_NO_MEMORY;
584 if (r->in.flags & DS_PDC_REQUIRED) {
585 status = dcerpc_netr_GetDcName(b,
586 p->mem_ctx, domain->dcname,
587 r->in.domain_name, &dc_info->dc_unc, &werr);
589 status = dcerpc_netr_GetAnyDCName(b,
590 p->mem_ctx, domain->dcname,
591 r->in.domain_name, &dc_info->dc_unc, &werr);
594 reset_cm_connection_on_error(domain, status);
595 if (!NT_STATUS_IS_OK(status)) {
596 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
600 if (!W_ERROR_IS_OK(werr)) {
601 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
603 status = werror_to_ntstatus(werr);
607 *r->out.dc_info = dc_info;
608 status = NT_STATUS_OK;
611 /* And restore our original timeout. */
612 rpccli_set_timeout(netlogon_pipe, orig_timeout);
617 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
619 struct winbindd_domain *domain = wb_child_domain();
622 enum lsa_SidType *types;
623 struct wbint_Principal *result;
627 if (domain == NULL) {
628 return NT_STATUS_REQUEST_NOT_ACCEPTED;
631 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
632 r->in.rids->rids, r->in.rids->num_rids,
633 &domain_name, &names, &types);
634 reset_cm_connection_on_error(domain, status);
635 if (!NT_STATUS_IS_OK(status)) {
639 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
641 result = talloc_array(p->mem_ctx, struct wbint_Principal,
642 r->in.rids->num_rids);
643 if (result == NULL) {
644 return NT_STATUS_NO_MEMORY;
647 for (i=0; i<r->in.rids->num_rids; i++) {
648 sid_compose(&result[i].sid, r->in.domain_sid,
649 r->in.rids->rids[i]);
650 result[i].type = types[i];
651 result[i].name = talloc_move(result, &names[i]);
656 r->out.names->num_principals = r->in.rids->num_rids;
657 r->out.names->principals = result;
661 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
662 struct wbint_CheckMachineAccount *r)
664 struct winbindd_domain *domain;
668 domain = wb_child_domain();
669 if (domain == NULL) {
670 return NT_STATUS_REQUEST_NOT_ACCEPTED;
674 invalidate_cm_connection(domain);
675 domain->conn.netlogon_force_reauth = true;
678 struct rpc_pipe_client *netlogon_pipe;
679 status = cm_connect_netlogon(domain, &netlogon_pipe);
682 /* There is a race condition between fetching the trust account
683 password and the periodic machine password change. So it's
684 possible that the trust account password has been changed on us.
685 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
687 #define MAX_RETRIES 3
689 if ((num_retries < MAX_RETRIES)
690 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
695 if (!NT_STATUS_IS_OK(status)) {
696 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
700 /* Pass back result code - zero for success, other values for
701 specific failures. */
703 DEBUG(3,("domain %s secret is %s\n", domain->name,
704 NT_STATUS_IS_OK(status) ? "good" : "bad"));
707 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
708 ("Checking the trust account password for domain %s returned %s\n",
709 domain->name, nt_errstr(status)));
714 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
715 struct wbint_ChangeMachineAccount *r)
717 struct messaging_context *msg_ctx = winbind_messaging_context();
718 struct winbindd_domain *domain;
720 struct rpc_pipe_client *netlogon_pipe;
722 domain = wb_child_domain();
723 if (domain == NULL) {
724 return NT_STATUS_REQUEST_NOT_ACCEPTED;
727 status = cm_connect_netlogon(domain, &netlogon_pipe);
728 if (!NT_STATUS_IS_OK(status)) {
729 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
733 status = trust_pw_change(domain->conn.netlogon_creds,
735 netlogon_pipe->binding_handle,
739 /* Pass back result code - zero for success, other values for
740 specific failures. */
742 DEBUG(3,("domain %s secret %s\n", domain->name,
743 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
746 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
747 ("Changing the trust account password for domain %s returned %s\n",
748 domain->name, nt_errstr(status)));
753 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
756 struct winbindd_domain *domain;
757 struct rpc_pipe_client *netlogon_pipe;
758 union netr_CONTROL_QUERY_INFORMATION info;
760 fstring logon_server;
761 struct dcerpc_binding_handle *b;
764 domain = wb_child_domain();
765 if (domain == NULL) {
766 return NT_STATUS_REQUEST_NOT_ACCEPTED;
770 status = cm_connect_netlogon(domain, &netlogon_pipe);
771 reset_cm_connection_on_error(domain, status);
772 if (!NT_STATUS_IS_OK(status)) {
773 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
778 b = netlogon_pipe->binding_handle;
780 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
781 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
782 if (*r->out.dcname == NULL) {
783 DEBUG(2, ("Could not allocate memory\n"));
784 return NT_STATUS_NO_MEMORY;
788 * This provokes a WERR_NOT_SUPPORTED error message. This is
789 * documented in the wspp docs. I could not get a successful
790 * call to work, but the main point here is testing that the
791 * netlogon pipe works.
793 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
794 logon_server, NETLOGON_CONTROL_QUERY,
797 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
798 DEBUG(10, ("Session might have expired. "
799 "Reconnect and retry once.\n"));
800 invalidate_cm_connection(domain);
805 reset_cm_connection_on_error(domain, status);
806 if (!NT_STATUS_IS_OK(status)) {
807 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
812 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
813 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
814 "WERR_NOT_SUPPORTED\n",
816 return werror_to_ntstatus(werr);
819 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
823 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
824 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
826 struct winbindd_domain *domain;
828 struct rpc_pipe_client *netlogon_pipe;
830 domain = wb_child_domain();
831 if (domain == NULL) {
832 return NT_STATUS_REQUEST_NOT_ACCEPTED;
835 status = cm_connect_netlogon(domain, &netlogon_pipe);
836 if (!NT_STATUS_IS_OK(status)) {
837 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
841 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
842 netlogon_pipe->binding_handle,
847 /* Pass back result code - zero for success, other values for
848 specific failures. */
850 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
851 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
854 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
855 ("Update of DNS records via RW DC %s returned %s\n",
856 domain->name, nt_errstr(status)));
861 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
862 struct winbind_SamLogon *r)
864 struct winbindd_domain *domain;
866 DATA_BLOB lm_response, nt_response;
869 domain = wb_child_domain();
870 if (domain == NULL) {
871 return NT_STATUS_REQUEST_NOT_ACCEPTED;
874 /* TODO: Handle interactive logons here */
875 if (r->in.validation_level != 3 ||
876 r->in.logon.network == NULL ||
877 (r->in.logon_level != NetlogonNetworkInformation
878 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
879 return NT_STATUS_REQUEST_NOT_ACCEPTED;
883 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
884 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
886 status = winbind_dual_SamLogon(domain, p->mem_ctx,
887 r->in.logon.network->identity_info.parameter_control,
888 r->in.logon.network->identity_info.account_name.string,
889 r->in.logon.network->identity_info.domain_name.string,
890 r->in.logon.network->identity_info.workstation.string,
891 r->in.logon.network->challenge,
892 lm_response, nt_response,
893 &r->out.authoritative,
896 &r->out.validation.sam3);
900 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
901 struct winbindd_domain *domain,
902 struct winbind_LogonControl *r)
905 struct rpc_pipe_client *netlogon_pipe = NULL;
906 struct netr_NETLOGON_INFO_2 *info2 = NULL;
907 WERROR check_result = WERR_INTERNAL_ERROR;
909 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
911 return WERR_NOT_ENOUGH_MEMORY;
914 if (domain->internal) {
915 check_result = WERR_OK;
920 * For now we just force a reconnect
922 * TODO: take care of the optional '\dcname'
924 invalidate_cm_connection(domain);
925 domain->conn.netlogon_force_reauth = true;
926 status = cm_connect_netlogon(domain, &netlogon_pipe);
927 reset_cm_connection_on_error(domain, status);
928 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
929 status = NT_STATUS_NO_LOGON_SERVERS;
931 if (!NT_STATUS_IS_OK(status)) {
932 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
933 __func__, domain->name, domain->alt_name,
936 * Here we return a top level error!
937 * This is different than TC_QUERY or TC_VERIFY.
939 return ntstatus_to_werror(status);
941 check_result = WERR_OK;
944 info2->pdc_connection_status = WERR_OK;
945 if (domain->dcname != NULL) {
946 info2->flags |= NETLOGON_HAS_IP;
947 info2->flags |= NETLOGON_HAS_TIMESERV;
948 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
950 if (info2->trusted_dc_name == NULL) {
951 return WERR_NOT_ENOUGH_MEMORY;
954 info2->trusted_dc_name = talloc_strdup(info2, "");
955 if (info2->trusted_dc_name == NULL) {
956 return WERR_NOT_ENOUGH_MEMORY;
959 info2->tc_connection_status = check_result;
961 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
962 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
963 "pdc_connection[%s] tc_connection[%s]\n",
964 __func__, domain->name, domain->alt_name,
966 win_errstr(info2->pdc_connection_status),
967 win_errstr(info2->tc_connection_status)));
970 r->out.query->info2 = info2;
972 DEBUG(5, ("%s: succeeded.\n", __func__));
976 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
977 struct winbindd_domain *domain,
978 struct winbind_LogonControl *r)
981 struct rpc_pipe_client *netlogon_pipe = NULL;
982 struct netr_NETLOGON_INFO_2 *info2 = NULL;
983 WERROR check_result = WERR_INTERNAL_ERROR;
985 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
987 return WERR_NOT_ENOUGH_MEMORY;
990 if (domain->internal) {
991 check_result = WERR_OK;
995 status = cm_connect_netlogon(domain, &netlogon_pipe);
996 reset_cm_connection_on_error(domain, status);
997 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
998 status = NT_STATUS_NO_LOGON_SERVERS;
1000 if (!NT_STATUS_IS_OK(status)) {
1001 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1002 nt_errstr(status)));
1003 check_result = ntstatus_to_werror(status);
1006 check_result = WERR_OK;
1009 info2->pdc_connection_status = WERR_OK;
1010 if (domain->dcname != NULL) {
1011 info2->flags |= NETLOGON_HAS_IP;
1012 info2->flags |= NETLOGON_HAS_TIMESERV;
1013 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1015 if (info2->trusted_dc_name == NULL) {
1016 return WERR_NOT_ENOUGH_MEMORY;
1019 info2->trusted_dc_name = talloc_strdup(info2, "");
1020 if (info2->trusted_dc_name == NULL) {
1021 return WERR_NOT_ENOUGH_MEMORY;
1024 info2->tc_connection_status = check_result;
1026 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1027 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1028 "pdc_connection[%s] tc_connection[%s]\n",
1029 __func__, domain->name, domain->alt_name,
1031 win_errstr(info2->pdc_connection_status),
1032 win_errstr(info2->tc_connection_status)));
1035 r->out.query->info2 = info2;
1037 DEBUG(5, ("%s: succeeded.\n", __func__));
1041 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1042 struct winbindd_domain *domain,
1043 struct winbind_LogonControl *r)
1045 TALLOC_CTX *frame = talloc_stackframe();
1048 struct lsa_String trusted_domain_name = {};
1049 struct lsa_StringLarge trusted_domain_name_l = {};
1050 struct rpc_pipe_client *local_lsa_pipe = NULL;
1051 struct policy_handle local_lsa_policy = {};
1052 struct dcerpc_binding_handle *local_lsa = NULL;
1053 struct rpc_pipe_client *netlogon_pipe = NULL;
1054 struct cli_credentials *creds = NULL;
1055 struct samr_Password *cur_nt_hash = NULL;
1056 uint32_t trust_attributes = 0;
1057 struct samr_Password new_owf_password = {};
1059 struct samr_Password old_owf_password = {};
1061 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1062 bool fetch_fti = false;
1063 struct lsa_ForestTrustInformation *new_fti = NULL;
1064 struct netr_TrustInfo *trust_info = NULL;
1065 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1066 struct dcerpc_binding_handle *b = NULL;
1067 WERROR check_result = WERR_INTERNAL_ERROR;
1068 WERROR verify_result = WERR_INTERNAL_ERROR;
1071 trusted_domain_name.string = domain->name;
1072 trusted_domain_name_l.string = domain->name;
1074 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1075 if (info2 == NULL) {
1077 return WERR_NOT_ENOUGH_MEMORY;
1080 if (domain->internal) {
1081 check_result = WERR_OK;
1085 status = pdb_get_trust_credentials(domain->name,
1089 if (NT_STATUS_IS_OK(status)) {
1090 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1094 if (!domain->primary) {
1095 union lsa_TrustedDomainInfo *tdi = NULL;
1097 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1099 if (!NT_STATUS_IS_OK(status)) {
1100 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1101 __location__, __func__, nt_errstr(status)));
1103 return WERR_INTERNAL_ERROR;
1105 local_lsa = local_lsa_pipe->binding_handle;
1107 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1109 &trusted_domain_name,
1110 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1112 if (!NT_STATUS_IS_OK(status)) {
1113 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1114 __location__, __func__, domain->name, nt_errstr(status)));
1116 return WERR_INTERNAL_ERROR;
1118 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1119 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1120 __location__, __func__, domain->name));
1122 return WERR_NO_SUCH_DOMAIN;
1124 if (!NT_STATUS_IS_OK(result)) {
1125 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1126 __location__, __func__, domain->name, nt_errstr(result)));
1128 return WERR_INTERNAL_ERROR;
1131 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1132 "returned no trusted domain information\n",
1133 __location__, __func__));
1135 return WERR_INTERNAL_ERROR;
1138 local_tdo = &tdi->info_ex;
1139 trust_attributes = local_tdo->trust_attributes;
1142 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1143 struct lsa_ForestTrustInformation *old_fti = NULL;
1145 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1147 &trusted_domain_name,
1148 LSA_FOREST_TRUST_DOMAIN_INFO,
1150 if (!NT_STATUS_IS_OK(status)) {
1151 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1152 __location__, __func__, domain->name, nt_errstr(status)));
1154 return WERR_INTERNAL_ERROR;
1156 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1157 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1158 __func__, domain->name));
1161 result = NT_STATUS_OK;
1163 if (!NT_STATUS_IS_OK(result)) {
1164 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1165 __location__, __func__, domain->name, nt_errstr(result)));
1167 return WERR_INTERNAL_ERROR;
1170 TALLOC_FREE(old_fti);
1174 status = cm_connect_netlogon(domain, &netlogon_pipe);
1175 reset_cm_connection_on_error(domain, status);
1176 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1177 status = NT_STATUS_NO_LOGON_SERVERS;
1179 if (!NT_STATUS_IS_OK(status)) {
1180 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1181 nt_errstr(status)));
1182 check_result = ntstatus_to_werror(status);
1185 check_result = WERR_OK;
1186 b = netlogon_pipe->binding_handle;
1188 if (cur_nt_hash == NULL) {
1189 verify_result = WERR_NO_TRUST_LSA_SECRET;
1194 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1197 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1198 status = NT_STATUS_NOT_SUPPORTED;
1200 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1202 status = NT_STATUS_OK;
1204 if (!NT_STATUS_IS_OK(status)) {
1205 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1206 invalidate_cm_connection(domain);
1210 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1212 domain->name, nt_errstr(status)));
1213 check_result = ntstatus_to_werror(status);
1218 if (new_fti != NULL) {
1219 struct lsa_ForestTrustInformation old_fti = {};
1220 struct lsa_ForestTrustInformation *merged_fti = NULL;
1221 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1223 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1226 if (!NT_STATUS_IS_OK(status)) {
1227 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1228 __location__, __func__,
1229 domain->name, nt_errstr(status)));
1231 return ntstatus_to_werror(status);
1234 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1236 &trusted_domain_name_l,
1237 LSA_FOREST_TRUST_DOMAIN_INFO,
1239 0, /* check_only=0 => store it! */
1242 if (!NT_STATUS_IS_OK(status)) {
1243 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1244 __location__, __func__, domain->name, nt_errstr(status)));
1246 return WERR_INTERNAL_ERROR;
1248 if (!NT_STATUS_IS_OK(result)) {
1249 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1250 __location__, __func__, domain->name, nt_errstr(result)));
1252 return ntstatus_to_werror(result);
1256 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1261 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1262 status = NT_STATUS_NOT_SUPPORTED;
1264 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1265 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1266 nt_errstr(status)));
1267 verify_result = WERR_OK;
1270 if (!NT_STATUS_IS_OK(status)) {
1271 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1272 invalidate_cm_connection(domain);
1276 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1277 nt_errstr(status)));
1279 if (!dcerpc_binding_handle_is_connected(b)) {
1280 check_result = ntstatus_to_werror(status);
1283 verify_result = ntstatus_to_werror(status);
1288 if (trust_info != NULL && trust_info->count >= 1) {
1289 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1291 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1292 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1297 cmp_new = memcmp(new_owf_password.hash,
1299 sizeof(cur_nt_hash->hash));
1300 cmp_old = memcmp(old_owf_password.hash,
1302 sizeof(cur_nt_hash->hash));
1303 if (cmp_new != 0 && cmp_old != 0) {
1304 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1305 "any password known to dcname[%s]\n",
1306 __func__, domain->name, domain->alt_name,
1308 verify_result = WERR_WRONG_PASSWORD;
1313 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1314 "against the old password known to dcname[%s]\n",
1315 __func__, domain->name, domain->alt_name,
1319 verify_result = WERR_OK;
1323 verify_result = check_result;
1325 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1326 info2->pdc_connection_status = verify_result;
1327 if (domain->dcname != NULL) {
1328 info2->flags |= NETLOGON_HAS_IP;
1329 info2->flags |= NETLOGON_HAS_TIMESERV;
1330 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1332 if (info2->trusted_dc_name == NULL) {
1334 return WERR_NOT_ENOUGH_MEMORY;
1337 info2->trusted_dc_name = talloc_strdup(info2, "");
1338 if (info2->trusted_dc_name == NULL) {
1340 return WERR_NOT_ENOUGH_MEMORY;
1343 info2->tc_connection_status = check_result;
1345 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1346 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1347 "pdc_connection[%s] tc_connection[%s]\n",
1348 __func__, domain->name, domain->alt_name,
1350 win_errstr(info2->pdc_connection_status),
1351 win_errstr(info2->tc_connection_status)));
1354 r->out.query->info2 = info2;
1356 DEBUG(5, ("%s: succeeded.\n", __func__));
1361 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1362 struct winbindd_domain *domain,
1363 struct winbind_LogonControl *r)
1365 struct messaging_context *msg_ctx = winbind_messaging_context();
1367 struct rpc_pipe_client *netlogon_pipe;
1368 struct cli_credentials *creds = NULL;
1369 struct samr_Password *cur_nt_hash = NULL;
1370 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1371 struct dcerpc_binding_handle *b;
1372 WERROR change_result = WERR_OK;
1375 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1376 if (info1 == NULL) {
1377 return WERR_NOT_ENOUGH_MEMORY;
1380 if (domain->internal) {
1381 return WERR_NOT_SUPPORTED;
1384 status = pdb_get_trust_credentials(domain->name,
1388 if (NT_STATUS_IS_OK(status)) {
1389 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1394 status = cm_connect_netlogon(domain, &netlogon_pipe);
1395 reset_cm_connection_on_error(domain, status);
1396 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1397 status = NT_STATUS_NO_LOGON_SERVERS;
1399 if (!NT_STATUS_IS_OK(status)) {
1400 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1401 __func__, domain->name, domain->alt_name,
1402 nt_errstr(status)));
1404 * Here we return a top level error!
1405 * This is different than TC_QUERY or TC_VERIFY.
1407 return ntstatus_to_werror(status);
1409 b = netlogon_pipe->binding_handle;
1411 if (cur_nt_hash == NULL) {
1412 change_result = WERR_NO_TRUST_LSA_SECRET;
1415 TALLOC_FREE(cur_nt_hash);
1417 status = trust_pw_change(domain->conn.netlogon_creds,
1418 msg_ctx, b, domain->name,
1420 if (!NT_STATUS_IS_OK(status)) {
1421 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1422 invalidate_cm_connection(domain);
1427 DEBUG(1, ("trust_pw_change(%s): %s\n",
1428 domain->name, nt_errstr(status)));
1430 change_result = ntstatus_to_werror(status);
1434 change_result = WERR_OK;
1437 info1->pdc_connection_status = change_result;
1439 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1440 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1441 "pdc_connection[%s]\n",
1442 __func__, domain->name, domain->alt_name,
1444 win_errstr(info1->pdc_connection_status)));
1447 r->out.query->info1 = info1;
1449 DEBUG(5, ("%s: succeeded.\n", __func__));
1453 WERROR _winbind_LogonControl(struct pipes_struct *p,
1454 struct winbind_LogonControl *r)
1456 struct winbindd_domain *domain;
1458 domain = wb_child_domain();
1459 if (domain == NULL) {
1460 return WERR_NO_SUCH_DOMAIN;
1463 switch (r->in.function_code) {
1464 case NETLOGON_CONTROL_REDISCOVER:
1465 if (r->in.level != 2) {
1466 return WERR_INVALID_PARAMETER;
1468 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1469 case NETLOGON_CONTROL_TC_QUERY:
1470 if (r->in.level != 2) {
1471 return WERR_INVALID_PARAMETER;
1473 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1474 case NETLOGON_CONTROL_TC_VERIFY:
1475 if (r->in.level != 2) {
1476 return WERR_INVALID_PARAMETER;
1478 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1479 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1480 if (r->in.level != 1) {
1481 return WERR_INVALID_PARAMETER;
1483 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1488 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1489 __func__, r->in.function_code));
1490 return WERR_NOT_SUPPORTED;
1493 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1494 struct winbind_GetForestTrustInformation *r)
1496 TALLOC_CTX *frame = talloc_stackframe();
1497 NTSTATUS status, result;
1498 struct winbindd_domain *domain;
1499 struct rpc_pipe_client *netlogon_pipe;
1500 struct dcerpc_binding_handle *b;
1502 struct lsa_String trusted_domain_name = {};
1503 struct lsa_StringLarge trusted_domain_name_l = {};
1504 union lsa_TrustedDomainInfo *tdi = NULL;
1505 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1506 struct lsa_ForestTrustInformation _old_fti = {};
1507 struct lsa_ForestTrustInformation *old_fti = NULL;
1508 struct lsa_ForestTrustInformation *new_fti = NULL;
1509 struct lsa_ForestTrustInformation *merged_fti = NULL;
1510 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1511 bool update_fti = false;
1512 struct rpc_pipe_client *local_lsa_pipe;
1513 struct policy_handle local_lsa_policy;
1514 struct dcerpc_binding_handle *local_lsa = NULL;
1516 domain = wb_child_domain();
1517 if (domain == NULL) {
1519 return WERR_NO_SUCH_DOMAIN;
1523 * checking for domain->internal and domain->primary
1524 * makes sure we only do some work when running as DC.
1527 if (domain->internal) {
1529 return WERR_NO_SUCH_DOMAIN;
1532 if (domain->primary) {
1534 return WERR_NO_SUCH_DOMAIN;
1537 trusted_domain_name.string = domain->name;
1538 trusted_domain_name_l.string = domain->name;
1540 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1542 if (!NT_STATUS_IS_OK(status)) {
1543 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1544 __location__, __func__, nt_errstr(status)));
1546 return WERR_INTERNAL_ERROR;
1548 local_lsa = local_lsa_pipe->binding_handle;
1550 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1552 &trusted_domain_name,
1553 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1555 if (!NT_STATUS_IS_OK(status)) {
1556 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1557 __location__, __func__, domain->name, nt_errstr(status)));
1559 return WERR_INTERNAL_ERROR;
1561 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1562 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1563 __location__, __func__, domain->name));
1565 return WERR_NO_SUCH_DOMAIN;
1567 if (!NT_STATUS_IS_OK(result)) {
1568 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1569 __location__, __func__, domain->name, nt_errstr(result)));
1571 return WERR_INTERNAL_ERROR;
1574 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1575 "returned no trusted domain information\n",
1576 __location__, __func__));
1578 return WERR_INTERNAL_ERROR;
1581 tdo = &tdi->info_ex;
1583 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1584 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1585 __func__, tdo->netbios_name.string,
1586 tdo->domain_name.string,
1587 (unsigned)tdo->trust_attributes));
1589 return WERR_NO_SUCH_DOMAIN;
1592 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1594 return WERR_INVALID_FLAGS;
1598 status = cm_connect_netlogon(domain, &netlogon_pipe);
1599 reset_cm_connection_on_error(domain, status);
1600 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1601 status = NT_STATUS_NO_LOGON_SERVERS;
1603 if (!NT_STATUS_IS_OK(status)) {
1604 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1605 nt_errstr(status)));
1607 return ntstatus_to_werror(status);
1609 b = netlogon_pipe->binding_handle;
1611 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1614 if (!NT_STATUS_IS_OK(status)) {
1615 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1616 invalidate_cm_connection(domain);
1620 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1621 domain->name, nt_errstr(status)));
1623 return ntstatus_to_werror(status);
1626 *r->out.forest_trust_info = new_fti;
1628 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1632 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1634 &trusted_domain_name,
1635 LSA_FOREST_TRUST_DOMAIN_INFO,
1637 if (!NT_STATUS_IS_OK(status)) {
1638 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1639 __location__, __func__, domain->name, nt_errstr(status)));
1641 return WERR_INTERNAL_ERROR;
1643 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1644 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1645 __func__, domain->name));
1647 old_fti = &_old_fti;
1648 result = NT_STATUS_OK;
1650 if (!NT_STATUS_IS_OK(result)) {
1651 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1652 __location__, __func__, domain->name, nt_errstr(result)));
1654 return WERR_INTERNAL_ERROR;
1657 if (old_fti == NULL) {
1658 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1659 "returned success without returning forest trust information\n",
1660 __location__, __func__));
1662 return WERR_INTERNAL_ERROR;
1669 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1671 if (!NT_STATUS_IS_OK(status)) {
1672 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1673 __location__, __func__, domain->name, nt_errstr(status)));
1675 return ntstatus_to_werror(status);
1678 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1680 &trusted_domain_name_l,
1681 LSA_FOREST_TRUST_DOMAIN_INFO,
1683 0, /* check_only=0 => store it! */
1686 if (!NT_STATUS_IS_OK(status)) {
1687 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1688 __location__, __func__, domain->name, nt_errstr(status)));
1690 return WERR_INTERNAL_ERROR;
1692 if (!NT_STATUS_IS_OK(result)) {
1693 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1694 __location__, __func__, domain->name, nt_errstr(result)));
1696 return ntstatus_to_werror(result);
1700 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1705 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1707 struct winbindd_domain *domain;
1709 struct rpc_pipe_client *netlogon_pipe;
1711 DEBUG(5, ("_winbind_SendToSam received\n"));
1712 domain = wb_child_domain();
1713 if (domain == NULL) {
1714 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1717 status = cm_connect_netlogon(domain, &netlogon_pipe);
1718 if (!NT_STATUS_IS_OK(status)) {
1719 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1723 status = netlogon_creds_cli_SendToSam(domain->conn.netlogon_creds,
1724 netlogon_pipe->binding_handle,