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 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
47 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
48 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
50 invalidate_cm_connection(domain);
51 /* We invalidated the connection. */
57 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
59 struct winbindd_domain *domain = wb_child_domain();
62 enum lsa_SidType type;
66 return NT_STATUS_REQUEST_NOT_ACCEPTED;
69 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
70 &dom_name, &name, &type);
71 reset_cm_connection_on_error(domain, status);
72 if (!NT_STATUS_IS_OK(status)) {
76 *r->out.domain = dom_name;
82 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
84 struct winbindd_domain *domain = wb_child_domain();
85 struct lsa_RefDomainList *domains = r->out.domains;
89 return NT_STATUS_REQUEST_NOT_ACCEPTED;
93 * This breaks the winbindd_domain->methods abstraction: This
94 * is only called for remote domains, and both winbindd_msrpc
95 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
96 * done at the wbint RPC layer.
98 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
99 &domains, &r->out.names);
101 if (domains != NULL) {
102 r->out.domains = domains;
105 reset_cm_connection_on_error(domain, status);
109 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
111 struct winbindd_domain *domain = wb_child_domain();
114 if (domain == NULL) {
115 return NT_STATUS_REQUEST_NOT_ACCEPTED;
118 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
119 r->in.name, r->in.flags,
120 r->out.sid, r->out.type);
121 reset_cm_connection_on_error(domain, status);
125 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
126 struct wbint_Sids2UnixIDs *r)
130 struct lsa_DomainInfo *d;
131 struct wbint_TransID *ids;
134 struct id_map **id_map_ptrs = NULL;
135 struct idmap_domain *dom;
136 NTSTATUS status = NT_STATUS_NO_MEMORY;
138 if (r->in.domains->count != 1) {
139 return NT_STATUS_INVALID_PARAMETER;
142 d = &r->in.domains->domains[0];
143 ids = r->in.ids->ids;
144 num_ids = r->in.ids->num_ids;
146 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
148 DEBUG(10, ("idmap domain %s:%s not found\n",
149 d->name.string, sid_string_dbg(d->sid)));
151 for (i=0; i<num_ids; i++) {
153 ids[i].xid = (struct unixid) {
155 .type = ID_TYPE_NOT_SPECIFIED
162 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
163 if (id_map_ptrs == NULL) {
168 * Convert the input data into a list of id_map structs
169 * suitable for handing in to the idmap sids_to_unixids
173 for (i=0; i<num_ids; i++) {
174 struct id_map *m = id_map_ptrs[i];
176 sid_compose(m->sid, d->sid, ids[i].rid);
177 m->status = ID_UNKNOWN;
178 m->xid = (struct unixid) { .type = ids[i].type };
181 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
183 if (!NT_STATUS_IS_OK(status)) {
184 DEBUG(10, ("sids_to_unixids returned %s\n",
190 * Extract the results for handing them back to the caller.
193 for (i=0; i<num_ids; i++) {
194 struct id_map *m = id_map_ptrs[i];
196 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
197 DBG_DEBUG("id %"PRIu32" is out of range "
198 "%"PRIu32"-%"PRIu32" for domain %s\n",
199 m->xid.id, dom->low_id, dom->high_id,
201 m->status = ID_UNMAPPED;
204 if (m->status == ID_MAPPED) {
207 ids[i].xid.id = UINT32_MAX;
208 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
214 status = NT_STATUS_NO_MEMORY;
216 TALLOC_FREE(id_map_ptrs);
220 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
221 struct wbint_UnixIDs2Sids *r)
223 struct id_map **maps;
227 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
229 return NT_STATUS_NO_MEMORY;
232 for (i=0; i<r->in.num_ids; i++) {
233 maps[i]->status = ID_UNKNOWN;
234 maps[i]->xid = r->in.xids[i];
237 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
239 if (!NT_STATUS_IS_OK(status)) {
244 for (i=0; i<r->in.num_ids; i++) {
245 r->out.xids[i] = maps[i]->xid;
246 sid_copy(&r->out.sids[i], maps[i]->sid);
254 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
259 status = idmap_allocate_uid(&xid);
260 if (!NT_STATUS_IS_OK(status)) {
263 *r->out.uid = xid.id;
267 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
272 status = idmap_allocate_gid(&xid);
273 if (!NT_STATUS_IS_OK(status)) {
276 *r->out.gid = xid.id;
280 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
282 struct idmap_domain *domain;
285 domain = idmap_find_domain(r->in.info->domain_name);
286 if ((domain == NULL) || (domain->query_user == NULL)) {
287 return NT_STATUS_REQUEST_NOT_ACCEPTED;
290 status = domain->query_user(domain, r->in.info);
294 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
295 struct wbint_LookupUserAliases *r)
297 struct winbindd_domain *domain = wb_child_domain();
300 if (domain == NULL) {
301 return NT_STATUS_REQUEST_NOT_ACCEPTED;
304 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
305 r->in.sids->num_sids,
307 &r->out.rids->num_rids,
309 reset_cm_connection_on_error(domain, status);
313 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
314 struct wbint_LookupUserGroups *r)
316 struct winbindd_domain *domain = wb_child_domain();
319 if (domain == NULL) {
320 return NT_STATUS_REQUEST_NOT_ACCEPTED;
323 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
324 &r->out.sids->num_sids,
326 reset_cm_connection_on_error(domain, status);
330 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
331 struct wbint_QuerySequenceNumber *r)
333 struct winbindd_domain *domain = wb_child_domain();
336 if (domain == NULL) {
337 return NT_STATUS_REQUEST_NOT_ACCEPTED;
340 status = wb_cache_sequence_number(domain, r->out.sequence);
341 reset_cm_connection_on_error(domain, status);
345 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
346 struct wbint_LookupGroupMembers *r)
348 struct winbindd_domain *domain = wb_child_domain();
349 uint32_t i, num_names;
350 struct dom_sid *sid_mem;
352 uint32_t *name_types;
355 if (domain == NULL) {
356 return NT_STATUS_REQUEST_NOT_ACCEPTED;
359 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
360 r->in.type, &num_names, &sid_mem,
361 &names, &name_types);
362 reset_cm_connection_on_error(domain, status);
363 if (!NT_STATUS_IS_OK(status)) {
367 r->out.members->num_principals = num_names;
368 r->out.members->principals = talloc_array(
369 r->out.members, struct wbint_Principal, num_names);
370 if (r->out.members->principals == NULL) {
371 return NT_STATUS_NO_MEMORY;
374 for (i=0; i<num_names; i++) {
375 struct wbint_Principal *m = &r->out.members->principals[i];
376 sid_copy(&m->sid, &sid_mem[i]);
377 m->name = talloc_move(r->out.members->principals, &names[i]);
378 m->type = (enum lsa_SidType)name_types[i];
384 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
385 struct wbint_QueryGroupList *r)
387 TALLOC_CTX *frame = NULL;
388 struct winbindd_domain *domain = wb_child_domain();
390 uint32_t num_local_groups = 0;
391 struct wb_acct_info *local_groups = NULL;
392 uint32_t num_dom_groups = 0;
393 struct wb_acct_info *dom_groups = NULL;
395 uint64_t num_total = 0;
396 struct wbint_Principal *result;
397 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
398 bool include_local_groups = false;
400 if (domain == NULL) {
401 return NT_STATUS_REQUEST_NOT_ACCEPTED;
404 frame = talloc_stackframe();
406 switch (lp_server_role()) {
407 case ROLE_ACTIVE_DIRECTORY_DC:
408 if (domain->internal) {
410 * we want to include local groups
411 * for BUILTIN and WORKGROUP
413 include_local_groups = true;
418 * We might include local groups in more
419 * setups later, but that requires more work
425 if (include_local_groups) {
426 status = wb_cache_enum_local_groups(domain, frame,
429 reset_cm_connection_on_error(domain, status);
430 if (!NT_STATUS_IS_OK(status)) {
435 status = wb_cache_enum_dom_groups(domain, frame,
438 reset_cm_connection_on_error(domain, status);
439 if (!NT_STATUS_IS_OK(status)) {
443 num_total = num_local_groups + num_dom_groups;
444 if (num_total > UINT32_MAX) {
445 status = NT_STATUS_INTERNAL_ERROR;
449 result = talloc_array(frame, struct wbint_Principal, num_total);
450 if (result == NULL) {
451 status = NT_STATUS_NO_MEMORY;
455 for (i = 0; i < num_local_groups; i++) {
456 struct wb_acct_info *lg = &local_groups[i];
457 struct wbint_Principal *rg = &result[ti++];
459 sid_compose(&rg->sid, &domain->sid, lg->rid);
460 rg->type = SID_NAME_ALIAS;
461 rg->name = talloc_strdup(result, lg->acct_name);
462 if (rg->name == NULL) {
463 status = NT_STATUS_NO_MEMORY;
467 num_local_groups = 0;
469 for (i = 0; i < num_dom_groups; i++) {
470 struct wb_acct_info *dg = &dom_groups[i];
471 struct wbint_Principal *rg = &result[ti++];
473 sid_compose(&rg->sid, &domain->sid, dg->rid);
474 rg->type = SID_NAME_DOM_GRP;
475 rg->name = talloc_strdup(result, dg->acct_name);
476 if (rg->name == NULL) {
477 status = NT_STATUS_NO_MEMORY;
483 r->out.groups->num_principals = ti;
484 r->out.groups->principals = talloc_move(r->out.groups, &result);
486 status = NT_STATUS_OK;
492 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
493 struct wbint_QueryUserRidList *r)
495 struct winbindd_domain *domain = wb_child_domain();
498 if (domain == NULL) {
499 return NT_STATUS_REQUEST_NOT_ACCEPTED;
503 * Right now this is overkill. We should add a backend call
504 * just querying the rids.
507 status = wb_cache_query_user_list(domain, p->mem_ctx,
509 reset_cm_connection_on_error(domain, status);
511 if (!NT_STATUS_IS_OK(status)) {
515 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
520 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
522 struct winbindd_domain *domain = wb_child_domain();
523 struct rpc_pipe_client *netlogon_pipe;
524 struct netr_DsRGetDCNameInfo *dc_info;
527 unsigned int orig_timeout;
528 struct dcerpc_binding_handle *b;
530 if (domain == NULL) {
531 return dsgetdcname(p->mem_ctx, server_messaging_context(),
532 r->in.domain_name, r->in.domain_guid,
533 r->in.site_name ? r->in.site_name : "",
538 status = cm_connect_netlogon(domain, &netlogon_pipe);
540 reset_cm_connection_on_error(domain, status);
541 if (!NT_STATUS_IS_OK(status)) {
542 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
546 b = netlogon_pipe->binding_handle;
548 /* This call can take a long time - allow the server to time out.
549 35 seconds should do it. */
551 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
553 if (domain->active_directory) {
554 status = dcerpc_netr_DsRGetDCName(b,
555 p->mem_ctx, domain->dcname,
556 r->in.domain_name, NULL, r->in.domain_guid,
557 r->in.flags, r->out.dc_info, &werr);
558 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
561 if (reset_cm_connection_on_error(domain, status)) {
563 status = cm_connect_netlogon(domain, &netlogon_pipe);
565 reset_cm_connection_on_error(domain, status);
566 if (!NT_STATUS_IS_OK(status)) {
567 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
571 b = netlogon_pipe->binding_handle;
573 /* This call can take a long time - allow the server to time out.
574 35 seconds should do it. */
576 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
581 * Fallback to less capable methods
584 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
585 if (dc_info == NULL) {
586 status = NT_STATUS_NO_MEMORY;
590 if (r->in.flags & DS_PDC_REQUIRED) {
591 status = dcerpc_netr_GetDcName(b,
592 p->mem_ctx, domain->dcname,
593 r->in.domain_name, &dc_info->dc_unc, &werr);
595 status = dcerpc_netr_GetAnyDCName(b,
596 p->mem_ctx, domain->dcname,
597 r->in.domain_name, &dc_info->dc_unc, &werr);
600 reset_cm_connection_on_error(domain, status);
601 if (!NT_STATUS_IS_OK(status)) {
602 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
606 if (!W_ERROR_IS_OK(werr)) {
607 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
609 status = werror_to_ntstatus(werr);
613 *r->out.dc_info = dc_info;
614 status = NT_STATUS_OK;
617 /* And restore our original timeout. */
618 rpccli_set_timeout(netlogon_pipe, orig_timeout);
623 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
625 struct winbindd_domain *domain = wb_child_domain();
628 enum lsa_SidType *types;
629 struct wbint_Principal *result;
633 if (domain == NULL) {
634 return NT_STATUS_REQUEST_NOT_ACCEPTED;
637 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
638 r->in.rids->rids, r->in.rids->num_rids,
639 &domain_name, &names, &types);
640 reset_cm_connection_on_error(domain, status);
641 if (!NT_STATUS_IS_OK(status)) {
645 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
647 result = talloc_array(p->mem_ctx, struct wbint_Principal,
648 r->in.rids->num_rids);
649 if (result == NULL) {
650 return NT_STATUS_NO_MEMORY;
653 for (i=0; i<r->in.rids->num_rids; i++) {
654 sid_compose(&result[i].sid, r->in.domain_sid,
655 r->in.rids->rids[i]);
656 result[i].type = types[i];
657 result[i].name = talloc_move(result, &names[i]);
662 r->out.names->num_principals = r->in.rids->num_rids;
663 r->out.names->principals = result;
667 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
668 struct wbint_CheckMachineAccount *r)
670 struct winbindd_domain *domain;
674 domain = wb_child_domain();
675 if (domain == NULL) {
676 return NT_STATUS_REQUEST_NOT_ACCEPTED;
680 invalidate_cm_connection(domain);
681 domain->conn.netlogon_force_reauth = true;
684 struct rpc_pipe_client *netlogon_pipe = NULL;
685 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
686 status = cm_connect_netlogon_secure(domain,
688 &netlogon_creds_ctx);
691 /* There is a race condition between fetching the trust account
692 password and the periodic machine password change. So it's
693 possible that the trust account password has been changed on us.
694 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
696 #define MAX_RETRIES 3
698 if ((num_retries < MAX_RETRIES)
699 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
704 if (!NT_STATUS_IS_OK(status)) {
705 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
709 /* Pass back result code - zero for success, other values for
710 specific failures. */
712 DEBUG(3,("domain %s secret is %s\n", domain->name,
713 NT_STATUS_IS_OK(status) ? "good" : "bad"));
716 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
717 ("Checking the trust account password for domain %s returned %s\n",
718 domain->name, nt_errstr(status)));
723 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
724 struct wbint_ChangeMachineAccount *r)
726 struct messaging_context *msg_ctx = server_messaging_context();
727 struct winbindd_domain *domain;
729 struct rpc_pipe_client *netlogon_pipe = NULL;
730 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
732 domain = wb_child_domain();
733 if (domain == NULL) {
734 return NT_STATUS_REQUEST_NOT_ACCEPTED;
737 status = cm_connect_netlogon_secure(domain,
739 &netlogon_creds_ctx);
740 if (!NT_STATUS_IS_OK(status)) {
741 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
745 status = trust_pw_change(netlogon_creds_ctx,
747 netlogon_pipe->binding_handle,
752 /* Pass back result code - zero for success, other values for
753 specific failures. */
755 DEBUG(3,("domain %s secret %s\n", domain->name,
756 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
759 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
760 ("Changing the trust account password for domain %s returned %s\n",
761 domain->name, nt_errstr(status)));
766 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
769 struct winbindd_domain *domain;
770 struct rpc_pipe_client *netlogon_pipe;
771 union netr_CONTROL_QUERY_INFORMATION info;
773 fstring logon_server;
774 struct dcerpc_binding_handle *b;
777 domain = wb_child_domain();
778 if (domain == NULL) {
779 return NT_STATUS_REQUEST_NOT_ACCEPTED;
783 status = cm_connect_netlogon(domain, &netlogon_pipe);
784 reset_cm_connection_on_error(domain, status);
785 if (!NT_STATUS_IS_OK(status)) {
786 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
791 b = netlogon_pipe->binding_handle;
793 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
794 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
795 if (*r->out.dcname == NULL) {
796 DEBUG(2, ("Could not allocate memory\n"));
797 return NT_STATUS_NO_MEMORY;
801 * This provokes a WERR_NOT_SUPPORTED error message. This is
802 * documented in the wspp docs. I could not get a successful
803 * call to work, but the main point here is testing that the
804 * netlogon pipe works.
806 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
807 logon_server, NETLOGON_CONTROL_QUERY,
810 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
811 DEBUG(10, ("Session might have expired. "
812 "Reconnect and retry once.\n"));
813 invalidate_cm_connection(domain);
818 reset_cm_connection_on_error(domain, status);
819 if (!NT_STATUS_IS_OK(status)) {
820 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
825 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
826 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
827 "WERR_NOT_SUPPORTED\n",
829 return werror_to_ntstatus(werr);
832 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
836 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
837 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
839 struct winbindd_domain *domain;
841 struct rpc_pipe_client *netlogon_pipe = NULL;
842 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
844 domain = wb_child_domain();
845 if (domain == NULL) {
846 return NT_STATUS_REQUEST_NOT_ACCEPTED;
849 status = cm_connect_netlogon_secure(domain,
851 &netlogon_creds_ctx);
852 if (!NT_STATUS_IS_OK(status)) {
853 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
857 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
858 netlogon_pipe->binding_handle,
863 /* Pass back result code - zero for success, other values for
864 specific failures. */
866 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
867 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
870 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
871 ("Update of DNS records via RW DC %s returned %s\n",
872 domain->name, nt_errstr(status)));
877 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
878 struct winbind_SamLogon *r)
880 struct winbindd_domain *domain;
882 struct netr_IdentityInfo *identity_info = NULL;
883 const uint8_t chal_zero[8] = {0, };
884 const uint8_t *challenge = chal_zero;
885 DATA_BLOB lm_response, nt_response;
887 uint16_t validation_level;
888 union netr_Validation *validation = NULL;
889 bool interactive = false;
891 domain = wb_child_domain();
892 if (domain == NULL) {
893 return NT_STATUS_REQUEST_NOT_ACCEPTED;
896 switch (r->in.validation_level) {
901 return NT_STATUS_REQUEST_NOT_ACCEPTED;
904 switch (r->in.logon_level) {
905 case NetlogonInteractiveInformation:
906 case NetlogonServiceInformation:
907 case NetlogonInteractiveTransitiveInformation:
908 case NetlogonServiceTransitiveInformation:
909 if (r->in.logon.password == NULL) {
910 return NT_STATUS_REQUEST_NOT_ACCEPTED;
914 identity_info = &r->in.logon.password->identity_info;
916 challenge = chal_zero;
917 lm_response = data_blob_talloc(p->mem_ctx,
918 r->in.logon.password->lmpassword.hash,
919 sizeof(r->in.logon.password->lmpassword.hash));
920 nt_response = data_blob_talloc(p->mem_ctx,
921 r->in.logon.password->ntpassword.hash,
922 sizeof(r->in.logon.password->ntpassword.hash));
925 case NetlogonNetworkInformation:
926 case NetlogonNetworkTransitiveInformation:
927 if (r->in.logon.network == NULL) {
928 return NT_STATUS_REQUEST_NOT_ACCEPTED;
932 identity_info = &r->in.logon.network->identity_info;
934 challenge = r->in.logon.network->challenge;
935 lm_response = data_blob_talloc(p->mem_ctx,
936 r->in.logon.network->lm.data,
937 r->in.logon.network->lm.length);
938 nt_response = data_blob_talloc(p->mem_ctx,
939 r->in.logon.network->nt.data,
940 r->in.logon.network->nt.length);
943 case NetlogonGenericInformation:
944 if (r->in.logon.generic == NULL) {
945 return NT_STATUS_REQUEST_NOT_ACCEPTED;
948 identity_info = &r->in.logon.generic->identity_info;
950 * Not implemented here...
952 return NT_STATUS_REQUEST_NOT_ACCEPTED;
955 return NT_STATUS_REQUEST_NOT_ACCEPTED;
958 status = winbind_dual_SamLogon(domain, p->mem_ctx,
960 identity_info->parameter_control,
961 identity_info->account_name.string,
962 identity_info->domain_name.string,
963 identity_info->workstation.string,
965 lm_response, nt_response,
966 &r->out.authoritative,
971 if (!NT_STATUS_IS_OK(status)) {
974 switch (r->in.validation_level) {
976 status = map_validation_to_info3(p->mem_ctx,
979 &r->out.validation.sam3);
980 TALLOC_FREE(validation);
981 if (!NT_STATUS_IS_OK(status)) {
986 status = map_validation_to_info6(p->mem_ctx,
989 &r->out.validation.sam6);
990 TALLOC_FREE(validation);
991 if (!NT_STATUS_IS_OK(status)) {
997 smb_panic(__location__);
998 return NT_STATUS_INTERNAL_ERROR;
1001 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1002 struct winbindd_domain *domain,
1003 struct winbind_LogonControl *r)
1006 struct rpc_pipe_client *netlogon_pipe = NULL;
1007 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1008 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1009 WERROR check_result = WERR_INTERNAL_ERROR;
1011 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1012 if (info2 == NULL) {
1013 return WERR_NOT_ENOUGH_MEMORY;
1016 if (domain->internal) {
1017 check_result = WERR_OK;
1022 * For now we just force a reconnect
1024 * TODO: take care of the optional '\dcname'
1026 invalidate_cm_connection(domain);
1027 domain->conn.netlogon_force_reauth = true;
1028 status = cm_connect_netlogon_secure(domain,
1030 &netlogon_creds_ctx);
1031 reset_cm_connection_on_error(domain, status);
1032 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1033 status = NT_STATUS_NO_LOGON_SERVERS;
1035 if (!NT_STATUS_IS_OK(status)) {
1036 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1037 __func__, domain->name, domain->alt_name,
1038 nt_errstr(status)));
1040 * Here we return a top level error!
1041 * This is different than TC_QUERY or TC_VERIFY.
1043 return ntstatus_to_werror(status);
1045 check_result = WERR_OK;
1048 info2->pdc_connection_status = WERR_OK;
1049 if (domain->dcname != NULL) {
1050 info2->flags |= NETLOGON_HAS_IP;
1051 info2->flags |= NETLOGON_HAS_TIMESERV;
1052 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1054 if (info2->trusted_dc_name == NULL) {
1055 return WERR_NOT_ENOUGH_MEMORY;
1058 info2->trusted_dc_name = talloc_strdup(info2, "");
1059 if (info2->trusted_dc_name == NULL) {
1060 return WERR_NOT_ENOUGH_MEMORY;
1063 info2->tc_connection_status = check_result;
1065 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1066 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1067 "pdc_connection[%s] tc_connection[%s]\n",
1068 __func__, domain->name, domain->alt_name,
1070 win_errstr(info2->pdc_connection_status),
1071 win_errstr(info2->tc_connection_status)));
1074 r->out.query->info2 = info2;
1076 DEBUG(5, ("%s: succeeded.\n", __func__));
1080 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1081 struct winbindd_domain *domain,
1082 struct winbind_LogonControl *r)
1085 struct rpc_pipe_client *netlogon_pipe = NULL;
1086 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1087 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1088 WERROR check_result = WERR_INTERNAL_ERROR;
1090 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1091 if (info2 == NULL) {
1092 return WERR_NOT_ENOUGH_MEMORY;
1095 if (domain->internal) {
1096 check_result = WERR_OK;
1100 status = cm_connect_netlogon_secure(domain,
1102 &netlogon_creds_ctx);
1103 reset_cm_connection_on_error(domain, status);
1104 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1105 status = NT_STATUS_NO_LOGON_SERVERS;
1107 if (!NT_STATUS_IS_OK(status)) {
1108 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1109 nt_errstr(status)));
1110 check_result = ntstatus_to_werror(status);
1113 check_result = WERR_OK;
1116 info2->pdc_connection_status = WERR_OK;
1117 if (domain->dcname != NULL) {
1118 info2->flags |= NETLOGON_HAS_IP;
1119 info2->flags |= NETLOGON_HAS_TIMESERV;
1120 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1122 if (info2->trusted_dc_name == NULL) {
1123 return WERR_NOT_ENOUGH_MEMORY;
1126 info2->trusted_dc_name = talloc_strdup(info2, "");
1127 if (info2->trusted_dc_name == NULL) {
1128 return WERR_NOT_ENOUGH_MEMORY;
1131 info2->tc_connection_status = check_result;
1133 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1134 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1135 "pdc_connection[%s] tc_connection[%s]\n",
1136 __func__, domain->name, domain->alt_name,
1138 win_errstr(info2->pdc_connection_status),
1139 win_errstr(info2->tc_connection_status)));
1142 r->out.query->info2 = info2;
1144 DEBUG(5, ("%s: succeeded.\n", __func__));
1148 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1149 struct winbindd_domain *domain,
1150 struct winbind_LogonControl *r)
1152 TALLOC_CTX *frame = talloc_stackframe();
1155 struct lsa_String trusted_domain_name = {};
1156 struct lsa_StringLarge trusted_domain_name_l = {};
1157 struct rpc_pipe_client *local_lsa_pipe = NULL;
1158 struct policy_handle local_lsa_policy = {};
1159 struct dcerpc_binding_handle *local_lsa = NULL;
1160 struct rpc_pipe_client *netlogon_pipe = NULL;
1161 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1162 struct cli_credentials *creds = NULL;
1163 struct samr_Password *cur_nt_hash = NULL;
1164 uint32_t trust_attributes = 0;
1165 struct samr_Password new_owf_password = {};
1167 struct samr_Password old_owf_password = {};
1169 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1170 bool fetch_fti = false;
1171 struct lsa_ForestTrustInformation *new_fti = NULL;
1172 struct netr_TrustInfo *trust_info = NULL;
1173 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1174 struct dcerpc_binding_handle *b = NULL;
1175 WERROR check_result = WERR_INTERNAL_ERROR;
1176 WERROR verify_result = WERR_INTERNAL_ERROR;
1179 trusted_domain_name.string = domain->name;
1180 trusted_domain_name_l.string = domain->name;
1182 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1183 if (info2 == NULL) {
1185 return WERR_NOT_ENOUGH_MEMORY;
1188 if (domain->internal) {
1189 check_result = WERR_OK;
1193 status = pdb_get_trust_credentials(domain->name,
1197 if (NT_STATUS_IS_OK(status)) {
1198 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1202 if (!domain->primary) {
1203 union lsa_TrustedDomainInfo *tdi = NULL;
1205 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1207 if (!NT_STATUS_IS_OK(status)) {
1208 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1209 __location__, __func__, nt_errstr(status)));
1211 return WERR_INTERNAL_ERROR;
1213 local_lsa = local_lsa_pipe->binding_handle;
1215 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1217 &trusted_domain_name,
1218 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1220 if (!NT_STATUS_IS_OK(status)) {
1221 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1222 __location__, __func__, domain->name, nt_errstr(status)));
1224 return WERR_INTERNAL_ERROR;
1226 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1227 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1228 __location__, __func__, domain->name));
1230 return WERR_NO_SUCH_DOMAIN;
1232 if (!NT_STATUS_IS_OK(result)) {
1233 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1234 __location__, __func__, domain->name, nt_errstr(result)));
1236 return WERR_INTERNAL_ERROR;
1239 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1240 "returned no trusted domain information\n",
1241 __location__, __func__));
1243 return WERR_INTERNAL_ERROR;
1246 local_tdo = &tdi->info_ex;
1247 trust_attributes = local_tdo->trust_attributes;
1250 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1251 struct lsa_ForestTrustInformation *old_fti = NULL;
1253 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1255 &trusted_domain_name,
1256 LSA_FOREST_TRUST_DOMAIN_INFO,
1258 if (!NT_STATUS_IS_OK(status)) {
1259 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1260 __location__, __func__, domain->name, nt_errstr(status)));
1262 return WERR_INTERNAL_ERROR;
1264 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1265 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1266 __func__, domain->name));
1269 result = NT_STATUS_OK;
1271 if (!NT_STATUS_IS_OK(result)) {
1272 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1273 __location__, __func__, domain->name, nt_errstr(result)));
1275 return WERR_INTERNAL_ERROR;
1278 TALLOC_FREE(old_fti);
1282 status = cm_connect_netlogon_secure(domain,
1284 &netlogon_creds_ctx);
1285 reset_cm_connection_on_error(domain, status);
1286 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1287 status = NT_STATUS_NO_LOGON_SERVERS;
1289 if (!NT_STATUS_IS_OK(status)) {
1290 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1291 nt_errstr(status)));
1292 check_result = ntstatus_to_werror(status);
1295 check_result = WERR_OK;
1296 b = netlogon_pipe->binding_handle;
1298 if (cur_nt_hash == NULL) {
1299 verify_result = WERR_NO_TRUST_LSA_SECRET;
1304 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1307 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1308 status = NT_STATUS_NOT_SUPPORTED;
1310 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1312 status = NT_STATUS_OK;
1314 if (!NT_STATUS_IS_OK(status)) {
1315 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1316 invalidate_cm_connection(domain);
1320 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1322 domain->name, nt_errstr(status)));
1323 check_result = ntstatus_to_werror(status);
1328 if (new_fti != NULL) {
1329 struct lsa_ForestTrustInformation old_fti = {};
1330 struct lsa_ForestTrustInformation *merged_fti = NULL;
1331 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1333 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1336 if (!NT_STATUS_IS_OK(status)) {
1337 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1338 __location__, __func__,
1339 domain->name, nt_errstr(status)));
1341 return ntstatus_to_werror(status);
1344 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1346 &trusted_domain_name_l,
1347 LSA_FOREST_TRUST_DOMAIN_INFO,
1349 0, /* check_only=0 => store it! */
1352 if (!NT_STATUS_IS_OK(status)) {
1353 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1354 __location__, __func__, domain->name, nt_errstr(status)));
1356 return WERR_INTERNAL_ERROR;
1358 if (!NT_STATUS_IS_OK(result)) {
1359 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1360 __location__, __func__, domain->name, nt_errstr(result)));
1362 return ntstatus_to_werror(result);
1366 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1371 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1372 status = NT_STATUS_NOT_SUPPORTED;
1374 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1375 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1376 nt_errstr(status)));
1377 verify_result = WERR_OK;
1380 if (!NT_STATUS_IS_OK(status)) {
1381 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1382 invalidate_cm_connection(domain);
1386 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1387 nt_errstr(status)));
1389 if (!dcerpc_binding_handle_is_connected(b)) {
1390 check_result = ntstatus_to_werror(status);
1393 verify_result = ntstatus_to_werror(status);
1398 if (trust_info != NULL && trust_info->count >= 1) {
1399 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1401 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1402 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1407 cmp_new = memcmp(new_owf_password.hash,
1409 sizeof(cur_nt_hash->hash));
1410 cmp_old = memcmp(old_owf_password.hash,
1412 sizeof(cur_nt_hash->hash));
1413 if (cmp_new != 0 && cmp_old != 0) {
1414 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1415 "any password known to dcname[%s]\n",
1416 __func__, domain->name, domain->alt_name,
1418 verify_result = WERR_WRONG_PASSWORD;
1423 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1424 "against the old password known to dcname[%s]\n",
1425 __func__, domain->name, domain->alt_name,
1429 verify_result = WERR_OK;
1433 verify_result = check_result;
1435 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1436 info2->pdc_connection_status = verify_result;
1437 if (domain->dcname != NULL) {
1438 info2->flags |= NETLOGON_HAS_IP;
1439 info2->flags |= NETLOGON_HAS_TIMESERV;
1440 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1442 if (info2->trusted_dc_name == NULL) {
1444 return WERR_NOT_ENOUGH_MEMORY;
1447 info2->trusted_dc_name = talloc_strdup(info2, "");
1448 if (info2->trusted_dc_name == NULL) {
1450 return WERR_NOT_ENOUGH_MEMORY;
1453 info2->tc_connection_status = check_result;
1455 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1456 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1457 "pdc_connection[%s] tc_connection[%s]\n",
1458 __func__, domain->name, domain->alt_name,
1460 win_errstr(info2->pdc_connection_status),
1461 win_errstr(info2->tc_connection_status)));
1464 r->out.query->info2 = info2;
1466 DEBUG(5, ("%s: succeeded.\n", __func__));
1471 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1472 struct winbindd_domain *domain,
1473 struct winbind_LogonControl *r)
1475 struct messaging_context *msg_ctx = server_messaging_context();
1477 struct rpc_pipe_client *netlogon_pipe = NULL;
1478 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1479 struct cli_credentials *creds = NULL;
1480 struct samr_Password *cur_nt_hash = NULL;
1481 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1482 struct dcerpc_binding_handle *b;
1483 WERROR change_result = WERR_OK;
1486 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1487 if (info1 == NULL) {
1488 return WERR_NOT_ENOUGH_MEMORY;
1491 if (domain->internal) {
1492 return WERR_NOT_SUPPORTED;
1495 status = pdb_get_trust_credentials(domain->name,
1499 if (NT_STATUS_IS_OK(status)) {
1500 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1505 status = cm_connect_netlogon_secure(domain,
1507 &netlogon_creds_ctx);
1508 reset_cm_connection_on_error(domain, status);
1509 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1510 status = NT_STATUS_NO_LOGON_SERVERS;
1512 if (!NT_STATUS_IS_OK(status)) {
1513 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1514 __func__, domain->name, domain->alt_name,
1515 nt_errstr(status)));
1517 * Here we return a top level error!
1518 * This is different than TC_QUERY or TC_VERIFY.
1520 return ntstatus_to_werror(status);
1522 b = netlogon_pipe->binding_handle;
1524 if (cur_nt_hash == NULL) {
1525 change_result = WERR_NO_TRUST_LSA_SECRET;
1528 TALLOC_FREE(cur_nt_hash);
1530 status = trust_pw_change(netlogon_creds_ctx,
1531 msg_ctx, b, domain->name,
1534 if (!NT_STATUS_IS_OK(status)) {
1535 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1536 invalidate_cm_connection(domain);
1541 DEBUG(1, ("trust_pw_change(%s): %s\n",
1542 domain->name, nt_errstr(status)));
1544 change_result = ntstatus_to_werror(status);
1548 change_result = WERR_OK;
1551 info1->pdc_connection_status = change_result;
1553 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1554 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1555 "pdc_connection[%s]\n",
1556 __func__, domain->name, domain->alt_name,
1558 win_errstr(info1->pdc_connection_status)));
1561 r->out.query->info1 = info1;
1563 DEBUG(5, ("%s: succeeded.\n", __func__));
1567 WERROR _winbind_LogonControl(struct pipes_struct *p,
1568 struct winbind_LogonControl *r)
1570 struct winbindd_domain *domain;
1572 domain = wb_child_domain();
1573 if (domain == NULL) {
1574 return WERR_NO_SUCH_DOMAIN;
1577 switch (r->in.function_code) {
1578 case NETLOGON_CONTROL_REDISCOVER:
1579 if (r->in.level != 2) {
1580 return WERR_INVALID_PARAMETER;
1582 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1583 case NETLOGON_CONTROL_TC_QUERY:
1584 if (r->in.level != 2) {
1585 return WERR_INVALID_PARAMETER;
1587 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1588 case NETLOGON_CONTROL_TC_VERIFY:
1589 if (r->in.level != 2) {
1590 return WERR_INVALID_PARAMETER;
1592 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1593 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1594 if (r->in.level != 1) {
1595 return WERR_INVALID_PARAMETER;
1597 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1602 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1603 __func__, r->in.function_code));
1604 return WERR_NOT_SUPPORTED;
1607 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1608 struct winbind_GetForestTrustInformation *r)
1610 TALLOC_CTX *frame = talloc_stackframe();
1611 NTSTATUS status, result;
1612 struct winbindd_domain *domain;
1613 struct rpc_pipe_client *netlogon_pipe = NULL;
1614 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1615 struct dcerpc_binding_handle *b;
1617 struct lsa_String trusted_domain_name = {};
1618 struct lsa_StringLarge trusted_domain_name_l = {};
1619 union lsa_TrustedDomainInfo *tdi = NULL;
1620 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1621 struct lsa_ForestTrustInformation _old_fti = {};
1622 struct lsa_ForestTrustInformation *old_fti = NULL;
1623 struct lsa_ForestTrustInformation *new_fti = NULL;
1624 struct lsa_ForestTrustInformation *merged_fti = NULL;
1625 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1626 bool update_fti = false;
1627 struct rpc_pipe_client *local_lsa_pipe;
1628 struct policy_handle local_lsa_policy;
1629 struct dcerpc_binding_handle *local_lsa = NULL;
1631 domain = wb_child_domain();
1632 if (domain == NULL) {
1634 return WERR_NO_SUCH_DOMAIN;
1638 * checking for domain->internal and domain->primary
1639 * makes sure we only do some work when running as DC.
1642 if (domain->internal) {
1644 return WERR_NO_SUCH_DOMAIN;
1647 if (domain->primary) {
1649 return WERR_NO_SUCH_DOMAIN;
1652 trusted_domain_name.string = domain->name;
1653 trusted_domain_name_l.string = domain->name;
1655 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1657 if (!NT_STATUS_IS_OK(status)) {
1658 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1659 __location__, __func__, nt_errstr(status)));
1661 return WERR_INTERNAL_ERROR;
1663 local_lsa = local_lsa_pipe->binding_handle;
1665 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1667 &trusted_domain_name,
1668 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1670 if (!NT_STATUS_IS_OK(status)) {
1671 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1672 __location__, __func__, domain->name, nt_errstr(status)));
1674 return WERR_INTERNAL_ERROR;
1676 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1677 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1678 __location__, __func__, domain->name));
1680 return WERR_NO_SUCH_DOMAIN;
1682 if (!NT_STATUS_IS_OK(result)) {
1683 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1684 __location__, __func__, domain->name, nt_errstr(result)));
1686 return WERR_INTERNAL_ERROR;
1689 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1690 "returned no trusted domain information\n",
1691 __location__, __func__));
1693 return WERR_INTERNAL_ERROR;
1696 tdo = &tdi->info_ex;
1698 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1699 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1700 __func__, tdo->netbios_name.string,
1701 tdo->domain_name.string,
1702 (unsigned)tdo->trust_attributes));
1704 return WERR_NO_SUCH_DOMAIN;
1707 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1709 return WERR_INVALID_FLAGS;
1713 status = cm_connect_netlogon_secure(domain,
1715 &netlogon_creds_ctx);
1716 reset_cm_connection_on_error(domain, status);
1717 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1718 status = NT_STATUS_NO_LOGON_SERVERS;
1720 if (!NT_STATUS_IS_OK(status)) {
1721 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1722 nt_errstr(status)));
1724 return ntstatus_to_werror(status);
1726 b = netlogon_pipe->binding_handle;
1728 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1731 if (!NT_STATUS_IS_OK(status)) {
1732 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1733 invalidate_cm_connection(domain);
1737 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1738 domain->name, nt_errstr(status)));
1740 return ntstatus_to_werror(status);
1743 *r->out.forest_trust_info = new_fti;
1745 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1749 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1751 &trusted_domain_name,
1752 LSA_FOREST_TRUST_DOMAIN_INFO,
1754 if (!NT_STATUS_IS_OK(status)) {
1755 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1756 __location__, __func__, domain->name, nt_errstr(status)));
1758 return WERR_INTERNAL_ERROR;
1760 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1761 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1762 __func__, domain->name));
1764 old_fti = &_old_fti;
1765 result = NT_STATUS_OK;
1767 if (!NT_STATUS_IS_OK(result)) {
1768 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1769 __location__, __func__, domain->name, nt_errstr(result)));
1771 return WERR_INTERNAL_ERROR;
1774 if (old_fti == NULL) {
1775 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1776 "returned success without returning forest trust information\n",
1777 __location__, __func__));
1779 return WERR_INTERNAL_ERROR;
1786 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1788 if (!NT_STATUS_IS_OK(status)) {
1789 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1790 __location__, __func__, domain->name, nt_errstr(status)));
1792 return ntstatus_to_werror(status);
1795 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1797 &trusted_domain_name_l,
1798 LSA_FOREST_TRUST_DOMAIN_INFO,
1800 0, /* check_only=0 => store it! */
1803 if (!NT_STATUS_IS_OK(status)) {
1804 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1805 __location__, __func__, domain->name, nt_errstr(status)));
1807 return WERR_INTERNAL_ERROR;
1809 if (!NT_STATUS_IS_OK(result)) {
1810 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1811 __location__, __func__, domain->name, nt_errstr(result)));
1813 return ntstatus_to_werror(result);
1817 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1822 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1824 struct winbindd_domain *domain;
1826 struct rpc_pipe_client *netlogon_pipe;
1827 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1829 DEBUG(5, ("_winbind_SendToSam received\n"));
1830 domain = wb_child_domain();
1831 if (domain == NULL) {
1832 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1835 status = cm_connect_netlogon_secure(domain,
1837 &netlogon_creds_ctx);
1838 if (!NT_STATUS_IS_OK(status)) {
1839 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1843 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1844 netlogon_pipe->binding_handle,