2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
35 #include "../source4/dsdb/samdb/samdb.h"
37 void _wbint_Ping(struct pipes_struct *p, struct wbint_Ping *r)
39 *r->out.out_data = r->in.in_data;
42 static bool reset_cm_connection_on_error(struct winbindd_domain *domain,
45 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
46 invalidate_cm_connection(domain);
47 /* We invalidated the connection. */
53 NTSTATUS _wbint_LookupSid(struct pipes_struct *p, struct wbint_LookupSid *r)
55 struct winbindd_domain *domain = wb_child_domain();
58 enum lsa_SidType type;
62 return NT_STATUS_REQUEST_NOT_ACCEPTED;
65 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid,
66 &dom_name, &name, &type);
67 reset_cm_connection_on_error(domain, status);
68 if (!NT_STATUS_IS_OK(status)) {
72 *r->out.domain = dom_name;
78 NTSTATUS _wbint_LookupSids(struct pipes_struct *p, struct wbint_LookupSids *r)
80 struct winbindd_domain *domain = wb_child_domain();
81 struct lsa_RefDomainList *domains = r->out.domains;
85 return NT_STATUS_REQUEST_NOT_ACCEPTED;
89 * This breaks the winbindd_domain->methods abstraction: This
90 * is only called for remote domains, and both winbindd_msrpc
91 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
92 * done at the wbint RPC layer.
94 status = rpc_lookup_sids(p->mem_ctx, domain, r->in.sids,
95 &domains, &r->out.names);
97 if (domains != NULL) {
98 r->out.domains = domains;
101 reset_cm_connection_on_error(domain, status);
105 NTSTATUS _wbint_LookupName(struct pipes_struct *p, struct wbint_LookupName *r)
107 struct winbindd_domain *domain = wb_child_domain();
110 if (domain == NULL) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED;
114 status = domain->methods->name_to_sid(
115 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags,
116 r->out.sid, r->out.type);
117 reset_cm_connection_on_error(domain, status);
121 NTSTATUS _wbint_Sids2UnixIDs(struct pipes_struct *p,
122 struct wbint_Sids2UnixIDs *r)
125 struct id_map *ids = NULL;
126 struct id_map **id_ptrs = NULL;
127 struct dom_sid *sids = NULL;
128 uint32_t *id_idx = NULL;
129 NTSTATUS status = NT_STATUS_NO_MEMORY;
131 for (i=0; i<r->in.domains->count; i++) {
132 struct lsa_DomainInfo *d = &r->in.domains->domains[i];
133 struct idmap_domain *dom;
136 dom = idmap_find_domain_with_sid(d->name.string, d->sid);
138 DEBUG(10, ("idmap domain %s:%s not found\n",
139 d->name.string, sid_string_dbg(d->sid)));
145 for (j=0; j<r->in.ids->num_ids; j++) {
146 if (r->in.ids->ids[j].domain_index == i) {
151 ids = talloc_realloc(talloc_tos(), ids,
152 struct id_map, num_ids);
156 id_ptrs = talloc_realloc(talloc_tos(), id_ptrs,
157 struct id_map *, num_ids+1);
158 if (id_ptrs == NULL) {
161 id_idx = talloc_realloc(talloc_tos(), id_idx,
163 if (id_idx == NULL) {
166 sids = talloc_realloc(talloc_tos(), sids,
167 struct dom_sid, num_ids);
175 * Convert the input data into a list of
176 * id_map structs suitable for handing in
177 * to the idmap sids_to_unixids method.
179 for (j=0; j<r->in.ids->num_ids; j++) {
180 struct wbint_TransID *id = &r->in.ids->ids[j];
182 if (id->domain_index != i) {
186 id_ptrs[num_ids] = &ids[num_ids];
188 ids[num_ids].sid = &sids[num_ids];
189 sid_compose(ids[num_ids].sid, d->sid, id->rid);
190 ids[num_ids].xid.type = id->type;
191 ids[num_ids].status = ID_UNKNOWN;
194 id_ptrs[num_ids] = NULL;
196 status = dom->methods->sids_to_unixids(dom, id_ptrs);
197 DEBUG(10, ("sids_to_unixids returned %s\n",
201 * Extract the results for handing them back to the caller.
203 for (j=0; j<num_ids; j++) {
204 struct wbint_TransID *id = &r->in.ids->ids[id_idx[j]];
206 if (ids[j].status != ID_MAPPED) {
207 id->xid.id = UINT32_MAX;
208 id->xid.type = ID_TYPE_NOT_SPECIFIED;
212 id->xid = ids[j].xid;
215 status = NT_STATUS_OK;
218 TALLOC_FREE(id_ptrs);
224 NTSTATUS _wbint_Uid2Sid(struct pipes_struct *p, struct wbint_Uid2Sid *r)
226 return idmap_uid_to_sid(r->out.sid, r->in.uid);
229 NTSTATUS _wbint_Gid2Sid(struct pipes_struct *p, struct wbint_Gid2Sid *r)
231 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
232 r->out.sid, r->in.gid);
235 NTSTATUS _wbint_AllocateUid(struct pipes_struct *p, struct wbint_AllocateUid *r)
240 status = idmap_allocate_uid(&xid);
241 if (!NT_STATUS_IS_OK(status)) {
244 *r->out.uid = xid.id;
248 NTSTATUS _wbint_AllocateGid(struct pipes_struct *p, struct wbint_AllocateGid *r)
253 status = idmap_allocate_gid(&xid);
254 if (!NT_STATUS_IS_OK(status)) {
257 *r->out.gid = xid.id;
261 NTSTATUS _wbint_QueryUser(struct pipes_struct *p, struct wbint_QueryUser *r)
263 struct winbindd_domain *domain = wb_child_domain();
266 if (domain == NULL) {
267 return NT_STATUS_REQUEST_NOT_ACCEPTED;
270 status = domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
272 reset_cm_connection_on_error(domain, status);
276 NTSTATUS _wbint_LookupUserAliases(struct pipes_struct *p,
277 struct wbint_LookupUserAliases *r)
279 struct winbindd_domain *domain = wb_child_domain();
282 if (domain == NULL) {
283 return NT_STATUS_REQUEST_NOT_ACCEPTED;
286 status = domain->methods->lookup_useraliases(
287 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids,
288 &r->out.rids->num_rids, &r->out.rids->rids);
289 reset_cm_connection_on_error(domain, status);
293 NTSTATUS _wbint_LookupUserGroups(struct pipes_struct *p,
294 struct wbint_LookupUserGroups *r)
296 struct winbindd_domain *domain = wb_child_domain();
299 if (domain == NULL) {
300 return NT_STATUS_REQUEST_NOT_ACCEPTED;
303 status = domain->methods->lookup_usergroups(
304 domain, p->mem_ctx, r->in.sid,
305 &r->out.sids->num_sids, &r->out.sids->sids);
306 reset_cm_connection_on_error(domain, status);
310 NTSTATUS _wbint_QuerySequenceNumber(struct pipes_struct *p,
311 struct wbint_QuerySequenceNumber *r)
313 struct winbindd_domain *domain = wb_child_domain();
316 if (domain == NULL) {
317 return NT_STATUS_REQUEST_NOT_ACCEPTED;
320 status = domain->methods->sequence_number(domain, r->out.sequence);
321 reset_cm_connection_on_error(domain, status);
325 NTSTATUS _wbint_LookupGroupMembers(struct pipes_struct *p,
326 struct wbint_LookupGroupMembers *r)
328 struct winbindd_domain *domain = wb_child_domain();
329 uint32_t i, num_names;
330 struct dom_sid *sid_mem;
332 uint32_t *name_types;
335 if (domain == NULL) {
336 return NT_STATUS_REQUEST_NOT_ACCEPTED;
339 status = domain->methods->lookup_groupmem(
340 domain, p->mem_ctx, r->in.sid, r->in.type,
341 &num_names, &sid_mem, &names, &name_types);
342 reset_cm_connection_on_error(domain, status);
343 if (!NT_STATUS_IS_OK(status)) {
347 r->out.members->num_principals = num_names;
348 r->out.members->principals = talloc_array(
349 r->out.members, struct wbint_Principal, num_names);
350 if (r->out.members->principals == NULL) {
351 return NT_STATUS_NO_MEMORY;
354 for (i=0; i<num_names; i++) {
355 struct wbint_Principal *m = &r->out.members->principals[i];
356 sid_copy(&m->sid, &sid_mem[i]);
357 m->name = talloc_move(r->out.members->principals, &names[i]);
358 m->type = (enum lsa_SidType)name_types[i];
364 NTSTATUS _wbint_QueryUserList(struct pipes_struct *p,
365 struct wbint_QueryUserList *r)
367 struct winbindd_domain *domain = wb_child_domain();
370 if (domain == NULL) {
371 return NT_STATUS_REQUEST_NOT_ACCEPTED;
374 status = domain->methods->query_user_list(
375 domain, p->mem_ctx, &r->out.users->num_userinfos,
376 &r->out.users->userinfos);
377 reset_cm_connection_on_error(domain, status);
381 NTSTATUS _wbint_QueryGroupList(struct pipes_struct *p,
382 struct wbint_QueryGroupList *r)
384 struct winbindd_domain *domain = wb_child_domain();
386 uint32_t num_local_groups = 0;
387 struct wb_acct_info *local_groups = NULL;
388 uint32_t num_dom_groups = 0;
389 struct wb_acct_info *dom_groups = NULL;
391 uint64_t num_total = 0;
392 struct wbint_Principal *result;
394 bool include_local_groups = false;
396 if (domain == NULL) {
397 return NT_STATUS_REQUEST_NOT_ACCEPTED;
400 switch (lp_server_role()) {
401 case ROLE_ACTIVE_DIRECTORY_DC:
402 if (domain->internal) {
404 * we want to include local groups
405 * for BUILTIN and WORKGROUP
407 include_local_groups = true;
412 * We might include local groups in more
413 * setups later, but that requires more work
419 if (include_local_groups) {
420 status = domain->methods->enum_local_groups(domain, talloc_tos(),
423 reset_cm_connection_on_error(domain, status);
424 if (!NT_STATUS_IS_OK(status)) {
429 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
432 reset_cm_connection_on_error(domain, status);
433 if (!NT_STATUS_IS_OK(status)) {
437 num_total = num_local_groups + num_dom_groups;
438 if (num_total > UINT32_MAX) {
439 return NT_STATUS_INTERNAL_ERROR;
442 result = talloc_array(r->out.groups, struct wbint_Principal,
444 if (result == NULL) {
445 return NT_STATUS_NO_MEMORY;
448 for (i = 0; i < num_local_groups; i++) {
449 struct wb_acct_info *lg = &local_groups[i];
450 struct wbint_Principal *rg = &result[ti++];
452 sid_compose(&rg->sid, &domain->sid, lg->rid);
453 rg->type = SID_NAME_ALIAS;
454 rg->name = talloc_strdup(result, lg->acct_name);
455 if (rg->name == NULL) {
457 TALLOC_FREE(dom_groups);
458 TALLOC_FREE(local_groups);
459 return NT_STATUS_NO_MEMORY;
462 num_local_groups = 0;
463 TALLOC_FREE(local_groups);
465 for (i = 0; i < num_dom_groups; i++) {
466 struct wb_acct_info *dg = &dom_groups[i];
467 struct wbint_Principal *rg = &result[ti++];
469 sid_compose(&rg->sid, &domain->sid, dg->rid);
470 rg->type = SID_NAME_DOM_GRP;
471 rg->name = talloc_strdup(result, dg->acct_name);
472 if (rg->name == NULL) {
474 TALLOC_FREE(dom_groups);
475 TALLOC_FREE(local_groups);
476 return NT_STATUS_NO_MEMORY;
480 TALLOC_FREE(dom_groups);
482 r->out.groups->num_principals = ti;
483 r->out.groups->principals = result;
488 NTSTATUS _wbint_DsGetDcName(struct pipes_struct *p, struct wbint_DsGetDcName *r)
490 struct winbindd_domain *domain = wb_child_domain();
491 struct rpc_pipe_client *netlogon_pipe;
492 struct netr_DsRGetDCNameInfo *dc_info;
495 unsigned int orig_timeout;
496 struct dcerpc_binding_handle *b;
498 if (domain == NULL) {
499 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
500 r->in.domain_name, r->in.domain_guid,
501 r->in.site_name ? r->in.site_name : "",
506 status = cm_connect_netlogon(domain, &netlogon_pipe);
508 reset_cm_connection_on_error(domain, status);
509 if (!NT_STATUS_IS_OK(status)) {
510 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
514 b = netlogon_pipe->binding_handle;
516 /* This call can take a long time - allow the server to time out.
517 35 seconds should do it. */
519 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
521 if (domain->active_directory) {
522 status = dcerpc_netr_DsRGetDCName(b,
523 p->mem_ctx, domain->dcname,
524 r->in.domain_name, NULL, r->in.domain_guid,
525 r->in.flags, r->out.dc_info, &werr);
526 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
529 if (reset_cm_connection_on_error(domain, status)) {
531 status = cm_connect_netlogon(domain, &netlogon_pipe);
533 reset_cm_connection_on_error(domain, status);
534 if (!NT_STATUS_IS_OK(status)) {
535 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
539 b = netlogon_pipe->binding_handle;
541 /* This call can take a long time - allow the server to time out.
542 35 seconds should do it. */
544 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
549 * Fallback to less capable methods
552 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
553 if (dc_info == NULL) {
554 status = NT_STATUS_NO_MEMORY;
558 if (r->in.flags & DS_PDC_REQUIRED) {
559 status = dcerpc_netr_GetDcName(b,
560 p->mem_ctx, domain->dcname,
561 r->in.domain_name, &dc_info->dc_unc, &werr);
563 status = dcerpc_netr_GetAnyDCName(b,
564 p->mem_ctx, domain->dcname,
565 r->in.domain_name, &dc_info->dc_unc, &werr);
568 reset_cm_connection_on_error(domain, status);
569 if (!NT_STATUS_IS_OK(status)) {
570 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
574 if (!W_ERROR_IS_OK(werr)) {
575 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
577 status = werror_to_ntstatus(werr);
581 *r->out.dc_info = dc_info;
582 status = NT_STATUS_OK;
585 /* And restore our original timeout. */
586 rpccli_set_timeout(netlogon_pipe, orig_timeout);
591 NTSTATUS _wbint_LookupRids(struct pipes_struct *p, struct wbint_LookupRids *r)
593 struct winbindd_domain *domain = wb_child_domain();
596 enum lsa_SidType *types;
597 struct wbint_Principal *result;
601 if (domain == NULL) {
602 return NT_STATUS_REQUEST_NOT_ACCEPTED;
605 status = domain->methods->rids_to_names(
606 domain, talloc_tos(), r->in.domain_sid, r->in.rids->rids,
607 r->in.rids->num_rids, &domain_name, &names, &types);
608 reset_cm_connection_on_error(domain, status);
609 if (!NT_STATUS_IS_OK(status)) {
613 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name);
615 result = talloc_array(p->mem_ctx, struct wbint_Principal,
616 r->in.rids->num_rids);
617 if (result == NULL) {
618 return NT_STATUS_NO_MEMORY;
621 for (i=0; i<r->in.rids->num_rids; i++) {
622 sid_compose(&result[i].sid, r->in.domain_sid,
623 r->in.rids->rids[i]);
624 result[i].type = types[i];
625 result[i].name = talloc_move(result, &names[i]);
630 r->out.names->num_principals = r->in.rids->num_rids;
631 r->out.names->principals = result;
635 NTSTATUS _wbint_CheckMachineAccount(struct pipes_struct *p,
636 struct wbint_CheckMachineAccount *r)
638 struct winbindd_domain *domain;
642 domain = wb_child_domain();
643 if (domain == NULL) {
644 return NT_STATUS_REQUEST_NOT_ACCEPTED;
648 invalidate_cm_connection(domain);
649 domain->conn.netlogon_force_reauth = true;
652 struct rpc_pipe_client *netlogon_pipe;
653 status = cm_connect_netlogon(domain, &netlogon_pipe);
656 /* There is a race condition between fetching the trust account
657 password and the periodic machine password change. So it's
658 possible that the trust account password has been changed on us.
659 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
661 #define MAX_RETRIES 3
663 if ((num_retries < MAX_RETRIES)
664 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
669 if (!NT_STATUS_IS_OK(status)) {
670 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
674 /* Pass back result code - zero for success, other values for
675 specific failures. */
677 DEBUG(3,("domain %s secret is %s\n", domain->name,
678 NT_STATUS_IS_OK(status) ? "good" : "bad"));
681 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
682 ("Checking the trust account password for domain %s returned %s\n",
683 domain->name, nt_errstr(status)));
688 NTSTATUS _wbint_ChangeMachineAccount(struct pipes_struct *p,
689 struct wbint_ChangeMachineAccount *r)
691 struct messaging_context *msg_ctx = winbind_messaging_context();
692 struct winbindd_domain *domain;
694 struct rpc_pipe_client *netlogon_pipe;
696 domain = wb_child_domain();
697 if (domain == NULL) {
698 return NT_STATUS_REQUEST_NOT_ACCEPTED;
701 status = cm_connect_netlogon(domain, &netlogon_pipe);
702 if (!NT_STATUS_IS_OK(status)) {
703 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
707 status = trust_pw_change(domain->conn.netlogon_creds,
709 netlogon_pipe->binding_handle,
713 /* Pass back result code - zero for success, other values for
714 specific failures. */
716 DEBUG(3,("domain %s secret %s\n", domain->name,
717 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
720 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
721 ("Changing the trust account password for domain %s returned %s\n",
722 domain->name, nt_errstr(status)));
727 NTSTATUS _wbint_PingDc(struct pipes_struct *p, struct wbint_PingDc *r)
730 struct winbindd_domain *domain;
731 struct rpc_pipe_client *netlogon_pipe;
732 union netr_CONTROL_QUERY_INFORMATION info;
734 fstring logon_server;
735 struct dcerpc_binding_handle *b;
738 domain = wb_child_domain();
739 if (domain == NULL) {
740 return NT_STATUS_REQUEST_NOT_ACCEPTED;
744 status = cm_connect_netlogon(domain, &netlogon_pipe);
745 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
747 * Retry to open new connection with new kerberos ticket.
749 invalidate_cm_connection(domain);
750 status = cm_connect_netlogon(domain, &netlogon_pipe);
753 reset_cm_connection_on_error(domain, status);
754 if (!NT_STATUS_IS_OK(status)) {
755 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
760 b = netlogon_pipe->binding_handle;
762 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
763 *r->out.dcname = talloc_strdup(p->mem_ctx, domain->dcname);
764 if (*r->out.dcname == NULL) {
765 DEBUG(2, ("Could not allocate memory\n"));
766 return NT_STATUS_NO_MEMORY;
770 * This provokes a WERR_NOT_SUPPORTED error message. This is
771 * documented in the wspp docs. I could not get a successful
772 * call to work, but the main point here is testing that the
773 * netlogon pipe works.
775 status = dcerpc_netr_LogonControl(b, p->mem_ctx,
776 logon_server, NETLOGON_CONTROL_QUERY,
779 if (!dcerpc_binding_handle_is_connected(b) && !retry) {
780 DEBUG(10, ("Session might have expired. "
781 "Reconnect and retry once.\n"));
782 invalidate_cm_connection(domain);
787 reset_cm_connection_on_error(domain, status);
788 if (!NT_STATUS_IS_OK(status)) {
789 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
794 if (!W_ERROR_EQUAL(werr, WERR_NOT_SUPPORTED)) {
795 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
796 "WERR_NOT_SUPPORTED\n",
798 return werror_to_ntstatus(werr);
801 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
805 NTSTATUS _winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct *p,
806 struct winbind_DsrUpdateReadOnlyServerDnsRecords *r)
808 struct winbindd_domain *domain;
810 struct rpc_pipe_client *netlogon_pipe;
812 domain = wb_child_domain();
813 if (domain == NULL) {
814 return NT_STATUS_REQUEST_NOT_ACCEPTED;
817 status = cm_connect_netlogon(domain, &netlogon_pipe);
818 if (!NT_STATUS_IS_OK(status)) {
819 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
823 status = netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain->conn.netlogon_creds,
824 netlogon_pipe->binding_handle,
829 /* Pass back result code - zero for success, other values for
830 specific failures. */
832 DEBUG(3,("DNS records for domain %s %s\n", domain->name,
833 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
836 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2,
837 ("Update of DNS records via RW DC %s returned %s\n",
838 domain->name, nt_errstr(status)));
843 NTSTATUS _winbind_SamLogon(struct pipes_struct *p,
844 struct winbind_SamLogon *r)
846 struct winbindd_domain *domain;
848 DATA_BLOB lm_response, nt_response;
849 domain = wb_child_domain();
850 if (domain == NULL) {
851 return NT_STATUS_REQUEST_NOT_ACCEPTED;
854 /* TODO: Handle interactive logons here */
855 if (r->in.validation_level != 3 ||
856 r->in.logon.network == NULL ||
857 (r->in.logon_level != NetlogonNetworkInformation
858 && r->in.logon_level != NetlogonNetworkTransitiveInformation)) {
859 return NT_STATUS_REQUEST_NOT_ACCEPTED;
863 lm_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->lm.data, r->in.logon.network->lm.length);
864 nt_response = data_blob_talloc(p->mem_ctx, r->in.logon.network->nt.data, r->in.logon.network->nt.length);
866 status = winbind_dual_SamLogon(domain, p->mem_ctx,
867 r->in.logon.network->identity_info.parameter_control,
868 r->in.logon.network->identity_info.account_name.string,
869 r->in.logon.network->identity_info.domain_name.string,
870 r->in.logon.network->identity_info.workstation.string,
871 r->in.logon.network->challenge,
872 lm_response, nt_response, &r->out.validation.sam3);
876 static WERROR _winbind_LogonControl_REDISCOVER(struct pipes_struct *p,
877 struct winbindd_domain *domain,
878 struct winbind_LogonControl *r)
881 struct rpc_pipe_client *netlogon_pipe = NULL;
882 struct netr_NETLOGON_INFO_2 *info2 = NULL;
883 WERROR check_result = WERR_INTERNAL_ERROR;
885 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
890 if (domain->internal) {
891 check_result = WERR_OK;
896 * For now we just force a reconnect
898 * TODO: take care of the optional '\dcname'
900 invalidate_cm_connection(domain);
901 domain->conn.netlogon_force_reauth = true;
902 status = cm_connect_netlogon(domain, &netlogon_pipe);
903 reset_cm_connection_on_error(domain, status);
904 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
905 status = NT_STATUS_NO_LOGON_SERVERS;
907 if (!NT_STATUS_IS_OK(status)) {
908 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
909 __func__, domain->name, domain->alt_name,
912 * Here we return a top level error!
913 * This is different than TC_QUERY or TC_VERIFY.
915 return ntstatus_to_werror(status);
917 check_result = WERR_OK;
920 info2->pdc_connection_status = WERR_OK;
921 if (domain->dcname != NULL) {
922 info2->flags |= NETLOGON_HAS_IP;
923 info2->flags |= NETLOGON_HAS_TIMESERV;
924 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
926 if (info2->trusted_dc_name == NULL) {
930 info2->trusted_dc_name = talloc_strdup(info2, "");
931 if (info2->trusted_dc_name == NULL) {
935 info2->tc_connection_status = check_result;
937 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
938 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
939 "pdc_connection[%s] tc_connection[%s]\n",
940 __func__, domain->name, domain->alt_name,
942 win_errstr(info2->pdc_connection_status),
943 win_errstr(info2->tc_connection_status)));
946 r->out.query->info2 = info2;
948 DEBUG(5, ("%s: succeeded.\n", __func__));
952 static WERROR _winbind_LogonControl_TC_QUERY(struct pipes_struct *p,
953 struct winbindd_domain *domain,
954 struct winbind_LogonControl *r)
957 struct rpc_pipe_client *netlogon_pipe = NULL;
958 struct netr_NETLOGON_INFO_2 *info2 = NULL;
959 WERROR check_result = WERR_INTERNAL_ERROR;
961 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
966 if (domain->internal) {
967 check_result = WERR_OK;
971 status = cm_connect_netlogon(domain, &netlogon_pipe);
972 reset_cm_connection_on_error(domain, status);
973 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
974 status = NT_STATUS_NO_LOGON_SERVERS;
976 if (!NT_STATUS_IS_OK(status)) {
977 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
979 check_result = ntstatus_to_werror(status);
982 check_result = WERR_OK;
985 info2->pdc_connection_status = WERR_OK;
986 if (domain->dcname != NULL) {
987 info2->flags |= NETLOGON_HAS_IP;
988 info2->flags |= NETLOGON_HAS_TIMESERV;
989 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
991 if (info2->trusted_dc_name == NULL) {
995 info2->trusted_dc_name = talloc_strdup(info2, "");
996 if (info2->trusted_dc_name == NULL) {
1000 info2->tc_connection_status = check_result;
1002 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1003 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1004 "pdc_connection[%s] tc_connection[%s]\n",
1005 __func__, domain->name, domain->alt_name,
1007 win_errstr(info2->pdc_connection_status),
1008 win_errstr(info2->tc_connection_status)));
1011 r->out.query->info2 = info2;
1013 DEBUG(5, ("%s: succeeded.\n", __func__));
1017 static WERROR _winbind_LogonControl_TC_VERIFY(struct pipes_struct *p,
1018 struct winbindd_domain *domain,
1019 struct winbind_LogonControl *r)
1021 TALLOC_CTX *frame = talloc_stackframe();
1024 struct lsa_String trusted_domain_name = {};
1025 struct lsa_StringLarge trusted_domain_name_l = {};
1026 struct rpc_pipe_client *local_lsa_pipe = NULL;
1027 struct policy_handle local_lsa_policy = {};
1028 struct dcerpc_binding_handle *local_lsa = NULL;
1029 struct rpc_pipe_client *netlogon_pipe = NULL;
1030 struct cli_credentials *creds = NULL;
1031 struct samr_Password *cur_nt_hash = NULL;
1032 uint32_t trust_attributes = 0;
1033 struct samr_Password new_owf_password = {};
1035 struct samr_Password old_owf_password = {};
1037 const struct lsa_TrustDomainInfoInfoEx *local_tdo = NULL;
1038 bool fetch_fti = false;
1039 struct lsa_ForestTrustInformation *new_fti = NULL;
1040 struct netr_TrustInfo *trust_info = NULL;
1041 struct netr_NETLOGON_INFO_2 *info2 = NULL;
1042 struct dcerpc_binding_handle *b = NULL;
1043 WERROR check_result = WERR_INTERNAL_ERROR;
1044 WERROR verify_result = WERR_INTERNAL_ERROR;
1047 trusted_domain_name.string = domain->name;
1048 trusted_domain_name_l.string = domain->name;
1050 info2 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_2);
1051 if (info2 == NULL) {
1056 if (domain->internal) {
1057 check_result = WERR_OK;
1061 status = pdb_get_trust_credentials(domain->name,
1065 if (NT_STATUS_IS_OK(status)) {
1066 cur_nt_hash = cli_credentials_get_nt_hash(creds, frame);
1070 if (!domain->primary) {
1071 union lsa_TrustedDomainInfo *tdi = NULL;
1073 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1075 if (!NT_STATUS_IS_OK(status)) {
1076 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1077 __location__, __func__, nt_errstr(status)));
1079 return WERR_INTERNAL_ERROR;
1081 local_lsa = local_lsa_pipe->binding_handle;
1083 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1085 &trusted_domain_name,
1086 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1088 if (!NT_STATUS_IS_OK(status)) {
1089 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1090 __location__, __func__, domain->name, nt_errstr(status)));
1092 return WERR_INTERNAL_ERROR;
1094 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1095 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1096 __location__, __func__, domain->name));
1098 return WERR_NO_SUCH_DOMAIN;
1100 if (!NT_STATUS_IS_OK(result)) {
1101 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1102 __location__, __func__, domain->name, nt_errstr(result)));
1104 return WERR_INTERNAL_ERROR;
1107 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1108 "returned no trusted domain information\n",
1109 __location__, __func__));
1111 return WERR_INTERNAL_ERROR;
1114 local_tdo = &tdi->info_ex;
1115 trust_attributes = local_tdo->trust_attributes;
1118 if (trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1119 struct lsa_ForestTrustInformation *old_fti = NULL;
1121 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1123 &trusted_domain_name,
1124 LSA_FOREST_TRUST_DOMAIN_INFO,
1126 if (!NT_STATUS_IS_OK(status)) {
1127 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1128 __location__, __func__, domain->name, nt_errstr(status)));
1130 return WERR_INTERNAL_ERROR;
1132 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1133 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1134 __func__, domain->name));
1137 result = NT_STATUS_OK;
1139 if (!NT_STATUS_IS_OK(result)) {
1140 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1141 __location__, __func__, domain->name, nt_errstr(result)));
1143 return WERR_INTERNAL_ERROR;
1146 TALLOC_FREE(old_fti);
1150 status = cm_connect_netlogon(domain, &netlogon_pipe);
1151 reset_cm_connection_on_error(domain, status);
1152 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1153 status = NT_STATUS_NO_LOGON_SERVERS;
1155 if (!NT_STATUS_IS_OK(status)) {
1156 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1157 nt_errstr(status)));
1158 check_result = ntstatus_to_werror(status);
1161 check_result = WERR_OK;
1162 b = netlogon_pipe->binding_handle;
1164 if (cur_nt_hash == NULL) {
1165 verify_result = WERR_NO_TRUST_LSA_SECRET;
1170 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1173 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1174 status = NT_STATUS_NOT_SUPPORTED;
1176 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1178 status = NT_STATUS_OK;
1180 if (!NT_STATUS_IS_OK(status)) {
1181 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1182 invalidate_cm_connection(domain);
1186 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1188 domain->name, nt_errstr(status)));
1189 check_result = ntstatus_to_werror(status);
1194 if (new_fti != NULL) {
1195 struct lsa_ForestTrustInformation old_fti = {};
1196 struct lsa_ForestTrustInformation *merged_fti = NULL;
1197 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1199 status = dsdb_trust_merge_forest_info(frame, local_tdo,
1202 if (!NT_STATUS_IS_OK(status)) {
1203 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1204 __location__, __func__,
1205 domain->name, nt_errstr(status)));
1207 return ntstatus_to_werror(status);
1210 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1212 &trusted_domain_name_l,
1213 LSA_FOREST_TRUST_DOMAIN_INFO,
1215 0, /* check_only=0 => store it! */
1218 if (!NT_STATUS_IS_OK(status)) {
1219 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1220 __location__, __func__, domain->name, nt_errstr(status)));
1222 return WERR_INTERNAL_ERROR;
1224 if (!NT_STATUS_IS_OK(result)) {
1225 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1226 __location__, __func__, domain->name, nt_errstr(result)));
1228 return ntstatus_to_werror(result);
1232 status = netlogon_creds_cli_ServerGetTrustInfo(domain->conn.netlogon_creds,
1237 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
1238 status = NT_STATUS_NOT_SUPPORTED;
1240 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED)) {
1241 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1242 nt_errstr(status)));
1243 verify_result = WERR_OK;
1246 if (!NT_STATUS_IS_OK(status)) {
1247 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1248 invalidate_cm_connection(domain);
1252 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1253 nt_errstr(status)));
1255 if (!dcerpc_binding_handle_is_connected(b)) {
1256 check_result = ntstatus_to_werror(status);
1259 verify_result = ntstatus_to_werror(status);
1264 if (trust_info != NULL && trust_info->count >= 1) {
1265 uint32_t diff = trust_info->data[0] ^ trust_attributes;
1267 if (diff & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
1268 verify_result = WERR_DOMAIN_TRUST_INCONSISTENT;
1273 cmp_new = memcmp(new_owf_password.hash,
1275 sizeof(cur_nt_hash->hash));
1276 cmp_old = memcmp(old_owf_password.hash,
1278 sizeof(cur_nt_hash->hash));
1279 if (cmp_new != 0 && cmp_old != 0) {
1280 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1281 "any password known to dcname[%s]\n",
1282 __func__, domain->name, domain->alt_name,
1284 verify_result = WERR_WRONG_PASSWORD;
1289 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1290 "against the old password known to dcname[%s]\n",
1291 __func__, domain->name, domain->alt_name,
1295 verify_result = WERR_OK;
1299 verify_result = check_result;
1301 info2->flags |= NETLOGON_VERIFY_STATUS_RETURNED;
1302 info2->pdc_connection_status = verify_result;
1303 if (domain->dcname != NULL) {
1304 info2->flags |= NETLOGON_HAS_IP;
1305 info2->flags |= NETLOGON_HAS_TIMESERV;
1306 info2->trusted_dc_name = talloc_asprintf(info2, "\\\\%s",
1308 if (info2->trusted_dc_name == NULL) {
1313 info2->trusted_dc_name = talloc_strdup(info2, "");
1314 if (info2->trusted_dc_name == NULL) {
1319 info2->tc_connection_status = check_result;
1321 if (!W_ERROR_IS_OK(info2->pdc_connection_status)) {
1322 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1323 "pdc_connection[%s] tc_connection[%s]\n",
1324 __func__, domain->name, domain->alt_name,
1326 win_errstr(info2->pdc_connection_status),
1327 win_errstr(info2->tc_connection_status)));
1330 r->out.query->info2 = info2;
1332 DEBUG(5, ("%s: succeeded.\n", __func__));
1337 static WERROR _winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct *p,
1338 struct winbindd_domain *domain,
1339 struct winbind_LogonControl *r)
1341 struct messaging_context *msg_ctx = winbind_messaging_context();
1343 struct rpc_pipe_client *netlogon_pipe;
1344 struct cli_credentials *creds = NULL;
1345 struct samr_Password *cur_nt_hash = NULL;
1346 struct netr_NETLOGON_INFO_1 *info1 = NULL;
1347 struct dcerpc_binding_handle *b;
1348 WERROR change_result = WERR_OK;
1351 info1 = talloc_zero(p->mem_ctx, struct netr_NETLOGON_INFO_1);
1352 if (info1 == NULL) {
1356 if (domain->internal) {
1357 return WERR_NOT_SUPPORTED;
1360 status = pdb_get_trust_credentials(domain->name,
1364 if (NT_STATUS_IS_OK(status)) {
1365 cur_nt_hash = cli_credentials_get_nt_hash(creds, p->mem_ctx);
1370 status = cm_connect_netlogon(domain, &netlogon_pipe);
1371 reset_cm_connection_on_error(domain, status);
1372 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1373 status = NT_STATUS_NO_LOGON_SERVERS;
1375 if (!NT_STATUS_IS_OK(status)) {
1376 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1377 __func__, domain->name, domain->alt_name,
1378 nt_errstr(status)));
1380 * Here we return a top level error!
1381 * This is different than TC_QUERY or TC_VERIFY.
1383 return ntstatus_to_werror(status);
1385 b = netlogon_pipe->binding_handle;
1387 if (cur_nt_hash == NULL) {
1388 change_result = WERR_NO_TRUST_LSA_SECRET;
1391 TALLOC_FREE(cur_nt_hash);
1393 status = trust_pw_change(domain->conn.netlogon_creds,
1394 msg_ctx, b, domain->name,
1396 if (!NT_STATUS_IS_OK(status)) {
1397 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1398 invalidate_cm_connection(domain);
1403 DEBUG(1, ("trust_pw_change(%s): %s\n",
1404 domain->name, nt_errstr(status)));
1406 change_result = ntstatus_to_werror(status);
1410 change_result = WERR_OK;
1413 info1->pdc_connection_status = change_result;
1415 if (!W_ERROR_IS_OK(info1->pdc_connection_status)) {
1416 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1417 "pdc_connection[%s]\n",
1418 __func__, domain->name, domain->alt_name,
1420 win_errstr(info1->pdc_connection_status)));
1423 r->out.query->info1 = info1;
1425 DEBUG(5, ("%s: succeeded.\n", __func__));
1429 WERROR _winbind_LogonControl(struct pipes_struct *p,
1430 struct winbind_LogonControl *r)
1432 struct winbindd_domain *domain;
1434 domain = wb_child_domain();
1435 if (domain == NULL) {
1436 return WERR_NO_SUCH_DOMAIN;
1439 switch (r->in.function_code) {
1440 case NETLOGON_CONTROL_REDISCOVER:
1441 if (r->in.level != 2) {
1442 return WERR_INVALID_PARAMETER;
1444 return _winbind_LogonControl_REDISCOVER(p, domain, r);
1445 case NETLOGON_CONTROL_TC_QUERY:
1446 if (r->in.level != 2) {
1447 return WERR_INVALID_PARAMETER;
1449 return _winbind_LogonControl_TC_QUERY(p, domain, r);
1450 case NETLOGON_CONTROL_TC_VERIFY:
1451 if (r->in.level != 2) {
1452 return WERR_INVALID_PARAMETER;
1454 return _winbind_LogonControl_TC_VERIFY(p, domain, r);
1455 case NETLOGON_CONTROL_CHANGE_PASSWORD:
1456 if (r->in.level != 1) {
1457 return WERR_INVALID_PARAMETER;
1459 return _winbind_LogonControl_CHANGE_PASSWORD(p, domain, r);
1464 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1465 __func__, r->in.function_code));
1466 return WERR_NOT_SUPPORTED;
1469 WERROR _winbind_GetForestTrustInformation(struct pipes_struct *p,
1470 struct winbind_GetForestTrustInformation *r)
1472 TALLOC_CTX *frame = talloc_stackframe();
1473 NTSTATUS status, result;
1474 struct winbindd_domain *domain;
1475 struct rpc_pipe_client *netlogon_pipe;
1476 struct dcerpc_binding_handle *b;
1478 struct lsa_String trusted_domain_name = {};
1479 struct lsa_StringLarge trusted_domain_name_l = {};
1480 union lsa_TrustedDomainInfo *tdi = NULL;
1481 const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1482 struct lsa_ForestTrustInformation _old_fti = {};
1483 struct lsa_ForestTrustInformation *old_fti = NULL;
1484 struct lsa_ForestTrustInformation *new_fti = NULL;
1485 struct lsa_ForestTrustInformation *merged_fti = NULL;
1486 struct lsa_ForestTrustCollisionInfo *collision_info = NULL;
1487 bool update_fti = false;
1488 struct rpc_pipe_client *local_lsa_pipe;
1489 struct policy_handle local_lsa_policy;
1490 struct dcerpc_binding_handle *local_lsa = NULL;
1492 domain = wb_child_domain();
1493 if (domain == NULL) {
1495 return WERR_NO_SUCH_DOMAIN;
1499 * checking for domain->internal and domain->primary
1500 * makes sure we only do some work when running as DC.
1503 if (domain->internal) {
1505 return WERR_NO_SUCH_DOMAIN;
1508 if (domain->primary) {
1510 return WERR_NO_SUCH_DOMAIN;
1513 trusted_domain_name.string = domain->name;
1514 trusted_domain_name_l.string = domain->name;
1516 status = open_internal_lsa_conn(frame, &local_lsa_pipe,
1518 if (!NT_STATUS_IS_OK(status)) {
1519 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1520 __location__, __func__, nt_errstr(status)));
1522 return WERR_INTERNAL_ERROR;
1524 local_lsa = local_lsa_pipe->binding_handle;
1526 status = dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa, frame,
1528 &trusted_domain_name,
1529 LSA_TRUSTED_DOMAIN_INFO_INFO_EX,
1531 if (!NT_STATUS_IS_OK(status)) {
1532 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1533 __location__, __func__, domain->name, nt_errstr(status)));
1535 return WERR_INTERNAL_ERROR;
1537 if (NT_STATUS_EQUAL(result, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1538 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1539 __location__, __func__, domain->name));
1541 return WERR_NO_SUCH_DOMAIN;
1543 if (!NT_STATUS_IS_OK(result)) {
1544 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1545 __location__, __func__, domain->name, nt_errstr(result)));
1547 return WERR_INTERNAL_ERROR;
1550 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1551 "returned no trusted domain information\n",
1552 __location__, __func__));
1554 return WERR_INTERNAL_ERROR;
1557 tdo = &tdi->info_ex;
1559 if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1560 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1561 __func__, tdo->netbios_name.string,
1562 tdo->domain_name.string,
1563 (unsigned)tdo->trust_attributes));
1565 return WERR_NO_SUCH_DOMAIN;
1568 if (r->in.flags & ~DS_GFTI_UPDATE_TDO) {
1570 return WERR_INVALID_FLAGS;
1574 status = cm_connect_netlogon(domain, &netlogon_pipe);
1575 reset_cm_connection_on_error(domain, status);
1576 if (NT_STATUS_EQUAL(status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1577 status = NT_STATUS_NO_LOGON_SERVERS;
1579 if (!NT_STATUS_IS_OK(status)) {
1580 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1581 nt_errstr(status)));
1583 return ntstatus_to_werror(status);
1585 b = netlogon_pipe->binding_handle;
1587 status = netlogon_creds_cli_GetForestTrustInformation(domain->conn.netlogon_creds,
1590 if (!NT_STATUS_IS_OK(status)) {
1591 if (!retry && dcerpc_binding_handle_is_connected(b)) {
1592 invalidate_cm_connection(domain);
1596 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1597 domain->name, nt_errstr(status)));
1599 return ntstatus_to_werror(status);
1602 *r->out.forest_trust_info = new_fti;
1604 if (r->in.flags & DS_GFTI_UPDATE_TDO) {
1608 status = dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa, frame,
1610 &trusted_domain_name,
1611 LSA_FOREST_TRUST_DOMAIN_INFO,
1613 if (!NT_STATUS_IS_OK(status)) {
1614 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1615 __location__, __func__, domain->name, nt_errstr(status)));
1617 return WERR_INTERNAL_ERROR;
1619 if (NT_STATUS_EQUAL(result, NT_STATUS_NOT_FOUND)) {
1620 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1621 __func__, domain->name));
1623 old_fti = &_old_fti;
1624 result = NT_STATUS_OK;
1626 if (!NT_STATUS_IS_OK(result)) {
1627 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1628 __location__, __func__, domain->name, nt_errstr(result)));
1630 return WERR_INTERNAL_ERROR;
1633 if (old_fti == NULL) {
1634 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1635 "returned success without returning forest trust information\n",
1636 __location__, __func__));
1638 return WERR_INTERNAL_ERROR;
1645 status = dsdb_trust_merge_forest_info(frame, tdo, old_fti, new_fti,
1647 if (!NT_STATUS_IS_OK(status)) {
1648 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1649 __location__, __func__, domain->name, nt_errstr(status)));
1651 return ntstatus_to_werror(status);
1654 status = dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa, frame,
1656 &trusted_domain_name_l,
1657 LSA_FOREST_TRUST_DOMAIN_INFO,
1659 0, /* check_only=0 => store it! */
1662 if (!NT_STATUS_IS_OK(status)) {
1663 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1664 __location__, __func__, domain->name, nt_errstr(status)));
1666 return WERR_INTERNAL_ERROR;
1668 if (!NT_STATUS_IS_OK(result)) {
1669 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1670 __location__, __func__, domain->name, nt_errstr(result)));
1672 return ntstatus_to_werror(result);
1676 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));