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"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
39 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
41 *r->out.out_data = r->in.in_data;
44 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
47 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
48 invalidate_cm_connection(domain);
49 /* We invalidated the connection. */
55 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
57 struct winbindd_domain *domain = wb_child_domain();
60 enum lsa_SidType type;
64 return NT_STATUS_REQUEST_NOT_ACCEPTED;
67 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
68 &dom_name, &name, &type);
69 reset_cm_connection_on_error(domain, status);
70 if (!NT_STATUS_IS_OK(status)) {
74 *r->out.domain = dom_name;
80 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
82 struct winbindd_domain *domain = wb_child_domain();
83 struct lsa_RefDomainList *domains = r->out.domains;
87 return NT_STATUS_REQUEST_NOT_ACCEPTED;
91 * This breaks the winbindd_domain->methods abstraction: This
92 * is only called for remote domains, and both winbindd_msrpc
93 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
94 * done at the wbint RPC layer.
96 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
97 &domains, &r->out.names);
99 if (domains != NULL) {
100 r->out.domains = domains;
103 reset_cm_connection_on_error(domain, status);
107 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
109 struct winbindd_domain *domain = wb_child_domain();
112 if (domain == NULL) {
113 return NT_STATUS_REQUEST_NOT_ACCEPTED;
116 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
117 r->in.name, r->in.flags,
118 r->out.sid, r->out.type);
119 reset_cm_connection_on_error(domain, status);
123 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
124 struct wbint_Sids2UnixIDs *r)
128 struct lsa_DomainInfo *d;
129 struct wbint_TransID *ids;
132 struct id_map **id_map_ptrs = NULL;
133 struct idmap_domain *dom;
134 NTSTATUS status = NT_STATUS_NO_MEMORY;
136 if (r->in.domains->count != 1) {
137 return NT_STATUS_INVALID_PARAMETER;
140 d = &r->in.domains->domains[0];
141 ids = r->in.ids->ids;
142 num_ids = r->in.ids->num_ids;
144 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
146 DEBUG(10, ("idmap domain %s:%s not found\n",
147 d->name.string, sid_string_dbg(d->sid)));
149 for (i=0; i<num_ids; i++) {
151 ids[i].xid = (struct unixid) {
153 .type = ID_TYPE_NOT_SPECIFIED
160 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
161 if (id_map_ptrs == NULL) {
166 * Convert the input data into a list of id_map structs
167 * suitable for handing in to the idmap sids_to_unixids
171 for (i=0; i<num_ids; i++) {
172 struct id_map *m = id_map_ptrs[i];
174 sid_compose(m->sid, d->sid, ids[i].rid);
175 m->status = ID_UNKNOWN;
176 m->xid = (struct unixid) { .type = ids[i].type };
179 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
181 if (!NT_STATUS_IS_OK(status)) {
182 DEBUG(10, ("sids_to_unixids returned %s\n",
188 * Extract the results for handing them back to the caller.
191 for (i=0; i<num_ids; i++) {
192 struct id_map *m = id_map_ptrs[i];
194 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
195 DBG_DEBUG("id %"PRIu32" is out of range "
196 "%"PRIu32"-%"PRIu32" for domain %s\n",
197 m->xid.id, dom->low_id, dom->high_id,
199 m->status = ID_UNMAPPED;
202 if (m->status == ID_MAPPED) {
205 ids[i].xid.id = UINT32_MAX;
206 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
212 status = NT_STATUS_NO_MEMORY;
214 TALLOC_FREE(id_map_ptrs);
218 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
219 struct wbint_UnixIDs2Sids *r)
221 struct id_map **maps;
225 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
227 return NT_STATUS_NO_MEMORY;
230 for (i=0; i<r->in.num_ids; i++) {
231 maps[i]->status = ID_UNKNOWN;
232 maps[i]->xid = r->in.xids[i];
235 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
237 if (!NT_STATUS_IS_OK(status)) {
242 for (i=0; i<r->in.num_ids; i++) {
243 r->out.xids[i] = maps[i]->xid;
244 sid_copy(&r->out.sids[i], maps[i]->sid);
252 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
257 status = idmap_allocate_uid(&xid);
258 if (!NT_STATUS_IS_OK(status)) {
261 *r->out.uid = xid.id;
265 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
270 status = idmap_allocate_gid(&xid);
271 if (!NT_STATUS_IS_OK(status)) {
274 *r->out.gid = xid.id;
278 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
280 struct idmap_domain *domain;
283 domain = idmap_find_domain(r->in.info->domain_name);
284 if ((domain == NULL) || (domain->query_user == NULL)) {
285 return NT_STATUS_REQUEST_NOT_ACCEPTED;
288 status = domain->query_user(domain, r->in.info);
292 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
293 struct wbint_LookupUserAliases *r)
295 struct winbindd_domain *domain = wb_child_domain();
298 if (domain == NULL) {
299 return NT_STATUS_REQUEST_NOT_ACCEPTED;
302 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
303 r->in.sids->num_sids,
305 &r->out.rids->num_rids,
307 reset_cm_connection_on_error(domain, status);
311 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
312 struct wbint_LookupUserGroups *r)
314 struct winbindd_domain *domain = wb_child_domain();
317 if (domain == NULL) {
318 return NT_STATUS_REQUEST_NOT_ACCEPTED;
321 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
322 &r->out.sids->num_sids,
324 reset_cm_connection_on_error(domain, status);
328 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
329 struct wbint_QuerySequenceNumber *r)
331 struct winbindd_domain *domain = wb_child_domain();
334 if (domain == NULL) {
335 return NT_STATUS_REQUEST_NOT_ACCEPTED;
338 status = wb_cache_sequence_number(domain, r->out.sequence);
339 reset_cm_connection_on_error(domain, status);
343 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
344 struct wbint_LookupGroupMembers *r)
346 struct winbindd_domain *domain = wb_child_domain();
347 uint32_t i, num_names;
348 struct dom_sid *sid_mem;
350 uint32_t *name_types;
353 if (domain == NULL) {
354 return NT_STATUS_REQUEST_NOT_ACCEPTED;
357 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
358 r->in.type, &num_names, &sid_mem,
359 &names, &name_types);
360 reset_cm_connection_on_error(domain, status);
361 if (!NT_STATUS_IS_OK(status)) {
365 r->out.members->num_principals = num_names;
366 r->out.members->principals = talloc_array(
367 r->out.members, struct wbint_Principal, num_names);
368 if (r->out.members->principals == NULL) {
369 return NT_STATUS_NO_MEMORY;
372 for (i=0; i<num_names; i++) {
373 struct wbint_Principal *m = &r->out.members->principals[i];
374 sid_copy(&m->sid, &sid_mem[i]);
375 m->name = talloc_move(r->out.members->principals, &names[i]);
376 m->type = (enum lsa_SidType)name_types[i];
382 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
383 struct wbint_QueryGroupList *r)
385 TALLOC_CTX *frame = NULL;
386 struct winbindd_domain *domain = wb_child_domain();
388 uint32_t num_local_groups = 0;
389 struct wb_acct_info *local_groups = NULL;
390 uint32_t num_dom_groups = 0;
391 struct wb_acct_info *dom_groups = NULL;
393 uint64_t num_total = 0;
394 struct wbint_Principal *result;
395 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
396 bool include_local_groups = false;
398 if (domain == NULL) {
399 return NT_STATUS_REQUEST_NOT_ACCEPTED;
402 frame = talloc_stackframe();
404 switch (lp_server_role()) {
405 case ROLE_ACTIVE_DIRECTORY_DC:
406 if (domain->internal) {
408 * we want to include local groups
409 * for BUILTIN and WORKGROUP
411 include_local_groups = true;
416 * We might include local groups in more
417 * setups later, but that requires more work
423 if (include_local_groups) {
424 status = wb_cache_enum_local_groups(domain, frame,
427 reset_cm_connection_on_error(domain, status);
428 if (!NT_STATUS_IS_OK(status)) {
433 status = wb_cache_enum_dom_groups(domain, frame,
436 reset_cm_connection_on_error(domain, status);
437 if (!NT_STATUS_IS_OK(status)) {
441 num_total = num_local_groups + num_dom_groups;
442 if (num_total > UINT32_MAX) {
443 status = NT_STATUS_INTERNAL_ERROR;
447 result = talloc_array(frame, struct wbint_Principal, num_total);
448 if (result == NULL) {
449 status = NT_STATUS_NO_MEMORY;
453 for (i = 0; i < num_local_groups; i++) {
454 struct wb_acct_info *lg = &local_groups[i];
455 struct wbint_Principal *rg = &result[ti++];
457 sid_compose(&rg->sid, &domain->sid, lg->rid);
458 rg->type = SID_NAME_ALIAS;
459 rg->name = talloc_strdup(result, lg->acct_name);
460 if (rg->name == NULL) {
461 status = NT_STATUS_NO_MEMORY;
465 num_local_groups = 0;
467 for (i = 0; i < num_dom_groups; i++) {
468 struct wb_acct_info *dg = &dom_groups[i];
469 struct wbint_Principal *rg = &result[ti++];
471 sid_compose(&rg->sid, &domain->sid, dg->rid);
472 rg->type = SID_NAME_DOM_GRP;
473 rg->name = talloc_strdup(result, dg->acct_name);
474 if (rg->name == NULL) {
475 status = NT_STATUS_NO_MEMORY;
481 r->out.groups->num_principals = ti;
482 r->out.groups->principals = talloc_move(r->out.groups, &result);
484 status = NT_STATUS_OK;
490 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
491 struct wbint_QueryUserRidList *r)
493 struct winbindd_domain *domain = wb_child_domain();
496 if (domain == NULL) {
497 return NT_STATUS_REQUEST_NOT_ACCEPTED;
501 * Right now this is overkill. We should add a backend call
502 * just querying the rids.
505 status = wb_cache_query_user_list(domain, p->mem_ctx,
507 reset_cm_connection_on_error(domain, status);
509 if (!NT_STATUS_IS_OK(status)) {
513 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
518 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
520 struct winbindd_domain *domain = wb_child_domain();
521 struct rpc_pipe_client *netlogon_pipe;
522 struct netr_DsRGetDCNameInfo *dc_info;
525 unsigned int orig_timeout;
526 struct dcerpc_binding_handle *b;
528 if (domain == NULL) {
529 return dsgetdcname(p->mem_ctx, server_messaging_context(),
530 r->in.domain_name, r->in.domain_guid,
531 r->in.site_name ? r->in.site_name : "",
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);
551 if (domain->active_directory) {
552 status = dcerpc_netr_DsRGetDCName(b,
553 p->mem_ctx, domain->dcname,
554 r->in.domain_name, NULL, r->in.domain_guid,
555 r->in.flags, r->out.dc_info, &werr);
556 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
559 if (reset_cm_connection_on_error(domain, status)) {
561 status = cm_connect_netlogon(domain, &netlogon_pipe);
563 reset_cm_connection_on_error(domain, status);
564 if (!NT_STATUS_IS_OK(status)) {
565 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
569 b = netlogon_pipe->binding_handle;
571 /* This call can take a long time - allow the server to time out.
572 35 seconds should do it. */
574 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
579 * Fallback to less capable methods
582 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
583 if (dc_info == NULL) {
584 status = NT_STATUS_NO_MEMORY;
588 if (r->in.flags & DS_PDC_REQUIRED) {
589 status = dcerpc_netr_GetDcName(b,
590 p->mem_ctx, domain->dcname,
591 r->in.domain_name, &dc_info->dc_unc, &werr);
593 status = dcerpc_netr_GetAnyDCName(b,
594 p->mem_ctx, domain->dcname,
595 r->in.domain_name, &dc_info->dc_unc, &werr);
598 reset_cm_connection_on_error(domain, status);
599 if (!NT_STATUS_IS_OK(status)) {
600 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
604 if (!W_ERROR_IS_OK(werr)) {
605 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
607 status = werror_to_ntstatus(werr);
611 *r->out.dc_info = dc_info;
612 status = NT_STATUS_OK;
615 /* And restore our original timeout. */
616 rpccli_set_timeout(netlogon_pipe, orig_timeout);
621 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
623 struct winbindd_domain *domain = wb_child_domain();
626 enum lsa_SidType *types;
627 struct wbint_Principal *result;
631 if (domain == NULL) {
632 return NT_STATUS_REQUEST_NOT_ACCEPTED;
635 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
636 r->in.rids->rids, r->in.rids->num_rids,
637 &domain_name, &names, &types);
638 reset_cm_connection_on_error(domain, status);
639 if (!NT_STATUS_IS_OK(status)) {
643 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
645 result = talloc_array(p->mem_ctx, struct wbint_Principal,
646 r->in.rids->num_rids);
647 if (result == NULL) {
648 return NT_STATUS_NO_MEMORY;
651 for (i=0; i<r->in.rids->num_rids; i++) {
652 sid_compose(&result[i].sid, r->in.domain_sid,
653 r->in.rids->rids[i]);
654 result[i].type = types[i];
655 result[i].name = talloc_move(result, &names[i]);
660 r->out.names->num_principals = r->in.rids->num_rids;
661 r->out.names->principals = result;
665 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
666 struct wbint_CheckMachineAccount *r)
668 struct winbindd_domain *domain;
672 domain = wb_child_domain();
673 if (domain == NULL) {
674 return NT_STATUS_REQUEST_NOT_ACCEPTED;
678 invalidate_cm_connection(domain);
679 domain->conn.netlogon_force_reauth = true;
682 struct rpc_pipe_client *netlogon_pipe = NULL;
683 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
684 status = cm_connect_netlogon_secure(domain,
686 &netlogon_creds_ctx);
689 /* There is a race condition between fetching the trust account
690 password and the periodic machine password change. So it's
691 possible that the trust account password has been changed on us.
692 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
694 #define MAX_RETRIES 3
696 if ((num_retries < MAX_RETRIES)
697 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
702 if (!NT_STATUS_IS_OK(status)) {
703 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
707 /* Pass back result code - zero for success, other values for
708 specific failures. */
710 DEBUG(3,("domain %s secret is %s\n", domain->name,
711 NT_STATUS_IS_OK(status) ? "good" : "bad"));
714 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
715 ("Checking the trust account password for domain %s returned %s\n",
716 domain->name, nt_errstr(status)));
721 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
722 struct wbint_ChangeMachineAccount *r)
724 struct messaging_context *msg_ctx = server_messaging_context();
725 struct winbindd_domain *domain;
727 struct rpc_pipe_client *netlogon_pipe = NULL;
728 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
730 domain = wb_child_domain();
731 if (domain == NULL) {
732 return NT_STATUS_REQUEST_NOT_ACCEPTED;
735 status = cm_connect_netlogon_secure(domain,
737 &netlogon_creds_ctx);
738 if (!NT_STATUS_IS_OK(status)) {
739 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
743 status = trust_pw_change(netlogon_creds_ctx,
745 netlogon_pipe->binding_handle,
750 /* Pass back result code - zero for success, other values for
751 specific failures. */
753 DEBUG(3,("domain %s secret %s\n", domain->name,
754 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
757 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
758 ("Changing the trust account password for domain %s returned %s\n",
759 domain->name, nt_errstr(status)));
764 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
767 struct winbindd_domain *domain;
768 struct rpc_pipe_client *netlogon_pipe;
769 union netr_CONTROL_QUERY_INFORMATION info;
771 fstring logon_server;
772 struct dcerpc_binding_handle *b;
775 domain = wb_child_domain();
776 if (domain == NULL) {
777 return NT_STATUS_REQUEST_NOT_ACCEPTED;
781 status = cm_connect_netlogon(domain, &netlogon_pipe);
782 reset_cm_connection_on_error(domain, status);
783 if (!NT_STATUS_IS_OK(status)) {
784 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
789 b = netlogon_pipe->binding_handle;
791 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
792 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
793 if (*r->out.dcname == NULL) {
794 DEBUG(2, ("Could not allocate memory\n"));
795 return NT_STATUS_NO_MEMORY;
799 * This provokes a WERR_NOT_SUPPORTED error message. This is
800 * documented in the wspp docs. I could not get a successful
801 * call to work, but the main point here is testing that the
802 * netlogon pipe works.
804 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
805 logon_server, NETLOGON_CONTROL_QUERY,
808 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
809 DEBUG(10, ("Session might have expired. "
810 "Reconnect and retry once.\n"));
811 invalidate_cm_connection(domain);
816 reset_cm_connection_on_error(domain, status);
817 if (!NT_STATUS_IS_OK(status)) {
818 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
823 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
824 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
825 "WERR_NOT_SUPPORTED\n",
827 return werror_to_ntstatus(werr);
830 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
834 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
835 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
837 struct winbindd_domain *domain;
839 struct rpc_pipe_client *netlogon_pipe = NULL;
840 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
842 domain = wb_child_domain();
843 if (domain == NULL) {
844 return NT_STATUS_REQUEST_NOT_ACCEPTED;
847 status = cm_connect_netlogon_secure(domain,
849 &netlogon_creds_ctx);
850 if (!NT_STATUS_IS_OK(status)) {
851 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
855 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
856 netlogon_pipe->binding_handle,
861 /* Pass back result code - zero for success, other values for
862 specific failures. */
864 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
865 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
868 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
869 ("Update of DNS records via RW DC %s returned %s\n",
870 domain->name, nt_errstr(status)));
875 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
876 struct winbind_SamLogon *r)
878 struct winbindd_domain *domain;
880 struct netr_IdentityInfo *identity_info = NULL;
881 const uint8_t chal_zero[8] = {0, };
882 const uint8_t *challenge = chal_zero;
883 DATA_BLOB lm_response, nt_response;
885 uint16_t validation_level;
886 union netr_Validation *validation = NULL;
887 bool interactive = false;
889 domain = wb_child_domain();
890 if (domain == NULL) {
891 return NT_STATUS_REQUEST_NOT_ACCEPTED;
894 switch (r->in.validation_level) {
899 return NT_STATUS_REQUEST_NOT_ACCEPTED;
902 switch (r->in.logon_level) {
903 case NetlogonInteractiveInformation:
904 case NetlogonServiceInformation:
905 case NetlogonInteractiveTransitiveInformation:
906 case NetlogonServiceTransitiveInformation:
907 if (r->in.logon.password == NULL) {
908 return NT_STATUS_REQUEST_NOT_ACCEPTED;
912 identity_info = &r->in.logon.password->identity_info;
914 challenge = chal_zero;
915 lm_response = data_blob_talloc(p->mem_ctx,
916 r->in.logon.password->lmpassword.hash,
917 sizeof(r->in.logon.password->lmpassword.hash));
918 nt_response = data_blob_talloc(p->mem_ctx,
919 r->in.logon.password->ntpassword.hash,
920 sizeof(r->in.logon.password->ntpassword.hash));
923 case NetlogonNetworkInformation:
924 case NetlogonNetworkTransitiveInformation:
925 if (r->in.logon.network == NULL) {
926 return NT_STATUS_REQUEST_NOT_ACCEPTED;
930 identity_info = &r->in.logon.network->identity_info;
932 challenge = r->in.logon.network->challenge;
933 lm_response = data_blob_talloc(p->mem_ctx,
934 r->in.logon.network->lm.data,
935 r->in.logon.network->lm.length);
936 nt_response = data_blob_talloc(p->mem_ctx,
937 r->in.logon.network->nt.data,
938 r->in.logon.network->nt.length);
941 case NetlogonGenericInformation:
942 if (r->in.logon.generic == NULL) {
943 return NT_STATUS_REQUEST_NOT_ACCEPTED;
946 identity_info = &r->in.logon.generic->identity_info;
948 * Not implemented here...
950 return NT_STATUS_REQUEST_NOT_ACCEPTED;
953 return NT_STATUS_REQUEST_NOT_ACCEPTED;
956 status = winbind_dual_SamLogon(domain, p->mem_ctx,
958 identity_info->parameter_control,
959 identity_info->account_name.string,
960 identity_info->domain_name.string,
961 identity_info->workstation.string,
963 lm_response, nt_response,
964 &r->out.authoritative,
969 if (!NT_STATUS_IS_OK(status)) {
972 switch (r->in.validation_level) {
974 status = map_validation_to_info3(p->mem_ctx,
977 &r->out.validation.sam3);
978 TALLOC_FREE(validation);
979 if (!NT_STATUS_IS_OK(status)) {
984 status = map_validation_to_info6(p->mem_ctx,
987 &r->out.validation.sam6);
988 TALLOC_FREE(validation);
989 if (!NT_STATUS_IS_OK(status)) {
995 smb_panic(__location__);
996 return NT_STATUS_INTERNAL_ERROR;
999 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1000 struct winbindd_domain *domain,
1001 struct winbind_LogonControl *r)
1004 struct rpc_pipe_client *netlogon_pipe = NULL;
1005 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1006 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1007 WERROR check_result = WERR_INTERNAL_ERROR;
1009 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1010 if (info2 == NULL) {
1011 return WERR_NOT_ENOUGH_MEMORY;
1014 if (domain->internal) {
1015 check_result = WERR_OK;
1020 * For now we just force a reconnect
1022 * TODO: take care of the optional '\dcname'
1024 invalidate_cm_connection(domain);
1025 domain->conn.netlogon_force_reauth = true;
1026 status = cm_connect_netlogon_secure(domain,
1028 &netlogon_creds_ctx);
1029 reset_cm_connection_on_error(domain, status);
1030 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1031 status = NT_STATUS_NO_LOGON_SERVERS;
1033 if (!NT_STATUS_IS_OK(status)) {
1034 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1035 __func__, domain->name, domain->alt_name,
1036 nt_errstr(status)));
1038 * Here we return a top level error!
1039 * This is different than TC_QUERY or TC_VERIFY.
1041 return ntstatus_to_werror(status);
1043 check_result = WERR_OK;
1046 info2->pdc_connection_status = WERR_OK;
1047 if (domain->dcname != NULL) {
1048 info2->flags |= NETLOGON_HAS_IP;
1049 info2->flags |= NETLOGON_HAS_TIMESERV;
1050 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1052 if (info2->trusted_dc_name == NULL) {
1053 return WERR_NOT_ENOUGH_MEMORY;
1056 info2->trusted_dc_name = talloc_strdup(info2, "");
1057 if (info2->trusted_dc_name == NULL) {
1058 return WERR_NOT_ENOUGH_MEMORY;
1061 info2->tc_connection_status = check_result;
1063 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1064 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1065 "pdc_connection[%s] tc_connection[%s]\n",
1066 __func__, domain->name, domain->alt_name,
1068 win_errstr(info2->pdc_connection_status),
1069 win_errstr(info2->tc_connection_status)));
1072 r->out.query->info2 = info2;
1074 DEBUG(5, ("%s: succeeded.\n", __func__));
1078 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1079 struct winbindd_domain *domain,
1080 struct winbind_LogonControl *r)
1083 struct rpc_pipe_client *netlogon_pipe = NULL;
1084 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1085 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1086 WERROR check_result = WERR_INTERNAL_ERROR;
1088 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1089 if (info2 == NULL) {
1090 return WERR_NOT_ENOUGH_MEMORY;
1093 if (domain->internal) {
1094 check_result = WERR_OK;
1098 status = cm_connect_netlogon_secure(domain,
1100 &netlogon_creds_ctx);
1101 reset_cm_connection_on_error(domain, status);
1102 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1103 status = NT_STATUS_NO_LOGON_SERVERS;
1105 if (!NT_STATUS_IS_OK(status)) {
1106 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1107 nt_errstr(status)));
1108 check_result = ntstatus_to_werror(status);
1111 check_result = WERR_OK;
1114 info2->pdc_connection_status = WERR_OK;
1115 if (domain->dcname != NULL) {
1116 info2->flags |= NETLOGON_HAS_IP;
1117 info2->flags |= NETLOGON_HAS_TIMESERV;
1118 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1120 if (info2->trusted_dc_name == NULL) {
1121 return WERR_NOT_ENOUGH_MEMORY;
1124 info2->trusted_dc_name = talloc_strdup(info2, "");
1125 if (info2->trusted_dc_name == NULL) {
1126 return WERR_NOT_ENOUGH_MEMORY;
1129 info2->tc_connection_status = check_result;
1131 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1132 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1133 "pdc_connection[%s] tc_connection[%s]\n",
1134 __func__, domain->name, domain->alt_name,
1136 win_errstr(info2->pdc_connection_status),
1137 win_errstr(info2->tc_connection_status)));
1140 r->out.query->info2 = info2;
1142 DEBUG(5, ("%s: succeeded.\n", __func__));
1146 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1147 struct winbindd_domain *domain,
1148 struct winbind_LogonControl *r)
1150 TALLOC_CTX *frame = talloc_stackframe();
1153 struct lsa_String trusted_domain_name = {};
1154 struct lsa_StringLarge trusted_domain_name_l = {};
1155 struct rpc_pipe_client *local_lsa_pipe = NULL;
1156 struct policy_handle local_lsa_policy = {};
1157 struct dcerpc_binding_handle *local_lsa = NULL;
1158 struct rpc_pipe_client *netlogon_pipe = NULL;
1159 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1160 struct cli_credentials *creds = NULL;
1161 struct samr_Password *cur_nt_hash = NULL;
1162 uint32_t trust_attributes = 0;
1163 struct samr_Password new_owf_password = {};
1165 struct samr_Password old_owf_password = {};
1167 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1168 bool fetch_fti = false;
1169 struct lsa_ForestTrustInformation *new_fti = NULL;
1170 struct netr_TrustInfo *trust_info = NULL;
1171 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1172 struct dcerpc_binding_handle *b = NULL;
1173 WERROR check_result = WERR_INTERNAL_ERROR;
1174 WERROR verify_result = WERR_INTERNAL_ERROR;
1177 trusted_domain_name.string = domain->name;
1178 trusted_domain_name_l.string = domain->name;
1180 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1181 if (info2 == NULL) {
1183 return WERR_NOT_ENOUGH_MEMORY;
1186 if (domain->internal) {
1187 check_result = WERR_OK;
1191 status = pdb_get_trust_credentials(domain->name,
1195 if (NT_STATUS_IS_OK(status)) {
1196 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1200 if (!domain->primary) {
1201 union lsa_TrustedDomainInfo *tdi = NULL;
1203 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1205 if (!NT_STATUS_IS_OK(status)) {
1206 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1207 __location__, __func__, nt_errstr(status)));
1209 return WERR_INTERNAL_ERROR;
1211 local_lsa = local_lsa_pipe->binding_handle;
1213 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1215 &trusted_domain_name,
1216 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1218 if (!NT_STATUS_IS_OK(status)) {
1219 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1220 __location__, __func__, domain->name, nt_errstr(status)));
1222 return WERR_INTERNAL_ERROR;
1224 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1225 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1226 __location__, __func__, domain->name));
1228 return WERR_NO_SUCH_DOMAIN;
1230 if (!NT_STATUS_IS_OK(result)) {
1231 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1232 __location__, __func__, domain->name, nt_errstr(result)));
1234 return WERR_INTERNAL_ERROR;
1237 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1238 "returned no trusted domain information\n",
1239 __location__, __func__));
1241 return WERR_INTERNAL_ERROR;
1244 local_tdo = &tdi->info_ex;
1245 trust_attributes = local_tdo->trust_attributes;
1248 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1249 struct lsa_ForestTrustInformation *old_fti = NULL;
1251 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1253 &trusted_domain_name,
1254 LSA_FOREST_TRUST_DOMAIN_INFO,
1256 if (!NT_STATUS_IS_OK(status)) {
1257 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1258 __location__, __func__, domain->name, nt_errstr(status)));
1260 return WERR_INTERNAL_ERROR;
1262 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1263 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1264 __func__, domain->name));
1267 result = NT_STATUS_OK;
1269 if (!NT_STATUS_IS_OK(result)) {
1270 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1271 __location__, __func__, domain->name, nt_errstr(result)));
1273 return WERR_INTERNAL_ERROR;
1276 TALLOC_FREE(old_fti);
1280 status = cm_connect_netlogon_secure(domain,
1282 &netlogon_creds_ctx);
1283 reset_cm_connection_on_error(domain, status);
1284 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1285 status = NT_STATUS_NO_LOGON_SERVERS;
1287 if (!NT_STATUS_IS_OK(status)) {
1288 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1289 nt_errstr(status)));
1290 check_result = ntstatus_to_werror(status);
1293 check_result = WERR_OK;
1294 b = netlogon_pipe->binding_handle;
1296 if (cur_nt_hash == NULL) {
1297 verify_result = WERR_NO_TRUST_LSA_SECRET;
1302 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1305 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1306 status = NT_STATUS_NOT_SUPPORTED;
1308 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1310 status = NT_STATUS_OK;
1312 if (!NT_STATUS_IS_OK(status)) {
1313 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1314 invalidate_cm_connection(domain);
1318 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1320 domain->name, nt_errstr(status)));
1321 check_result = ntstatus_to_werror(status);
1326 if (new_fti != NULL) {
1327 struct lsa_ForestTrustInformation old_fti = {};
1328 struct lsa_ForestTrustInformation *merged_fti = NULL;
1329 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1331 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1334 if (!NT_STATUS_IS_OK(status)) {
1335 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1336 __location__, __func__,
1337 domain->name, nt_errstr(status)));
1339 return ntstatus_to_werror(status);
1342 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1344 &trusted_domain_name_l,
1345 LSA_FOREST_TRUST_DOMAIN_INFO,
1347 0, /* check_only=0 => store it! */
1350 if (!NT_STATUS_IS_OK(status)) {
1351 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1352 __location__, __func__, domain->name, nt_errstr(status)));
1354 return WERR_INTERNAL_ERROR;
1356 if (!NT_STATUS_IS_OK(result)) {
1357 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1358 __location__, __func__, domain->name, nt_errstr(result)));
1360 return ntstatus_to_werror(result);
1364 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1369 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1370 status = NT_STATUS_NOT_SUPPORTED;
1372 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1373 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1374 nt_errstr(status)));
1375 verify_result = WERR_OK;
1378 if (!NT_STATUS_IS_OK(status)) {
1379 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1380 invalidate_cm_connection(domain);
1384 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1385 nt_errstr(status)));
1387 if (!dcerpc_binding_handle_is_connected(b)) {
1388 check_result = ntstatus_to_werror(status);
1391 verify_result = ntstatus_to_werror(status);
1396 if (trust_info != NULL && trust_info->count >= 1) {
1397 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1399 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1400 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1405 cmp_new = memcmp(new_owf_password.hash,
1407 sizeof(cur_nt_hash->hash));
1408 cmp_old = memcmp(old_owf_password.hash,
1410 sizeof(cur_nt_hash->hash));
1411 if (cmp_new != 0 && cmp_old != 0) {
1412 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1413 "any password known to dcname[%s]\n",
1414 __func__, domain->name, domain->alt_name,
1416 verify_result = WERR_WRONG_PASSWORD;
1421 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1422 "against the old password known to dcname[%s]\n",
1423 __func__, domain->name, domain->alt_name,
1427 verify_result = WERR_OK;
1431 verify_result = check_result;
1433 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1434 info2->pdc_connection_status = verify_result;
1435 if (domain->dcname != NULL) {
1436 info2->flags |= NETLOGON_HAS_IP;
1437 info2->flags |= NETLOGON_HAS_TIMESERV;
1438 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1440 if (info2->trusted_dc_name == NULL) {
1442 return WERR_NOT_ENOUGH_MEMORY;
1445 info2->trusted_dc_name = talloc_strdup(info2, "");
1446 if (info2->trusted_dc_name == NULL) {
1448 return WERR_NOT_ENOUGH_MEMORY;
1451 info2->tc_connection_status = check_result;
1453 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1454 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1455 "pdc_connection[%s] tc_connection[%s]\n",
1456 __func__, domain->name, domain->alt_name,
1458 win_errstr(info2->pdc_connection_status),
1459 win_errstr(info2->tc_connection_status)));
1462 r->out.query->info2 = info2;
1464 DEBUG(5, ("%s: succeeded.\n", __func__));
1469 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1470 struct winbindd_domain *domain,
1471 struct winbind_LogonControl *r)
1473 struct messaging_context *msg_ctx = server_messaging_context();
1475 struct rpc_pipe_client *netlogon_pipe = NULL;
1476 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1477 struct cli_credentials *creds = NULL;
1478 struct samr_Password *cur_nt_hash = NULL;
1479 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1480 struct dcerpc_binding_handle *b;
1481 WERROR change_result = WERR_OK;
1484 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1485 if (info1 == NULL) {
1486 return WERR_NOT_ENOUGH_MEMORY;
1489 if (domain->internal) {
1490 return WERR_NOT_SUPPORTED;
1493 status = pdb_get_trust_credentials(domain->name,
1497 if (NT_STATUS_IS_OK(status)) {
1498 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1503 status = cm_connect_netlogon_secure(domain,
1505 &netlogon_creds_ctx);
1506 reset_cm_connection_on_error(domain, status);
1507 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1508 status = NT_STATUS_NO_LOGON_SERVERS;
1510 if (!NT_STATUS_IS_OK(status)) {
1511 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1512 __func__, domain->name, domain->alt_name,
1513 nt_errstr(status)));
1515 * Here we return a top level error!
1516 * This is different than TC_QUERY or TC_VERIFY.
1518 return ntstatus_to_werror(status);
1520 b = netlogon_pipe->binding_handle;
1522 if (cur_nt_hash == NULL) {
1523 change_result = WERR_NO_TRUST_LSA_SECRET;
1526 TALLOC_FREE(cur_nt_hash);
1528 status = trust_pw_change(netlogon_creds_ctx,
1529 msg_ctx, b, domain->name,
1532 if (!NT_STATUS_IS_OK(status)) {
1533 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1534 invalidate_cm_connection(domain);
1539 DEBUG(1, ("trust_pw_change(%s): %s\n",
1540 domain->name, nt_errstr(status)));
1542 change_result = ntstatus_to_werror(status);
1546 change_result = WERR_OK;
1549 info1->pdc_connection_status = change_result;
1551 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1552 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1553 "pdc_connection[%s]\n",
1554 __func__, domain->name, domain->alt_name,
1556 win_errstr(info1->pdc_connection_status)));
1559 r->out.query->info1 = info1;
1561 DEBUG(5, ("%s: succeeded.\n", __func__));
1565 WERROR _winbind_LogonControl(struct pipes_struct *p,
1566 struct winbind_LogonControl *r)
1568 struct winbindd_domain *domain;
1570 domain = wb_child_domain();
1571 if (domain == NULL) {
1572 return WERR_NO_SUCH_DOMAIN;
1575 switch (r->in.function_code) {
1576 case NETLOGON_CONTROL_REDISCOVER:
1577 if (r->in.level != 2) {
1578 return WERR_INVALID_PARAMETER;
1580 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1581 case NETLOGON_CONTROL_TC_QUERY:
1582 if (r->in.level != 2) {
1583 return WERR_INVALID_PARAMETER;
1585 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1586 case NETLOGON_CONTROL_TC_VERIFY:
1587 if (r->in.level != 2) {
1588 return WERR_INVALID_PARAMETER;
1590 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1591 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1592 if (r->in.level != 1) {
1593 return WERR_INVALID_PARAMETER;
1595 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1600 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1601 __func__, r->in.function_code));
1602 return WERR_NOT_SUPPORTED;
1605 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1606 struct winbind_GetForestTrustInformation *r)
1608 TALLOC_CTX *frame = talloc_stackframe();
1609 NTSTATUS status, result;
1610 struct winbindd_domain *domain;
1611 struct rpc_pipe_client *netlogon_pipe = NULL;
1612 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1613 struct dcerpc_binding_handle *b;
1615 struct lsa_String trusted_domain_name = {};
1616 struct lsa_StringLarge trusted_domain_name_l = {};
1617 union lsa_TrustedDomainInfo *tdi = NULL;
1618 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1619 struct lsa_ForestTrustInformation _old_fti = {};
1620 struct lsa_ForestTrustInformation *old_fti = NULL;
1621 struct lsa_ForestTrustInformation *new_fti = NULL;
1622 struct lsa_ForestTrustInformation *merged_fti = NULL;
1623 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1624 bool update_fti = false;
1625 struct rpc_pipe_client *local_lsa_pipe;
1626 struct policy_handle local_lsa_policy;
1627 struct dcerpc_binding_handle *local_lsa = NULL;
1629 domain = wb_child_domain();
1630 if (domain == NULL) {
1632 return WERR_NO_SUCH_DOMAIN;
1636 * checking for domain->internal and domain->primary
1637 * makes sure we only do some work when running as DC.
1640 if (domain->internal) {
1642 return WERR_NO_SUCH_DOMAIN;
1645 if (domain->primary) {
1647 return WERR_NO_SUCH_DOMAIN;
1650 trusted_domain_name.string = domain->name;
1651 trusted_domain_name_l.string = domain->name;
1653 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1655 if (!NT_STATUS_IS_OK(status)) {
1656 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1657 __location__, __func__, nt_errstr(status)));
1659 return WERR_INTERNAL_ERROR;
1661 local_lsa = local_lsa_pipe->binding_handle;
1663 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1665 &trusted_domain_name,
1666 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1668 if (!NT_STATUS_IS_OK(status)) {
1669 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1670 __location__, __func__, domain->name, nt_errstr(status)));
1672 return WERR_INTERNAL_ERROR;
1674 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1675 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1676 __location__, __func__, domain->name));
1678 return WERR_NO_SUCH_DOMAIN;
1680 if (!NT_STATUS_IS_OK(result)) {
1681 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1682 __location__, __func__, domain->name, nt_errstr(result)));
1684 return WERR_INTERNAL_ERROR;
1687 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1688 "returned no trusted domain information\n",
1689 __location__, __func__));
1691 return WERR_INTERNAL_ERROR;
1694 tdo = &tdi->info_ex;
1696 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1697 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1698 __func__, tdo->netbios_name.string,
1699 tdo->domain_name.string,
1700 (unsigned)tdo->trust_attributes));
1702 return WERR_NO_SUCH_DOMAIN;
1705 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1707 return WERR_INVALID_FLAGS;
1711 status = cm_connect_netlogon_secure(domain,
1713 &netlogon_creds_ctx);
1714 reset_cm_connection_on_error(domain, status);
1715 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1716 status = NT_STATUS_NO_LOGON_SERVERS;
1718 if (!NT_STATUS_IS_OK(status)) {
1719 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1720 nt_errstr(status)));
1722 return ntstatus_to_werror(status);
1724 b = netlogon_pipe->binding_handle;
1726 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1729 if (!NT_STATUS_IS_OK(status)) {
1730 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1731 invalidate_cm_connection(domain);
1735 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1736 domain->name, nt_errstr(status)));
1738 return ntstatus_to_werror(status);
1741 *r->out.forest_trust_info = new_fti;
1743 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1747 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1749 &trusted_domain_name,
1750 LSA_FOREST_TRUST_DOMAIN_INFO,
1752 if (!NT_STATUS_IS_OK(status)) {
1753 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1754 __location__, __func__, domain->name, nt_errstr(status)));
1756 return WERR_INTERNAL_ERROR;
1758 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1759 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1760 __func__, domain->name));
1762 old_fti = &_old_fti;
1763 result = NT_STATUS_OK;
1765 if (!NT_STATUS_IS_OK(result)) {
1766 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1767 __location__, __func__, domain->name, nt_errstr(result)));
1769 return WERR_INTERNAL_ERROR;
1772 if (old_fti == NULL) {
1773 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1774 "returned success without returning forest trust information\n",
1775 __location__, __func__));
1777 return WERR_INTERNAL_ERROR;
1784 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1786 if (!NT_STATUS_IS_OK(status)) {
1787 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1788 __location__, __func__, domain->name, nt_errstr(status)));
1790 return ntstatus_to_werror(status);
1793 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1795 &trusted_domain_name_l,
1796 LSA_FOREST_TRUST_DOMAIN_INFO,
1798 0, /* check_only=0 => store it! */
1801 if (!NT_STATUS_IS_OK(status)) {
1802 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1803 __location__, __func__, domain->name, nt_errstr(status)));
1805 return WERR_INTERNAL_ERROR;
1807 if (!NT_STATUS_IS_OK(result)) {
1808 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1809 __location__, __func__, domain->name, nt_errstr(result)));
1811 return ntstatus_to_werror(result);
1815 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1820 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1822 struct winbindd_domain *domain;
1824 struct rpc_pipe_client *netlogon_pipe;
1825 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1827 DEBUG(5, ("_winbind_SendToSam received\n"));
1828 domain = wb_child_domain();
1829 if (domain == NULL) {
1830 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1833 status = cm_connect_netlogon_secure(domain,
1835 &netlogon_creds_ctx);
1836 if (!NT_STATUS_IS_OK(status)) {
1837 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1841 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1842 netlogon_pipe->binding_handle,