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/rpc/dcesrv_core.h"
29 #include "librpc/gen_ndr/ndr_winbind.h"
30 #include "librpc/gen_ndr/ndr_winbind_scompat.h"
31 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "../librpc/gen_ndr/ndr_lsa_c.h"
34 #include "../libcli/security/security.h"
35 #include "../libcli/auth/netlogon_creds_cli.h"
37 #include "../source4/dsdb/samdb/samdb.h"
38 #include "rpc_client/cli_netlogon.h"
39 #include "rpc_client/util_netlogon.h"
40 #include "libsmb/dsgetdcname.h"
41 #include "lib/global_contexts.h"
43 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
45 *r->out.out_data = r->in.in_data;
48 bool reset_cm_connection_on_error(struct winbindd_domain *domain,
49 struct dcerpc_binding_handle *b,
52 if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) ||
53 NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR) ||
54 NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
55 invalidate_cm_connection(domain);
56 domain->conn.netlogon_force_reauth = true;
60 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) ||
61 NT_STATUS_EQUAL(status, NT_STATUS_IO_DEVICE_ERROR))
63 invalidate_cm_connection(domain);
64 /* We invalidated the connection. */
68 if (b != NULL && !dcerpc_binding_handle_is_connected(b)) {
69 invalidate_cm_connection(domain);
76 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
78 struct winbindd_domain *domain = wb_child_domain();
81 enum lsa_SidType type;
85 return NT_STATUS_REQUEST_NOT_ACCEPTED;
88 status = wb_cache_sid_to_name(domain, p->mem_ctx, r->in.sid,
89 &dom_name, &name, &type);
90 reset_cm_connection_on_error(domain, NULL, status);
91 if (!NT_STATUS_IS_OK(status)) {
95 *r->out.domain = dom_name;
101 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
103 struct winbindd_domain *domain = wb_child_domain();
104 struct lsa_RefDomainList *domains = r->out.domains;
108 if (domain == NULL) {
109 return NT_STATUS_REQUEST_NOT_ACCEPTED;
113 * This breaks the winbindd_domain->methods abstraction: This
114 * is only called for remote domains, and both winbindd_msrpc
115 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
116 * done at the wbint RPC layer.
119 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
120 &domains, &r->out.names);
122 if (domains != NULL) {
123 r->out.domains = domains;
126 if (!retry && reset_cm_connection_on_error(domain, NULL, status)) {
134 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
136 struct winbindd_domain *domain = wb_child_domain();
139 if (domain == NULL) {
140 return NT_STATUS_REQUEST_NOT_ACCEPTED;
143 status = wb_cache_name_to_sid(domain, p->mem_ctx, r->in.domain,
144 r->in.name, r->in.flags,
145 r->out.sid, r->out.type);
146 reset_cm_connection_on_error(domain, NULL, status);
150 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
151 struct wbint_Sids2UnixIDs *r)
155 struct lsa_DomainInfo *d;
156 struct wbint_TransID *ids;
159 struct id_map **id_map_ptrs = NULL;
160 struct idmap_domain *dom;
161 NTSTATUS status = NT_STATUS_NO_MEMORY;
163 if (r->in.domains->count != 1) {
164 return NT_STATUS_INVALID_PARAMETER;
167 d = &r->in.domains->domains[0];
168 ids = r->in.ids->ids;
169 num_ids = r->in.ids->num_ids;
171 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
173 struct dom_sid_buf buf;
174 DEBUG(10, ("idmap domain %s:%s not found\n",
176 dom_sid_str_buf(d->sid, &buf)));
178 for (i=0; i<num_ids; i++) {
180 ids[i].xid = (struct unixid) {
182 .type = ID_TYPE_NOT_SPECIFIED
189 id_map_ptrs = id_map_ptrs_init(talloc_tos(), num_ids);
190 if (id_map_ptrs == NULL) {
195 * Convert the input data into a list of id_map structs
196 * suitable for handing in to the idmap sids_to_unixids
200 for (i=0; i<num_ids; i++) {
201 struct id_map *m = id_map_ptrs[i];
203 sid_compose(m->sid, d->sid, ids[i].rid);
204 m->status = ID_UNKNOWN;
205 m->xid = (struct unixid) { .type = ids[i].type_hint };
208 status = dom->methods->sids_to_unixids(dom, id_map_ptrs);
210 if (NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
212 * This is okay. We need to transfer the mapped ones
213 * up to our caller. The individual mappings carry the
214 * information whether they are mapped or not.
216 status = NT_STATUS_OK;
219 if (!NT_STATUS_IS_OK(status)) {
220 DEBUG(10, ("sids_to_unixids returned %s\n",
226 * Extract the results for handing them back to the caller.
229 for (i=0; i<num_ids; i++) {
230 struct id_map *m = id_map_ptrs[i];
232 if (m->status == ID_REQUIRE_TYPE) {
233 ids[i].xid.id = UINT32_MAX;
234 ids[i].xid.type = ID_TYPE_WB_REQUIRE_TYPE;
238 if (!idmap_unix_id_is_in_range(m->xid.id, dom)) {
239 DBG_DEBUG("id %"PRIu32" is out of range "
240 "%"PRIu32"-%"PRIu32" for domain %s\n",
241 m->xid.id, dom->low_id, dom->high_id,
243 m->status = ID_UNMAPPED;
246 if (m->status == ID_MAPPED) {
249 ids[i].xid.id = UINT32_MAX;
250 ids[i].xid.type = ID_TYPE_NOT_SPECIFIED;
256 status = NT_STATUS_NO_MEMORY;
258 TALLOC_FREE(id_map_ptrs);
262 NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p,
263 struct wbint_UnixIDs2Sids *r)
265 struct id_map **maps;
269 maps = id_map_ptrs_init(talloc_tos(), r->in.num_ids);
271 return NT_STATUS_NO_MEMORY;
274 for (i=0; i<r->in.num_ids; i++) {
275 maps[i]->status = ID_UNKNOWN;
276 maps[i]->xid = r->in.xids[i];
279 status = idmap_backend_unixids_to_sids(maps, r->in.domain_name,
281 if (!NT_STATUS_IS_OK(status)) {
286 for (i=0; i<r->in.num_ids; i++) {
287 if (maps[i]->status == ID_MAPPED) {
288 r->out.xids[i] = maps[i]->xid;
289 sid_copy(&r->out.sids[i], maps[i]->sid);
291 r->out.sids[i] = (struct dom_sid) { 0 };
300 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
305 status = idmap_allocate_uid(&xid);
306 if (!NT_STATUS_IS_OK(status)) {
309 *r->out.uid = xid.id;
313 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
318 status = idmap_allocate_gid(&xid);
319 if (!NT_STATUS_IS_OK(status)) {
322 *r->out.gid = xid.id;
326 NTSTATUS _wbint_GetNssInfo(struct pipes_struct *p, struct wbint_GetNssInfo *r)
328 struct idmap_domain *domain;
331 domain = idmap_find_domain(r->in.info->domain_name);
332 if ((domain == NULL) || (domain->query_user == NULL)) {
333 return NT_STATUS_REQUEST_NOT_ACCEPTED;
336 status = domain->query_user(domain, r->in.info);
340 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
341 struct wbint_LookupUserAliases *r)
343 struct winbindd_domain *domain = wb_child_domain();
346 if (domain == NULL) {
347 return NT_STATUS_REQUEST_NOT_ACCEPTED;
350 status = wb_cache_lookup_useraliases(domain, p->mem_ctx,
351 r->in.sids->num_sids,
353 &r->out.rids->num_rids,
355 reset_cm_connection_on_error(domain, NULL, status);
359 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
360 struct wbint_LookupUserGroups *r)
362 struct winbindd_domain *domain = wb_child_domain();
365 if (domain == NULL) {
366 return NT_STATUS_REQUEST_NOT_ACCEPTED;
369 status = wb_cache_lookup_usergroups(domain, p->mem_ctx, r->in.sid,
370 &r->out.sids->num_sids,
372 reset_cm_connection_on_error(domain, NULL, status);
376 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
377 struct wbint_QuerySequenceNumber *r)
379 struct winbindd_domain *domain = wb_child_domain();
382 if (domain == NULL) {
383 return NT_STATUS_REQUEST_NOT_ACCEPTED;
386 status = wb_cache_sequence_number(domain, r->out.sequence);
387 reset_cm_connection_on_error(domain, NULL, status);
391 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
392 struct wbint_LookupGroupMembers *r)
394 struct winbindd_domain *domain = wb_child_domain();
395 uint32_t i, num_names;
396 struct dom_sid *sid_mem;
398 uint32_t *name_types;
401 if (domain == NULL) {
402 return NT_STATUS_REQUEST_NOT_ACCEPTED;
405 status = wb_cache_lookup_groupmem(domain, p->mem_ctx, r->in.sid,
406 r->in.type, &num_names, &sid_mem,
407 &names, &name_types);
408 reset_cm_connection_on_error(domain, NULL, status);
409 if (!NT_STATUS_IS_OK(status)) {
413 r->out.members->num_principals = num_names;
414 r->out.members->principals = talloc_array(
415 r->out.members, struct wbint_Principal, num_names);
416 if (r->out.members->principals == NULL) {
417 return NT_STATUS_NO_MEMORY;
420 for (i=0; i<num_names; i++) {
421 struct wbint_Principal *m = &r->out.members->principals[i];
422 sid_copy(&m->sid, &sid_mem[i]);
423 m->name = talloc_move(r->out.members->principals, &names[i]);
424 m->type = (enum lsa_SidType)name_types[i];
430 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
431 struct wbint_QueryGroupList *r)
433 TALLOC_CTX *frame = NULL;
434 struct winbindd_domain *domain = wb_child_domain();
436 uint32_t num_local_groups = 0;
437 struct wb_acct_info *local_groups = NULL;
438 uint32_t num_dom_groups = 0;
439 struct wb_acct_info *dom_groups = NULL;
441 uint64_t num_total = 0;
442 struct wbint_Principal *result;
443 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
444 bool include_local_groups = false;
446 if (domain == NULL) {
447 return NT_STATUS_REQUEST_NOT_ACCEPTED;
450 frame = talloc_stackframe();
452 switch (lp_server_role()) {
453 case ROLE_ACTIVE_DIRECTORY_DC:
454 if (domain->internal) {
456 * we want to include local groups
457 * for BUILTIN and WORKGROUP
459 include_local_groups = true;
464 * We might include local groups in more
465 * setups later, but that requires more work
471 if (include_local_groups) {
472 status = wb_cache_enum_local_groups(domain, frame,
475 reset_cm_connection_on_error(domain, NULL, status);
476 if (!NT_STATUS_IS_OK(status)) {
481 status = wb_cache_enum_dom_groups(domain, frame,
484 reset_cm_connection_on_error(domain, NULL, status);
485 if (!NT_STATUS_IS_OK(status)) {
489 num_total = num_local_groups + num_dom_groups;
490 if (num_total > UINT32_MAX) {
491 status = NT_STATUS_INTERNAL_ERROR;
495 result = talloc_array(frame, struct wbint_Principal, num_total);
496 if (result == NULL) {
497 status = NT_STATUS_NO_MEMORY;
501 for (i = 0; i < num_local_groups; i++) {
502 struct wb_acct_info *lg = &local_groups[i];
503 struct wbint_Principal *rg = &result[ti++];
505 sid_compose(&rg->sid, &domain->sid, lg->rid);
506 rg->type = SID_NAME_ALIAS;
507 rg->name = talloc_strdup(result, lg->acct_name);
508 if (rg->name == NULL) {
509 status = NT_STATUS_NO_MEMORY;
513 num_local_groups = 0;
515 for (i = 0; i < num_dom_groups; i++) {
516 struct wb_acct_info *dg = &dom_groups[i];
517 struct wbint_Principal *rg = &result[ti++];
519 sid_compose(&rg->sid, &domain->sid, dg->rid);
520 rg->type = SID_NAME_DOM_GRP;
521 rg->name = talloc_strdup(result, dg->acct_name);
522 if (rg->name == NULL) {
523 status = NT_STATUS_NO_MEMORY;
529 r->out.groups->num_principals = ti;
530 r->out.groups->principals = talloc_move(r->out.groups, &result);
532 status = NT_STATUS_OK;
538 NTSTATUS _wbint_QueryUserRidList(struct pipes_struct *p,
539 struct wbint_QueryUserRidList *r)
541 struct winbindd_domain *domain = wb_child_domain();
544 if (domain == NULL) {
545 return NT_STATUS_REQUEST_NOT_ACCEPTED;
549 * Right now this is overkill. We should add a backend call
550 * just querying the rids.
553 status = wb_cache_query_user_list(domain, p->mem_ctx,
555 reset_cm_connection_on_error(domain, NULL, status);
557 if (!NT_STATUS_IS_OK(status)) {
561 r->out.rids->num_rids = talloc_array_length(r->out.rids->rids);
566 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
568 struct winbindd_domain *domain = wb_child_domain();
569 struct rpc_pipe_client *netlogon_pipe;
570 struct netr_DsRGetDCNameInfo *dc_info;
573 unsigned int orig_timeout;
574 struct dcerpc_binding_handle *b;
576 bool try_dsrgetdcname = false;
578 if (domain == NULL) {
579 return dsgetdcname(p->mem_ctx, global_messaging_context(),
580 r->in.domain_name, r->in.domain_guid,
581 r->in.site_name ? r->in.site_name : "",
586 if (domain->active_directory) {
587 try_dsrgetdcname = true;
591 status = cm_connect_netlogon(domain, &netlogon_pipe);
593 reset_cm_connection_on_error(domain, NULL, status);
594 if (!NT_STATUS_IS_OK(status)) {
595 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
599 b = netlogon_pipe->binding_handle;
601 /* This call can take a long time - allow the server to time out.
602 35 seconds should do it. */
604 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
606 if (try_dsrgetdcname) {
607 status = dcerpc_netr_DsRGetDCName(b,
608 p->mem_ctx, domain->dcname,
609 r->in.domain_name, NULL, r->in.domain_guid,
610 r->in.flags, r->out.dc_info, &werr);
611 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
615 reset_cm_connection_on_error(domain, NULL, status))
620 try_dsrgetdcname = false;
625 * Fallback to less capable methods
628 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
629 if (dc_info == NULL) {
630 status = NT_STATUS_NO_MEMORY;
634 if (r->in.flags & DS_PDC_REQUIRED) {
635 status = dcerpc_netr_GetDcName(b,
636 p->mem_ctx, domain->dcname,
637 r->in.domain_name, &dc_info->dc_unc, &werr);
639 status = dcerpc_netr_GetAnyDCName(b,
640 p->mem_ctx, domain->dcname,
641 r->in.domain_name, &dc_info->dc_unc, &werr);
644 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
648 if (!NT_STATUS_IS_OK(status)) {
649 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
653 if (!W_ERROR_IS_OK(werr)) {
654 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
656 status = werror_to_ntstatus(werr);
660 *r->out.dc_info = dc_info;
661 status = NT_STATUS_OK;
664 /* And restore our original timeout. */
665 rpccli_set_timeout(netlogon_pipe, orig_timeout);
670 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
672 struct winbindd_domain *domain = wb_child_domain();
675 enum lsa_SidType *types;
676 struct wbint_Principal *result;
680 if (domain == NULL) {
681 return NT_STATUS_REQUEST_NOT_ACCEPTED;
684 status = wb_cache_rids_to_names(domain, talloc_tos(), r->in.domain_sid,
685 r->in.rids->rids, r->in.rids->num_rids,
686 &domain_name, &names, &types);
687 reset_cm_connection_on_error(domain, NULL, status);
688 if (!NT_STATUS_IS_OK(status) &&
689 !NT_STATUS_EQUAL(status, STATUS_SOME_UNMAPPED)) {
693 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
695 result = talloc_array(p->mem_ctx, struct wbint_Principal,
696 r->in.rids->num_rids);
697 if (result == NULL) {
698 return NT_STATUS_NO_MEMORY;
701 for (i=0; i<r->in.rids->num_rids; i++) {
702 sid_compose(&result[i].sid, r->in.domain_sid,
703 r->in.rids->rids[i]);
704 result[i].type = types[i];
705 result[i].name = talloc_move(result, &names[i]);
710 r->out.names->num_principals = r->in.rids->num_rids;
711 r->out.names->principals = result;
715 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
716 struct wbint_CheckMachineAccount *r)
718 struct winbindd_domain *domain;
722 domain = wb_child_domain();
723 if (domain == NULL) {
724 return NT_STATUS_REQUEST_NOT_ACCEPTED;
728 invalidate_cm_connection(domain);
729 domain->conn.netlogon_force_reauth = true;
732 struct rpc_pipe_client *netlogon_pipe = NULL;
733 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
734 status = cm_connect_netlogon_secure(domain,
736 &netlogon_creds_ctx);
739 /* There is a race condition between fetching the trust account
740 password and the periodic machine password change. So it's
741 possible that the trust account password has been changed on us.
742 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
744 #define MAX_RETRIES 3
746 if ((num_retries < MAX_RETRIES)
747 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
752 if (!NT_STATUS_IS_OK(status)) {
753 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
757 /* Pass back result code - zero for success, other values for
758 specific failures. */
760 DEBUG(3,("domain %s secret is %s\n", domain->name,
761 NT_STATUS_IS_OK(status) ? "good" : "bad"));
764 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
765 ("Checking the trust account password for domain %s returned %s\n",
766 domain->name, nt_errstr(status)));
771 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
772 struct wbint_ChangeMachineAccount *r)
774 struct messaging_context *msg_ctx = global_messaging_context();
775 struct winbindd_domain *domain;
777 struct rpc_pipe_client *netlogon_pipe = NULL;
778 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
780 domain = wb_child_domain();
781 if (domain == NULL) {
782 return NT_STATUS_REQUEST_NOT_ACCEPTED;
785 status = cm_connect_netlogon_secure(domain,
787 &netlogon_creds_ctx);
788 if (!NT_STATUS_IS_OK(status)) {
789 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
793 status = trust_pw_change(netlogon_creds_ctx,
795 netlogon_pipe->binding_handle,
800 /* Pass back result code - zero for success, other values for
801 specific failures. */
803 DEBUG(3,("domain %s secret %s\n", domain->name,
804 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
807 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
808 ("Changing the trust account password for domain %s returned %s\n",
809 domain->name, nt_errstr(status)));
814 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
817 struct winbindd_domain *domain;
818 struct rpc_pipe_client *netlogon_pipe;
819 union netr_CONTROL_QUERY_INFORMATION info;
821 fstring logon_server;
822 struct dcerpc_binding_handle *b;
825 domain = wb_child_domain();
826 if (domain == NULL) {
827 return NT_STATUS_REQUEST_NOT_ACCEPTED;
831 status = cm_connect_netlogon(domain, &netlogon_pipe);
832 reset_cm_connection_on_error(domain, NULL, status);
833 if (!NT_STATUS_IS_OK(status)) {
834 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
839 b = netlogon_pipe->binding_handle;
841 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
842 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
843 if (*r->out.dcname == NULL) {
844 DEBUG(2, ("Could not allocate memory\n"));
845 return NT_STATUS_NO_MEMORY;
849 * This provokes a WERR_NOT_SUPPORTED error message. This is
850 * documented in the wspp docs. I could not get a successful
851 * call to work, but the main point here is testing that the
852 * netlogon pipe works.
854 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
855 logon_server, NETLOGON_CONTROL_QUERY,
858 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
863 if (!NT_STATUS_IS_OK(status)) {
864 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
869 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
870 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
871 "WERR_NOT_SUPPORTED\n",
873 return werror_to_ntstatus(werr);
876 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
880 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
881 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
883 struct winbindd_domain *domain;
885 struct rpc_pipe_client *netlogon_pipe = NULL;
886 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
887 struct dcerpc_binding_handle *b = NULL;
890 domain = wb_child_domain();
891 if (domain == NULL) {
892 return NT_STATUS_REQUEST_NOT_ACCEPTED;
896 status = cm_connect_netlogon_secure(domain,
898 &netlogon_creds_ctx);
899 if (!NT_STATUS_IS_OK(status)) {
900 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
904 b = netlogon_pipe->binding_handle;
906 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx,
907 netlogon_pipe->binding_handle,
912 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
917 /* Pass back result code - zero for success, other values for
918 specific failures. */
920 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
921 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
924 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
925 ("Update of DNS records via RW DC %s returned %s\n",
926 domain->name, nt_errstr(status)));
931 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
932 struct winbind_SamLogon *r)
934 struct dcesrv_call_state *dce_call = p->dce_call;
935 struct dcesrv_connection *dcesrv_conn = dce_call->conn;
936 const struct tsocket_address *local_address =
937 dcesrv_connection_get_local_address(dcesrv_conn);
938 const struct tsocket_address *remote_address =
939 dcesrv_connection_get_remote_address(dcesrv_conn);
940 struct winbindd_domain *domain;
942 struct netr_IdentityInfo *identity_info = NULL;
943 const uint8_t chal_zero[8] = {0, };
944 const uint8_t *challenge = chal_zero;
945 DATA_BLOB lm_response, nt_response;
947 uint16_t validation_level;
948 union netr_Validation *validation = NULL;
949 bool interactive = false;
952 * Make sure we start with authoritative=true,
953 * it will only set to false if we don't know the
956 r->out.authoritative = true;
958 domain = wb_child_domain();
959 if (domain == NULL) {
960 return NT_STATUS_REQUEST_NOT_ACCEPTED;
963 switch (r->in.validation_level) {
968 return NT_STATUS_REQUEST_NOT_ACCEPTED;
971 switch (r->in.logon_level) {
972 case NetlogonInteractiveInformation:
973 case NetlogonServiceInformation:
974 case NetlogonInteractiveTransitiveInformation:
975 case NetlogonServiceTransitiveInformation:
976 if (r->in.logon.password == NULL) {
977 return NT_STATUS_REQUEST_NOT_ACCEPTED;
981 identity_info = &r->in.logon.password->identity_info;
983 challenge = chal_zero;
984 lm_response = data_blob_talloc(p->mem_ctx,
985 r->in.logon.password->lmpassword.hash,
986 sizeof(r->in.logon.password->lmpassword.hash));
987 nt_response = data_blob_talloc(p->mem_ctx,
988 r->in.logon.password->ntpassword.hash,
989 sizeof(r->in.logon.password->ntpassword.hash));
992 case NetlogonNetworkInformation:
993 case NetlogonNetworkTransitiveInformation:
994 if (r->in.logon.network == NULL) {
995 return NT_STATUS_REQUEST_NOT_ACCEPTED;
999 identity_info = &r->in.logon.network->identity_info;
1001 challenge = r->in.logon.network->challenge;
1002 lm_response = data_blob_talloc(p->mem_ctx,
1003 r->in.logon.network->lm.data,
1004 r->in.logon.network->lm.length);
1005 nt_response = data_blob_talloc(p->mem_ctx,
1006 r->in.logon.network->nt.data,
1007 r->in.logon.network->nt.length);
1010 case NetlogonGenericInformation:
1011 if (r->in.logon.generic == NULL) {
1012 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1015 identity_info = &r->in.logon.generic->identity_info;
1017 * Not implemented here...
1019 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1022 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1025 status = winbind_dual_SamLogon(domain, p->mem_ctx,
1027 identity_info->parameter_control,
1028 identity_info->account_name.string,
1029 identity_info->domain_name.string,
1030 identity_info->workstation.string,
1031 identity_info->logon_id,
1035 lm_response, nt_response,
1038 &r->out.authoritative,
1039 true, /* skip_sam */
1043 if (!NT_STATUS_IS_OK(status)) {
1046 switch (r->in.validation_level) {
1048 status = map_validation_to_info3(p->mem_ctx,
1051 &r->out.validation.sam3);
1052 TALLOC_FREE(validation);
1053 if (!NT_STATUS_IS_OK(status)) {
1056 return NT_STATUS_OK;
1058 status = map_validation_to_info6(p->mem_ctx,
1061 &r->out.validation.sam6);
1062 TALLOC_FREE(validation);
1063 if (!NT_STATUS_IS_OK(status)) {
1066 return NT_STATUS_OK;
1069 smb_panic(__location__);
1070 return NT_STATUS_INTERNAL_ERROR;
1073 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
1074 struct winbindd_domain *domain,
1075 struct winbind_LogonControl *r)
1078 struct rpc_pipe_client *netlogon_pipe = NULL;
1079 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1080 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1081 WERROR check_result = WERR_INTERNAL_ERROR;
1083 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1084 if (info2 == NULL) {
1085 return WERR_NOT_ENOUGH_MEMORY;
1088 if (domain->internal) {
1089 check_result = WERR_OK;
1094 * For now we just force a reconnect
1096 * TODO: take care of the optional '\dcname'
1098 invalidate_cm_connection(domain);
1099 domain->conn.netlogon_force_reauth = true;
1100 status = cm_connect_netlogon_secure(domain,
1102 &netlogon_creds_ctx);
1103 reset_cm_connection_on_error(domain, NULL, 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(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1109 __func__, domain->name, domain->alt_name,
1110 nt_errstr(status)));
1112 * Here we return a top level error!
1113 * This is different than TC_QUERY or TC_VERIFY.
1115 return ntstatus_to_werror(status);
1117 check_result = WERR_OK;
1120 info2->pdc_connection_status = WERR_OK;
1121 if (domain->dcname != NULL) {
1122 info2->flags |= NETLOGON_HAS_IP;
1123 info2->flags |= NETLOGON_HAS_TIMESERV;
1124 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1126 if (info2->trusted_dc_name == NULL) {
1127 return WERR_NOT_ENOUGH_MEMORY;
1130 info2->trusted_dc_name = talloc_strdup(info2, "");
1131 if (info2->trusted_dc_name == NULL) {
1132 return WERR_NOT_ENOUGH_MEMORY;
1135 info2->tc_connection_status = check_result;
1137 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1138 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1139 "pdc_connection[%s] tc_connection[%s]\n",
1140 __func__, domain->name, domain->alt_name,
1142 win_errstr(info2->pdc_connection_status),
1143 win_errstr(info2->tc_connection_status)));
1146 r->out.query->info2 = info2;
1148 DEBUG(5, ("%s: succeeded.\n", __func__));
1152 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
1153 struct winbindd_domain *domain,
1154 struct winbind_LogonControl *r)
1157 struct rpc_pipe_client *netlogon_pipe = NULL;
1158 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1159 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1160 WERROR check_result = WERR_INTERNAL_ERROR;
1162 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1163 if (info2 == NULL) {
1164 return WERR_NOT_ENOUGH_MEMORY;
1167 if (domain->internal) {
1168 check_result = WERR_OK;
1172 status = cm_connect_netlogon_secure(domain,
1174 &netlogon_creds_ctx);
1175 reset_cm_connection_on_error(domain, NULL, 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;
1188 info2->pdc_connection_status = WERR_OK;
1189 if (domain->dcname != NULL) {
1190 info2->flags |= NETLOGON_HAS_IP;
1191 info2->flags |= NETLOGON_HAS_TIMESERV;
1192 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1194 if (info2->trusted_dc_name == NULL) {
1195 return WERR_NOT_ENOUGH_MEMORY;
1198 info2->trusted_dc_name = talloc_strdup(info2, "");
1199 if (info2->trusted_dc_name == NULL) {
1200 return WERR_NOT_ENOUGH_MEMORY;
1203 info2->tc_connection_status = check_result;
1205 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1206 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1207 "pdc_connection[%s] tc_connection[%s]\n",
1208 __func__, domain->name, domain->alt_name,
1210 win_errstr(info2->pdc_connection_status),
1211 win_errstr(info2->tc_connection_status)));
1214 r->out.query->info2 = info2;
1216 DEBUG(5, ("%s: succeeded.\n", __func__));
1220 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1221 struct winbindd_domain *domain,
1222 struct winbind_LogonControl *r)
1224 TALLOC_CTX *frame = talloc_stackframe();
1227 struct lsa_String trusted_domain_name = {};
1228 struct lsa_StringLarge trusted_domain_name_l = {};
1229 struct rpc_pipe_client *local_lsa_pipe = NULL;
1230 struct policy_handle local_lsa_policy = {};
1231 struct dcerpc_binding_handle *local_lsa = NULL;
1232 struct rpc_pipe_client *netlogon_pipe = NULL;
1233 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1234 struct cli_credentials *creds = NULL;
1235 struct samr_Password *cur_nt_hash = NULL;
1236 uint32_t trust_attributes = 0;
1237 struct samr_Password new_owf_password = {};
1239 struct samr_Password old_owf_password = {};
1241 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1242 bool fetch_fti = false;
1243 struct lsa_ForestTrustInformation *new_fti = NULL;
1244 struct netr_TrustInfo *trust_info = NULL;
1245 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1246 struct dcerpc_binding_handle *b = NULL;
1247 WERROR check_result = WERR_INTERNAL_ERROR;
1248 WERROR verify_result = WERR_INTERNAL_ERROR;
1251 trusted_domain_name.string = domain->name;
1252 trusted_domain_name_l.string = domain->name;
1254 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1255 if (info2 == NULL) {
1257 return WERR_NOT_ENOUGH_MEMORY;
1260 if (domain->internal) {
1261 check_result = WERR_OK;
1265 status = pdb_get_trust_credentials(domain->name,
1269 if (NT_STATUS_IS_OK(status)) {
1270 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1274 if (!domain->primary) {
1275 union lsa_TrustedDomainInfo *tdi = NULL;
1277 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1279 if (!NT_STATUS_IS_OK(status)) {
1280 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1281 __location__, __func__, nt_errstr(status)));
1283 return WERR_INTERNAL_ERROR;
1285 local_lsa = local_lsa_pipe->binding_handle;
1287 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1289 &trusted_domain_name,
1290 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1292 if (!NT_STATUS_IS_OK(status)) {
1293 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1294 __location__, __func__, domain->name, nt_errstr(status)));
1296 return WERR_INTERNAL_ERROR;
1298 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1299 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1300 __location__, __func__, domain->name));
1302 return WERR_NO_SUCH_DOMAIN;
1304 if (!NT_STATUS_IS_OK(result)) {
1305 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1306 __location__, __func__, domain->name, nt_errstr(result)));
1308 return WERR_INTERNAL_ERROR;
1311 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1312 "returned no trusted domain information\n",
1313 __location__, __func__));
1315 return WERR_INTERNAL_ERROR;
1318 local_tdo = &tdi->info_ex;
1319 trust_attributes = local_tdo->trust_attributes;
1322 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1323 struct lsa_ForestTrustInformation *old_fti = NULL;
1325 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1327 &trusted_domain_name,
1328 LSA_FOREST_TRUST_DOMAIN_INFO,
1330 if (!NT_STATUS_IS_OK(status)) {
1331 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1332 __location__, __func__, domain->name, nt_errstr(status)));
1334 return WERR_INTERNAL_ERROR;
1336 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1337 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1338 __func__, domain->name));
1341 result = NT_STATUS_OK;
1343 if (!NT_STATUS_IS_OK(result)) {
1344 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1345 __location__, __func__, domain->name, nt_errstr(result)));
1347 return WERR_INTERNAL_ERROR;
1350 TALLOC_FREE(old_fti);
1354 status = cm_connect_netlogon_secure(domain,
1356 &netlogon_creds_ctx);
1357 reset_cm_connection_on_error(domain, NULL, status);
1358 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1359 status = NT_STATUS_NO_LOGON_SERVERS;
1361 if (!NT_STATUS_IS_OK(status)) {
1362 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1363 nt_errstr(status)));
1364 check_result = ntstatus_to_werror(status);
1367 check_result = WERR_OK;
1368 b = netlogon_pipe->binding_handle;
1370 if (cur_nt_hash == NULL) {
1371 verify_result = WERR_NO_TRUST_LSA_SECRET;
1376 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1379 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1380 status = NT_STATUS_NOT_SUPPORTED;
1382 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1384 status = NT_STATUS_OK;
1386 if (!NT_STATUS_IS_OK(status)) {
1388 reset_cm_connection_on_error(domain, b, status))
1393 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1395 domain->name, nt_errstr(status)));
1396 check_result = ntstatus_to_werror(status);
1401 if (new_fti != NULL) {
1402 struct lsa_ForestTrustInformation old_fti = {};
1403 struct lsa_ForestTrustInformation *merged_fti = NULL;
1404 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1406 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1409 if (!NT_STATUS_IS_OK(status)) {
1410 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1411 __location__, __func__,
1412 domain->name, nt_errstr(status)));
1414 return ntstatus_to_werror(status);
1417 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1419 &trusted_domain_name_l,
1420 LSA_FOREST_TRUST_DOMAIN_INFO,
1422 0, /* check_only=0 => store it! */
1425 if (!NT_STATUS_IS_OK(status)) {
1426 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1427 __location__, __func__, domain->name, nt_errstr(status)));
1429 return WERR_INTERNAL_ERROR;
1431 if (!NT_STATUS_IS_OK(result)) {
1432 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1433 __location__, __func__, domain->name, nt_errstr(result)));
1435 return ntstatus_to_werror(result);
1439 status = netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx,
1444 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1445 status = NT_STATUS_NOT_SUPPORTED;
1447 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1448 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1449 nt_errstr(status)));
1450 verify_result = WERR_OK;
1453 if (!NT_STATUS_IS_OK(status)) {
1454 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1458 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1459 nt_errstr(status)));
1461 if (!dcerpc_binding_handle_is_connected(b)) {
1462 check_result = ntstatus_to_werror(status);
1465 verify_result = ntstatus_to_werror(status);
1470 if (trust_info != NULL && trust_info->count >= 1) {
1471 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1473 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1474 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1479 cmp_new = memcmp(new_owf_password.hash,
1481 sizeof(cur_nt_hash->hash));
1482 cmp_old = memcmp(old_owf_password.hash,
1484 sizeof(cur_nt_hash->hash));
1485 if (cmp_new != 0 && cmp_old != 0) {
1486 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1487 "any password known to dcname[%s]\n",
1488 __func__, domain->name, domain->alt_name,
1490 verify_result = WERR_WRONG_PASSWORD;
1495 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1496 "against the old password known to dcname[%s]\n",
1497 __func__, domain->name, domain->alt_name,
1501 verify_result = WERR_OK;
1505 verify_result = check_result;
1507 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1508 info2->pdc_connection_status = verify_result;
1509 if (domain->dcname != NULL) {
1510 info2->flags |= NETLOGON_HAS_IP;
1511 info2->flags |= NETLOGON_HAS_TIMESERV;
1512 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1514 if (info2->trusted_dc_name == NULL) {
1516 return WERR_NOT_ENOUGH_MEMORY;
1519 info2->trusted_dc_name = talloc_strdup(info2, "");
1520 if (info2->trusted_dc_name == NULL) {
1522 return WERR_NOT_ENOUGH_MEMORY;
1525 info2->tc_connection_status = check_result;
1527 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1528 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1529 "pdc_connection[%s] tc_connection[%s]\n",
1530 __func__, domain->name, domain->alt_name,
1532 win_errstr(info2->pdc_connection_status),
1533 win_errstr(info2->tc_connection_status)));
1536 r->out.query->info2 = info2;
1538 DEBUG(5, ("%s: succeeded.\n", __func__));
1543 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1544 struct winbindd_domain *domain,
1545 struct winbind_LogonControl *r)
1547 struct messaging_context *msg_ctx = global_messaging_context();
1549 struct rpc_pipe_client *netlogon_pipe = NULL;
1550 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1551 struct cli_credentials *creds = NULL;
1552 struct samr_Password *cur_nt_hash = NULL;
1553 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1554 struct dcerpc_binding_handle *b;
1555 WERROR change_result = WERR_OK;
1558 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1559 if (info1 == NULL) {
1560 return WERR_NOT_ENOUGH_MEMORY;
1563 if (domain->internal) {
1564 return WERR_NOT_SUPPORTED;
1567 status = pdb_get_trust_credentials(domain->name,
1571 if (NT_STATUS_IS_OK(status)) {
1572 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1577 status = cm_connect_netlogon_secure(domain,
1579 &netlogon_creds_ctx);
1580 reset_cm_connection_on_error(domain, NULL, status);
1581 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1582 status = NT_STATUS_NO_LOGON_SERVERS;
1584 if (!NT_STATUS_IS_OK(status)) {
1585 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1586 __func__, domain->name, domain->alt_name,
1587 nt_errstr(status)));
1589 * Here we return a top level error!
1590 * This is different than TC_QUERY or TC_VERIFY.
1592 return ntstatus_to_werror(status);
1594 b = netlogon_pipe->binding_handle;
1596 if (cur_nt_hash == NULL) {
1597 change_result = WERR_NO_TRUST_LSA_SECRET;
1600 TALLOC_FREE(cur_nt_hash);
1602 status = trust_pw_change(netlogon_creds_ctx,
1603 msg_ctx, b, domain->name,
1606 if (!NT_STATUS_IS_OK(status)) {
1607 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1612 DEBUG(1, ("trust_pw_change(%s): %s\n",
1613 domain->name, nt_errstr(status)));
1615 change_result = ntstatus_to_werror(status);
1619 change_result = WERR_OK;
1622 info1->pdc_connection_status = change_result;
1624 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1625 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1626 "pdc_connection[%s]\n",
1627 __func__, domain->name, domain->alt_name,
1629 win_errstr(info1->pdc_connection_status)));
1632 r->out.query->info1 = info1;
1634 DEBUG(5, ("%s: succeeded.\n", __func__));
1638 WERROR _winbind_LogonControl(struct pipes_struct *p,
1639 struct winbind_LogonControl *r)
1641 struct winbindd_domain *domain;
1643 domain = wb_child_domain();
1644 if (domain == NULL) {
1645 return WERR_NO_SUCH_DOMAIN;
1648 switch (r->in.function_code) {
1649 case NETLOGON_CONTROL_REDISCOVER:
1650 if (r->in.level != 2) {
1651 return WERR_INVALID_PARAMETER;
1653 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1654 case NETLOGON_CONTROL_TC_QUERY:
1655 if (r->in.level != 2) {
1656 return WERR_INVALID_PARAMETER;
1658 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1659 case NETLOGON_CONTROL_TC_VERIFY:
1660 if (r->in.level != 2) {
1661 return WERR_INVALID_PARAMETER;
1663 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1664 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1665 if (r->in.level != 1) {
1666 return WERR_INVALID_PARAMETER;
1668 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1673 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1674 __func__, r->in.function_code));
1675 return WERR_NOT_SUPPORTED;
1678 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1679 struct winbind_GetForestTrustInformation *r)
1681 TALLOC_CTX *frame = talloc_stackframe();
1682 NTSTATUS status, result;
1683 struct winbindd_domain *domain;
1684 struct rpc_pipe_client *netlogon_pipe = NULL;
1685 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1686 struct dcerpc_binding_handle *b;
1688 struct lsa_String trusted_domain_name = {};
1689 struct lsa_StringLarge trusted_domain_name_l = {};
1690 union lsa_TrustedDomainInfo *tdi = NULL;
1691 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1692 struct lsa_ForestTrustInformation _old_fti = {};
1693 struct lsa_ForestTrustInformation *old_fti = NULL;
1694 struct lsa_ForestTrustInformation *new_fti = NULL;
1695 struct lsa_ForestTrustInformation *merged_fti = NULL;
1696 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1697 bool update_fti = false;
1698 struct rpc_pipe_client *local_lsa_pipe;
1699 struct policy_handle local_lsa_policy;
1700 struct dcerpc_binding_handle *local_lsa = NULL;
1702 domain = wb_child_domain();
1703 if (domain == NULL) {
1705 return WERR_NO_SUCH_DOMAIN;
1709 * checking for domain->internal and domain->primary
1710 * makes sure we only do some work when running as DC.
1713 if (domain->internal) {
1715 return WERR_NO_SUCH_DOMAIN;
1718 if (domain->primary) {
1720 return WERR_NO_SUCH_DOMAIN;
1723 trusted_domain_name.string = domain->name;
1724 trusted_domain_name_l.string = domain->name;
1726 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1728 if (!NT_STATUS_IS_OK(status)) {
1729 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1730 __location__, __func__, nt_errstr(status)));
1732 return WERR_INTERNAL_ERROR;
1734 local_lsa = local_lsa_pipe->binding_handle;
1736 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1738 &trusted_domain_name,
1739 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1741 if (!NT_STATUS_IS_OK(status)) {
1742 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1743 __location__, __func__, domain->name, nt_errstr(status)));
1745 return WERR_INTERNAL_ERROR;
1747 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1748 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1749 __location__, __func__, domain->name));
1751 return WERR_NO_SUCH_DOMAIN;
1753 if (!NT_STATUS_IS_OK(result)) {
1754 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1755 __location__, __func__, domain->name, nt_errstr(result)));
1757 return WERR_INTERNAL_ERROR;
1760 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1761 "returned no trusted domain information\n",
1762 __location__, __func__));
1764 return WERR_INTERNAL_ERROR;
1767 tdo = &tdi->info_ex;
1769 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1770 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1771 __func__, tdo->netbios_name.string,
1772 tdo->domain_name.string,
1773 (unsigned)tdo->trust_attributes));
1775 return WERR_NO_SUCH_DOMAIN;
1778 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1780 return WERR_INVALID_FLAGS;
1784 status = cm_connect_netlogon_secure(domain,
1786 &netlogon_creds_ctx);
1787 reset_cm_connection_on_error(domain, NULL, status);
1788 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1789 status = NT_STATUS_NO_LOGON_SERVERS;
1791 if (!NT_STATUS_IS_OK(status)) {
1792 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1793 nt_errstr(status)));
1795 return ntstatus_to_werror(status);
1797 b = netlogon_pipe->binding_handle;
1799 status = netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx,
1802 if (!NT_STATUS_IS_OK(status)) {
1803 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1807 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1808 domain->name, nt_errstr(status)));
1810 return ntstatus_to_werror(status);
1813 *r->out.forest_trust_info = new_fti;
1815 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1819 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1821 &trusted_domain_name,
1822 LSA_FOREST_TRUST_DOMAIN_INFO,
1824 if (!NT_STATUS_IS_OK(status)) {
1825 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1826 __location__, __func__, domain->name, nt_errstr(status)));
1828 return WERR_INTERNAL_ERROR;
1830 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1831 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1832 __func__, domain->name));
1834 old_fti = &_old_fti;
1835 result = NT_STATUS_OK;
1837 if (!NT_STATUS_IS_OK(result)) {
1838 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1839 __location__, __func__, domain->name, nt_errstr(result)));
1841 return WERR_INTERNAL_ERROR;
1844 if (old_fti == NULL) {
1845 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1846 "returned success without returning forest trust information\n",
1847 __location__, __func__));
1849 return WERR_INTERNAL_ERROR;
1856 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1858 if (!NT_STATUS_IS_OK(status)) {
1859 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1860 __location__, __func__, domain->name, nt_errstr(status)));
1862 return ntstatus_to_werror(status);
1865 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1867 &trusted_domain_name_l,
1868 LSA_FOREST_TRUST_DOMAIN_INFO,
1870 0, /* check_only=0 => store it! */
1873 if (!NT_STATUS_IS_OK(status)) {
1874 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1875 __location__, __func__, domain->name, nt_errstr(status)));
1877 return WERR_INTERNAL_ERROR;
1879 if (!NT_STATUS_IS_OK(result)) {
1880 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1881 __location__, __func__, domain->name, nt_errstr(result)));
1883 return ntstatus_to_werror(result);
1887 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1892 NTSTATUS _winbind_SendToSam(struct pipes_struct *p, struct winbind_SendToSam *r)
1894 struct winbindd_domain *domain;
1896 struct rpc_pipe_client *netlogon_pipe;
1897 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
1898 struct dcerpc_binding_handle *b = NULL;
1901 DEBUG(5, ("_winbind_SendToSam received\n"));
1902 domain = wb_child_domain();
1903 if (domain == NULL) {
1904 return NT_STATUS_REQUEST_NOT_ACCEPTED;
1908 status = cm_connect_netlogon_secure(domain,
1910 &netlogon_creds_ctx);
1911 reset_cm_connection_on_error(domain, NULL, status);
1912 if (!NT_STATUS_IS_OK(status)) {
1913 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1917 b = netlogon_pipe->binding_handle;
1919 status = netlogon_creds_cli_SendToSam(netlogon_creds_ctx,
1922 if (!retry && reset_cm_connection_on_error(domain, b, status)) {
1930 #include "librpc/gen_ndr/ndr_winbind_scompat.c"