2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "winbindd/winbindd.h"
25 #include "winbindd/winbindd_proto.h"
26 #include "rpc_client/cli_pipe.h"
28 #include "librpc/gen_ndr/srv_winbind.h"
29 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
30 #include "../librpc/gen_ndr/ndr_lsa_c.h"
32 #include "../libcli/security/security.h"
33 #include "../libcli/auth/netlogon_creds_cli.h"
35 #include "../source4/dsdb/samdb/samdb.h"
37 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
39 *r
->out
.out_data
= r
->in
.in_data
;
42 static bool reset_cm_connection_on_error(struct winbindd_domain
*domain
,
45 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
46 invalidate_cm_connection(domain
);
47 /* We invalidated the connection. */
53 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
55 struct winbindd_domain
*domain
= wb_child_domain();
58 enum lsa_SidType type
;
62 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
65 status
= wb_cache_sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
66 &dom_name
, &name
, &type
);
67 reset_cm_connection_on_error(domain
, status
);
68 if (!NT_STATUS_IS_OK(status
)) {
72 *r
->out
.domain
= dom_name
;
78 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
80 struct winbindd_domain
*domain
= wb_child_domain();
81 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
85 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
89 * This breaks the winbindd_domain->methods abstraction: This
90 * is only called for remote domains, and both winbindd_msrpc
91 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
92 * done at the wbint RPC layer.
94 status
= rpc_lookup_sids(p
->mem_ctx
, domain
, r
->in
.sids
,
95 &domains
, &r
->out
.names
);
97 if (domains
!= NULL
) {
98 r
->out
.domains
= domains
;
101 reset_cm_connection_on_error(domain
, status
);
105 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
107 struct winbindd_domain
*domain
= wb_child_domain();
110 if (domain
== NULL
) {
111 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
114 status
= wb_cache_name_to_sid(domain
, p
->mem_ctx
, r
->in
.domain
,
115 r
->in
.name
, r
->in
.flags
,
116 r
->out
.sid
, r
->out
.type
);
117 reset_cm_connection_on_error(domain
, status
);
121 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
122 struct wbint_Sids2UnixIDs
*r
)
126 struct lsa_DomainInfo
*d
;
127 struct wbint_TransID
*ids
;
130 struct id_map
**id_map_ptrs
= NULL
;
131 struct idmap_domain
*dom
;
132 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
134 if (r
->in
.domains
->count
!= 1) {
135 return NT_STATUS_INVALID_PARAMETER
;
138 d
= &r
->in
.domains
->domains
[0];
139 ids
= r
->in
.ids
->ids
;
140 num_ids
= r
->in
.ids
->num_ids
;
142 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
144 DEBUG(10, ("idmap domain %s:%s not found\n",
145 d
->name
.string
, sid_string_dbg(d
->sid
)));
147 for (i
=0; i
<num_ids
; i
++) {
149 ids
[i
].xid
= (struct unixid
) {
151 .type
= ID_TYPE_NOT_SPECIFIED
158 id_map_ptrs
= id_map_ptrs_init(talloc_tos(), num_ids
);
159 if (id_map_ptrs
== NULL
) {
164 * Convert the input data into a list of id_map structs
165 * suitable for handing in to the idmap sids_to_unixids
169 for (i
=0; i
<num_ids
; i
++) {
170 struct id_map
*m
= id_map_ptrs
[i
];
172 sid_compose(m
->sid
, d
->sid
, ids
[i
].rid
);
173 m
->status
= ID_UNKNOWN
;
174 m
->xid
= (struct unixid
) { .type
= ids
[i
].type
};
177 status
= dom
->methods
->sids_to_unixids(dom
, id_map_ptrs
);
179 if (!NT_STATUS_IS_OK(status
)) {
180 DEBUG(10, ("sids_to_unixids returned %s\n",
186 * Extract the results for handing them back to the caller.
189 for (i
=0; i
<num_ids
; i
++) {
190 struct id_map
*m
= id_map_ptrs
[i
];
192 if (!idmap_unix_id_is_in_range(m
->xid
.id
, dom
)) {
193 m
->status
= ID_UNMAPPED
;
196 if (m
->status
== ID_MAPPED
) {
199 ids
[i
].xid
.id
= UINT32_MAX
;
200 ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
206 status
= NT_STATUS_NO_MEMORY
;
208 TALLOC_FREE(id_map_ptrs
);
212 NTSTATUS
_wbint_UnixIDs2Sids(struct pipes_struct
*p
,
213 struct wbint_UnixIDs2Sids
*r
)
215 struct id_map
**maps
;
219 maps
= id_map_ptrs_init(talloc_tos(), r
->in
.num_ids
);
221 return NT_STATUS_NO_MEMORY
;
224 for (i
=0; i
<r
->in
.num_ids
; i
++) {
225 maps
[i
]->status
= ID_UNKNOWN
;
226 maps
[i
]->xid
= r
->in
.xids
[i
];
229 status
= idmap_backend_unixids_to_sids(maps
, r
->in
.domain_name
);
230 if (!NT_STATUS_IS_OK(status
)) {
235 for (i
=0; i
<r
->in
.num_ids
; i
++) {
236 r
->out
.xids
[i
] = maps
[i
]->xid
;
237 sid_copy(&r
->out
.sids
[i
], maps
[i
]->sid
);
245 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
250 status
= idmap_allocate_uid(&xid
);
251 if (!NT_STATUS_IS_OK(status
)) {
254 *r
->out
.uid
= xid
.id
;
258 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
263 status
= idmap_allocate_gid(&xid
);
264 if (!NT_STATUS_IS_OK(status
)) {
267 *r
->out
.gid
= xid
.id
;
271 NTSTATUS
_wbint_GetNssInfo(struct pipes_struct
*p
, struct wbint_GetNssInfo
*r
)
273 struct idmap_domain
*domain
;
276 domain
= idmap_find_domain(r
->in
.info
->domain_name
);
277 if ((domain
== NULL
) || (domain
->query_user
== NULL
)) {
278 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
281 status
= domain
->query_user(domain
, r
->in
.info
);
285 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
286 struct wbint_LookupUserAliases
*r
)
288 struct winbindd_domain
*domain
= wb_child_domain();
291 if (domain
== NULL
) {
292 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
295 status
= wb_cache_lookup_useraliases(domain
, p
->mem_ctx
,
296 r
->in
.sids
->num_sids
,
298 &r
->out
.rids
->num_rids
,
300 reset_cm_connection_on_error(domain
, status
);
304 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
305 struct wbint_LookupUserGroups
*r
)
307 struct winbindd_domain
*domain
= wb_child_domain();
310 if (domain
== NULL
) {
311 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
314 status
= wb_cache_lookup_usergroups(domain
, p
->mem_ctx
, r
->in
.sid
,
315 &r
->out
.sids
->num_sids
,
317 reset_cm_connection_on_error(domain
, status
);
321 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
322 struct wbint_QuerySequenceNumber
*r
)
324 struct winbindd_domain
*domain
= wb_child_domain();
327 if (domain
== NULL
) {
328 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
331 status
= wb_cache_sequence_number(domain
, r
->out
.sequence
);
332 reset_cm_connection_on_error(domain
, status
);
336 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
337 struct wbint_LookupGroupMembers
*r
)
339 struct winbindd_domain
*domain
= wb_child_domain();
340 uint32_t i
, num_names
;
341 struct dom_sid
*sid_mem
;
343 uint32_t *name_types
;
346 if (domain
== NULL
) {
347 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
350 status
= wb_cache_lookup_groupmem(domain
, p
->mem_ctx
, r
->in
.sid
,
351 r
->in
.type
, &num_names
, &sid_mem
,
352 &names
, &name_types
);
353 reset_cm_connection_on_error(domain
, status
);
354 if (!NT_STATUS_IS_OK(status
)) {
358 r
->out
.members
->num_principals
= num_names
;
359 r
->out
.members
->principals
= talloc_array(
360 r
->out
.members
, struct wbint_Principal
, num_names
);
361 if (r
->out
.members
->principals
== NULL
) {
362 return NT_STATUS_NO_MEMORY
;
365 for (i
=0; i
<num_names
; i
++) {
366 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
367 sid_copy(&m
->sid
, &sid_mem
[i
]);
368 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
369 m
->type
= (enum lsa_SidType
)name_types
[i
];
375 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
376 struct wbint_QueryGroupList
*r
)
378 struct winbindd_domain
*domain
= wb_child_domain();
380 uint32_t num_local_groups
= 0;
381 struct wb_acct_info
*local_groups
= NULL
;
382 uint32_t num_dom_groups
= 0;
383 struct wb_acct_info
*dom_groups
= NULL
;
385 uint64_t num_total
= 0;
386 struct wbint_Principal
*result
;
388 bool include_local_groups
= false;
390 if (domain
== NULL
) {
391 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
394 switch (lp_server_role()) {
395 case ROLE_ACTIVE_DIRECTORY_DC
:
396 if (domain
->internal
) {
398 * we want to include local groups
399 * for BUILTIN and WORKGROUP
401 include_local_groups
= true;
406 * We might include local groups in more
407 * setups later, but that requires more work
413 if (include_local_groups
) {
414 status
= wb_cache_enum_local_groups(domain
, talloc_tos(),
417 reset_cm_connection_on_error(domain
, status
);
418 if (!NT_STATUS_IS_OK(status
)) {
423 status
= wb_cache_enum_dom_groups(domain
, talloc_tos(),
426 reset_cm_connection_on_error(domain
, status
);
427 if (!NT_STATUS_IS_OK(status
)) {
431 num_total
= num_local_groups
+ num_dom_groups
;
432 if (num_total
> UINT32_MAX
) {
433 return NT_STATUS_INTERNAL_ERROR
;
436 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
438 if (result
== NULL
) {
439 return NT_STATUS_NO_MEMORY
;
442 for (i
= 0; i
< num_local_groups
; i
++) {
443 struct wb_acct_info
*lg
= &local_groups
[i
];
444 struct wbint_Principal
*rg
= &result
[ti
++];
446 sid_compose(&rg
->sid
, &domain
->sid
, lg
->rid
);
447 rg
->type
= SID_NAME_ALIAS
;
448 rg
->name
= talloc_strdup(result
, lg
->acct_name
);
449 if (rg
->name
== NULL
) {
451 TALLOC_FREE(dom_groups
);
452 TALLOC_FREE(local_groups
);
453 return NT_STATUS_NO_MEMORY
;
456 num_local_groups
= 0;
457 TALLOC_FREE(local_groups
);
459 for (i
= 0; i
< num_dom_groups
; i
++) {
460 struct wb_acct_info
*dg
= &dom_groups
[i
];
461 struct wbint_Principal
*rg
= &result
[ti
++];
463 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
464 rg
->type
= SID_NAME_DOM_GRP
;
465 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
466 if (rg
->name
== NULL
) {
468 TALLOC_FREE(dom_groups
);
469 TALLOC_FREE(local_groups
);
470 return NT_STATUS_NO_MEMORY
;
474 TALLOC_FREE(dom_groups
);
476 r
->out
.groups
->num_principals
= ti
;
477 r
->out
.groups
->principals
= result
;
482 NTSTATUS
_wbint_QueryUserRidList(struct pipes_struct
*p
,
483 struct wbint_QueryUserRidList
*r
)
485 struct winbindd_domain
*domain
= wb_child_domain();
488 if (domain
== NULL
) {
489 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
493 * Right now this is overkill. We should add a backend call
494 * just querying the rids.
497 status
= wb_cache_query_user_list(domain
, p
->mem_ctx
,
499 reset_cm_connection_on_error(domain
, status
);
501 if (!NT_STATUS_IS_OK(status
)) {
505 r
->out
.rids
->num_rids
= talloc_array_length(r
->out
.rids
->rids
);
510 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
512 struct winbindd_domain
*domain
= wb_child_domain();
513 struct rpc_pipe_client
*netlogon_pipe
;
514 struct netr_DsRGetDCNameInfo
*dc_info
;
517 unsigned int orig_timeout
;
518 struct dcerpc_binding_handle
*b
;
520 if (domain
== NULL
) {
521 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
522 r
->in
.domain_name
, r
->in
.domain_guid
,
523 r
->in
.site_name
? r
->in
.site_name
: "",
528 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
530 reset_cm_connection_on_error(domain
, status
);
531 if (!NT_STATUS_IS_OK(status
)) {
532 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
536 b
= netlogon_pipe
->binding_handle
;
538 /* This call can take a long time - allow the server to time out.
539 35 seconds should do it. */
541 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
543 if (domain
->active_directory
) {
544 status
= dcerpc_netr_DsRGetDCName(b
,
545 p
->mem_ctx
, domain
->dcname
,
546 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
547 r
->in
.flags
, r
->out
.dc_info
, &werr
);
548 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
551 if (reset_cm_connection_on_error(domain
, status
)) {
553 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
555 reset_cm_connection_on_error(domain
, status
);
556 if (!NT_STATUS_IS_OK(status
)) {
557 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
561 b
= netlogon_pipe
->binding_handle
;
563 /* This call can take a long time - allow the server to time out.
564 35 seconds should do it. */
566 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
571 * Fallback to less capable methods
574 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
575 if (dc_info
== NULL
) {
576 status
= NT_STATUS_NO_MEMORY
;
580 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
581 status
= dcerpc_netr_GetDcName(b
,
582 p
->mem_ctx
, domain
->dcname
,
583 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
585 status
= dcerpc_netr_GetAnyDCName(b
,
586 p
->mem_ctx
, domain
->dcname
,
587 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
590 reset_cm_connection_on_error(domain
, status
);
591 if (!NT_STATUS_IS_OK(status
)) {
592 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
596 if (!W_ERROR_IS_OK(werr
)) {
597 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
599 status
= werror_to_ntstatus(werr
);
603 *r
->out
.dc_info
= dc_info
;
604 status
= NT_STATUS_OK
;
607 /* And restore our original timeout. */
608 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
613 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
615 struct winbindd_domain
*domain
= wb_child_domain();
618 enum lsa_SidType
*types
;
619 struct wbint_Principal
*result
;
623 if (domain
== NULL
) {
624 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
627 status
= wb_cache_rids_to_names(domain
, talloc_tos(), r
->in
.domain_sid
,
628 r
->in
.rids
->rids
, r
->in
.rids
->num_rids
,
629 &domain_name
, &names
, &types
);
630 reset_cm_connection_on_error(domain
, status
);
631 if (!NT_STATUS_IS_OK(status
)) {
635 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
637 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
638 r
->in
.rids
->num_rids
);
639 if (result
== NULL
) {
640 return NT_STATUS_NO_MEMORY
;
643 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
644 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
645 r
->in
.rids
->rids
[i
]);
646 result
[i
].type
= types
[i
];
647 result
[i
].name
= talloc_move(result
, &names
[i
]);
652 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
653 r
->out
.names
->principals
= result
;
657 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
658 struct wbint_CheckMachineAccount
*r
)
660 struct winbindd_domain
*domain
;
664 domain
= wb_child_domain();
665 if (domain
== NULL
) {
666 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
670 invalidate_cm_connection(domain
);
671 domain
->conn
.netlogon_force_reauth
= true;
674 struct rpc_pipe_client
*netlogon_pipe
;
675 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
678 /* There is a race condition between fetching the trust account
679 password and the periodic machine password change. So it's
680 possible that the trust account password has been changed on us.
681 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
683 #define MAX_RETRIES 3
685 if ((num_retries
< MAX_RETRIES
)
686 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
691 if (!NT_STATUS_IS_OK(status
)) {
692 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
696 /* Pass back result code - zero for success, other values for
697 specific failures. */
699 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
700 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
703 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
704 ("Checking the trust account password for domain %s returned %s\n",
705 domain
->name
, nt_errstr(status
)));
710 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
711 struct wbint_ChangeMachineAccount
*r
)
713 struct messaging_context
*msg_ctx
= winbind_messaging_context();
714 struct winbindd_domain
*domain
;
716 struct rpc_pipe_client
*netlogon_pipe
;
718 domain
= wb_child_domain();
719 if (domain
== NULL
) {
720 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
723 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
724 if (!NT_STATUS_IS_OK(status
)) {
725 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
729 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
731 netlogon_pipe
->binding_handle
,
735 /* Pass back result code - zero for success, other values for
736 specific failures. */
738 DEBUG(3,("domain %s secret %s\n", domain
->name
,
739 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
742 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
743 ("Changing the trust account password for domain %s returned %s\n",
744 domain
->name
, nt_errstr(status
)));
749 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
752 struct winbindd_domain
*domain
;
753 struct rpc_pipe_client
*netlogon_pipe
;
754 union netr_CONTROL_QUERY_INFORMATION info
;
756 fstring logon_server
;
757 struct dcerpc_binding_handle
*b
;
760 domain
= wb_child_domain();
761 if (domain
== NULL
) {
762 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
766 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
767 reset_cm_connection_on_error(domain
, status
);
768 if (!NT_STATUS_IS_OK(status
)) {
769 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
774 b
= netlogon_pipe
->binding_handle
;
776 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
777 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
778 if (*r
->out
.dcname
== NULL
) {
779 DEBUG(2, ("Could not allocate memory\n"));
780 return NT_STATUS_NO_MEMORY
;
784 * This provokes a WERR_NOT_SUPPORTED error message. This is
785 * documented in the wspp docs. I could not get a successful
786 * call to work, but the main point here is testing that the
787 * netlogon pipe works.
789 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
790 logon_server
, NETLOGON_CONTROL_QUERY
,
793 if (!dcerpc_binding_handle_is_connected(b
) && !retry
) {
794 DEBUG(10, ("Session might have expired. "
795 "Reconnect and retry once.\n"));
796 invalidate_cm_connection(domain
);
801 reset_cm_connection_on_error(domain
, status
);
802 if (!NT_STATUS_IS_OK(status
)) {
803 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
808 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
809 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
810 "WERR_NOT_SUPPORTED\n",
812 return werror_to_ntstatus(werr
);
815 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
819 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
820 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
822 struct winbindd_domain
*domain
;
824 struct rpc_pipe_client
*netlogon_pipe
;
826 domain
= wb_child_domain();
827 if (domain
== NULL
) {
828 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
831 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
832 if (!NT_STATUS_IS_OK(status
)) {
833 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
837 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain
->conn
.netlogon_creds
,
838 netlogon_pipe
->binding_handle
,
843 /* Pass back result code - zero for success, other values for
844 specific failures. */
846 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
847 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
850 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
851 ("Update of DNS records via RW DC %s returned %s\n",
852 domain
->name
, nt_errstr(status
)));
857 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
858 struct winbind_SamLogon
*r
)
860 struct winbindd_domain
*domain
;
862 DATA_BLOB lm_response
, nt_response
;
865 domain
= wb_child_domain();
866 if (domain
== NULL
) {
867 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
870 /* TODO: Handle interactive logons here */
871 if (r
->in
.validation_level
!= 3 ||
872 r
->in
.logon
.network
== NULL
||
873 (r
->in
.logon_level
!= NetlogonNetworkInformation
874 && r
->in
.logon_level
!= NetlogonNetworkTransitiveInformation
)) {
875 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
879 lm_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->lm
.data
, r
->in
.logon
.network
->lm
.length
);
880 nt_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->nt
.data
, r
->in
.logon
.network
->nt
.length
);
882 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
883 r
->in
.logon
.network
->identity_info
.parameter_control
,
884 r
->in
.logon
.network
->identity_info
.account_name
.string
,
885 r
->in
.logon
.network
->identity_info
.domain_name
.string
,
886 r
->in
.logon
.network
->identity_info
.workstation
.string
,
887 r
->in
.logon
.network
->challenge
,
888 lm_response
, nt_response
,
889 &r
->out
.authoritative
, &flags
,
890 &r
->out
.validation
.sam3
);
894 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
895 struct winbindd_domain
*domain
,
896 struct winbind_LogonControl
*r
)
899 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
900 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
901 WERROR check_result
= WERR_INTERNAL_ERROR
;
903 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
905 return WERR_NOT_ENOUGH_MEMORY
;
908 if (domain
->internal
) {
909 check_result
= WERR_OK
;
914 * For now we just force a reconnect
916 * TODO: take care of the optional '\dcname'
918 invalidate_cm_connection(domain
);
919 domain
->conn
.netlogon_force_reauth
= true;
920 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
921 reset_cm_connection_on_error(domain
, status
);
922 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
923 status
= NT_STATUS_NO_LOGON_SERVERS
;
925 if (!NT_STATUS_IS_OK(status
)) {
926 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
927 __func__
, domain
->name
, domain
->alt_name
,
930 * Here we return a top level error!
931 * This is different than TC_QUERY or TC_VERIFY.
933 return ntstatus_to_werror(status
);
935 check_result
= WERR_OK
;
938 info2
->pdc_connection_status
= WERR_OK
;
939 if (domain
->dcname
!= NULL
) {
940 info2
->flags
|= NETLOGON_HAS_IP
;
941 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
942 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
944 if (info2
->trusted_dc_name
== NULL
) {
945 return WERR_NOT_ENOUGH_MEMORY
;
948 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
949 if (info2
->trusted_dc_name
== NULL
) {
950 return WERR_NOT_ENOUGH_MEMORY
;
953 info2
->tc_connection_status
= check_result
;
955 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
956 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
957 "pdc_connection[%s] tc_connection[%s]\n",
958 __func__
, domain
->name
, domain
->alt_name
,
960 win_errstr(info2
->pdc_connection_status
),
961 win_errstr(info2
->tc_connection_status
)));
964 r
->out
.query
->info2
= info2
;
966 DEBUG(5, ("%s: succeeded.\n", __func__
));
970 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
971 struct winbindd_domain
*domain
,
972 struct winbind_LogonControl
*r
)
975 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
976 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
977 WERROR check_result
= WERR_INTERNAL_ERROR
;
979 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
981 return WERR_NOT_ENOUGH_MEMORY
;
984 if (domain
->internal
) {
985 check_result
= WERR_OK
;
989 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
990 reset_cm_connection_on_error(domain
, status
);
991 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
992 status
= NT_STATUS_NO_LOGON_SERVERS
;
994 if (!NT_STATUS_IS_OK(status
)) {
995 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
997 check_result
= ntstatus_to_werror(status
);
1000 check_result
= WERR_OK
;
1003 info2
->pdc_connection_status
= WERR_OK
;
1004 if (domain
->dcname
!= NULL
) {
1005 info2
->flags
|= NETLOGON_HAS_IP
;
1006 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1007 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1009 if (info2
->trusted_dc_name
== NULL
) {
1010 return WERR_NOT_ENOUGH_MEMORY
;
1013 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1014 if (info2
->trusted_dc_name
== NULL
) {
1015 return WERR_NOT_ENOUGH_MEMORY
;
1018 info2
->tc_connection_status
= check_result
;
1020 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1021 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1022 "pdc_connection[%s] tc_connection[%s]\n",
1023 __func__
, domain
->name
, domain
->alt_name
,
1025 win_errstr(info2
->pdc_connection_status
),
1026 win_errstr(info2
->tc_connection_status
)));
1029 r
->out
.query
->info2
= info2
;
1031 DEBUG(5, ("%s: succeeded.\n", __func__
));
1035 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1036 struct winbindd_domain
*domain
,
1037 struct winbind_LogonControl
*r
)
1039 TALLOC_CTX
*frame
= talloc_stackframe();
1042 struct lsa_String trusted_domain_name
= {};
1043 struct lsa_StringLarge trusted_domain_name_l
= {};
1044 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1045 struct policy_handle local_lsa_policy
= {};
1046 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1047 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1048 struct cli_credentials
*creds
= NULL
;
1049 struct samr_Password
*cur_nt_hash
= NULL
;
1050 uint32_t trust_attributes
= 0;
1051 struct samr_Password new_owf_password
= {};
1053 struct samr_Password old_owf_password
= {};
1055 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1056 bool fetch_fti
= false;
1057 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1058 struct netr_TrustInfo
*trust_info
= NULL
;
1059 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1060 struct dcerpc_binding_handle
*b
= NULL
;
1061 WERROR check_result
= WERR_INTERNAL_ERROR
;
1062 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1065 trusted_domain_name
.string
= domain
->name
;
1066 trusted_domain_name_l
.string
= domain
->name
;
1068 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1069 if (info2
== NULL
) {
1071 return WERR_NOT_ENOUGH_MEMORY
;
1074 if (domain
->internal
) {
1075 check_result
= WERR_OK
;
1079 status
= pdb_get_trust_credentials(domain
->name
,
1083 if (NT_STATUS_IS_OK(status
)) {
1084 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1088 if (!domain
->primary
) {
1089 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1091 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1093 if (!NT_STATUS_IS_OK(status
)) {
1094 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1095 __location__
, __func__
, nt_errstr(status
)));
1097 return WERR_INTERNAL_ERROR
;
1099 local_lsa
= local_lsa_pipe
->binding_handle
;
1101 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1103 &trusted_domain_name
,
1104 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1106 if (!NT_STATUS_IS_OK(status
)) {
1107 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1108 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1110 return WERR_INTERNAL_ERROR
;
1112 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1113 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1114 __location__
, __func__
, domain
->name
));
1116 return WERR_NO_SUCH_DOMAIN
;
1118 if (!NT_STATUS_IS_OK(result
)) {
1119 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1120 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1122 return WERR_INTERNAL_ERROR
;
1125 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1126 "returned no trusted domain information\n",
1127 __location__
, __func__
));
1129 return WERR_INTERNAL_ERROR
;
1132 local_tdo
= &tdi
->info_ex
;
1133 trust_attributes
= local_tdo
->trust_attributes
;
1136 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1137 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1139 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1141 &trusted_domain_name
,
1142 LSA_FOREST_TRUST_DOMAIN_INFO
,
1144 if (!NT_STATUS_IS_OK(status
)) {
1145 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1146 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1148 return WERR_INTERNAL_ERROR
;
1150 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1151 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1152 __func__
, domain
->name
));
1155 result
= NT_STATUS_OK
;
1157 if (!NT_STATUS_IS_OK(result
)) {
1158 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1159 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1161 return WERR_INTERNAL_ERROR
;
1164 TALLOC_FREE(old_fti
);
1168 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1169 reset_cm_connection_on_error(domain
, status
);
1170 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1171 status
= NT_STATUS_NO_LOGON_SERVERS
;
1173 if (!NT_STATUS_IS_OK(status
)) {
1174 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1175 nt_errstr(status
)));
1176 check_result
= ntstatus_to_werror(status
);
1179 check_result
= WERR_OK
;
1180 b
= netlogon_pipe
->binding_handle
;
1182 if (cur_nt_hash
== NULL
) {
1183 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1188 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1191 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1192 status
= NT_STATUS_NOT_SUPPORTED
;
1194 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1196 status
= NT_STATUS_OK
;
1198 if (!NT_STATUS_IS_OK(status
)) {
1199 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1200 invalidate_cm_connection(domain
);
1204 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1206 domain
->name
, nt_errstr(status
)));
1207 check_result
= ntstatus_to_werror(status
);
1212 if (new_fti
!= NULL
) {
1213 struct lsa_ForestTrustInformation old_fti
= {};
1214 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1215 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1217 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1220 if (!NT_STATUS_IS_OK(status
)) {
1221 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1222 __location__
, __func__
,
1223 domain
->name
, nt_errstr(status
)));
1225 return ntstatus_to_werror(status
);
1228 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1230 &trusted_domain_name_l
,
1231 LSA_FOREST_TRUST_DOMAIN_INFO
,
1233 0, /* check_only=0 => store it! */
1236 if (!NT_STATUS_IS_OK(status
)) {
1237 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1238 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1240 return WERR_INTERNAL_ERROR
;
1242 if (!NT_STATUS_IS_OK(result
)) {
1243 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1244 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1246 return ntstatus_to_werror(result
);
1250 status
= netlogon_creds_cli_ServerGetTrustInfo(domain
->conn
.netlogon_creds
,
1255 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1256 status
= NT_STATUS_NOT_SUPPORTED
;
1258 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1259 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1260 nt_errstr(status
)));
1261 verify_result
= WERR_OK
;
1264 if (!NT_STATUS_IS_OK(status
)) {
1265 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1266 invalidate_cm_connection(domain
);
1270 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1271 nt_errstr(status
)));
1273 if (!dcerpc_binding_handle_is_connected(b
)) {
1274 check_result
= ntstatus_to_werror(status
);
1277 verify_result
= ntstatus_to_werror(status
);
1282 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1283 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1285 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1286 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1291 cmp_new
= memcmp(new_owf_password
.hash
,
1293 sizeof(cur_nt_hash
->hash
));
1294 cmp_old
= memcmp(old_owf_password
.hash
,
1296 sizeof(cur_nt_hash
->hash
));
1297 if (cmp_new
!= 0 && cmp_old
!= 0) {
1298 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1299 "any password known to dcname[%s]\n",
1300 __func__
, domain
->name
, domain
->alt_name
,
1302 verify_result
= WERR_WRONG_PASSWORD
;
1307 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1308 "against the old password known to dcname[%s]\n",
1309 __func__
, domain
->name
, domain
->alt_name
,
1313 verify_result
= WERR_OK
;
1317 verify_result
= check_result
;
1319 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1320 info2
->pdc_connection_status
= verify_result
;
1321 if (domain
->dcname
!= NULL
) {
1322 info2
->flags
|= NETLOGON_HAS_IP
;
1323 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1324 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1326 if (info2
->trusted_dc_name
== NULL
) {
1328 return WERR_NOT_ENOUGH_MEMORY
;
1331 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1332 if (info2
->trusted_dc_name
== NULL
) {
1334 return WERR_NOT_ENOUGH_MEMORY
;
1337 info2
->tc_connection_status
= check_result
;
1339 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1340 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1341 "pdc_connection[%s] tc_connection[%s]\n",
1342 __func__
, domain
->name
, domain
->alt_name
,
1344 win_errstr(info2
->pdc_connection_status
),
1345 win_errstr(info2
->tc_connection_status
)));
1348 r
->out
.query
->info2
= info2
;
1350 DEBUG(5, ("%s: succeeded.\n", __func__
));
1355 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1356 struct winbindd_domain
*domain
,
1357 struct winbind_LogonControl
*r
)
1359 struct messaging_context
*msg_ctx
= winbind_messaging_context();
1361 struct rpc_pipe_client
*netlogon_pipe
;
1362 struct cli_credentials
*creds
= NULL
;
1363 struct samr_Password
*cur_nt_hash
= NULL
;
1364 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1365 struct dcerpc_binding_handle
*b
;
1366 WERROR change_result
= WERR_OK
;
1369 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1370 if (info1
== NULL
) {
1371 return WERR_NOT_ENOUGH_MEMORY
;
1374 if (domain
->internal
) {
1375 return WERR_NOT_SUPPORTED
;
1378 status
= pdb_get_trust_credentials(domain
->name
,
1382 if (NT_STATUS_IS_OK(status
)) {
1383 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1388 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1389 reset_cm_connection_on_error(domain
, status
);
1390 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1391 status
= NT_STATUS_NO_LOGON_SERVERS
;
1393 if (!NT_STATUS_IS_OK(status
)) {
1394 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1395 __func__
, domain
->name
, domain
->alt_name
,
1396 nt_errstr(status
)));
1398 * Here we return a top level error!
1399 * This is different than TC_QUERY or TC_VERIFY.
1401 return ntstatus_to_werror(status
);
1403 b
= netlogon_pipe
->binding_handle
;
1405 if (cur_nt_hash
== NULL
) {
1406 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1409 TALLOC_FREE(cur_nt_hash
);
1411 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
1412 msg_ctx
, b
, domain
->name
,
1414 if (!NT_STATUS_IS_OK(status
)) {
1415 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1416 invalidate_cm_connection(domain
);
1421 DEBUG(1, ("trust_pw_change(%s): %s\n",
1422 domain
->name
, nt_errstr(status
)));
1424 change_result
= ntstatus_to_werror(status
);
1428 change_result
= WERR_OK
;
1431 info1
->pdc_connection_status
= change_result
;
1433 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1434 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1435 "pdc_connection[%s]\n",
1436 __func__
, domain
->name
, domain
->alt_name
,
1438 win_errstr(info1
->pdc_connection_status
)));
1441 r
->out
.query
->info1
= info1
;
1443 DEBUG(5, ("%s: succeeded.\n", __func__
));
1447 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1448 struct winbind_LogonControl
*r
)
1450 struct winbindd_domain
*domain
;
1452 domain
= wb_child_domain();
1453 if (domain
== NULL
) {
1454 return WERR_NO_SUCH_DOMAIN
;
1457 switch (r
->in
.function_code
) {
1458 case NETLOGON_CONTROL_REDISCOVER
:
1459 if (r
->in
.level
!= 2) {
1460 return WERR_INVALID_PARAMETER
;
1462 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1463 case NETLOGON_CONTROL_TC_QUERY
:
1464 if (r
->in
.level
!= 2) {
1465 return WERR_INVALID_PARAMETER
;
1467 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1468 case NETLOGON_CONTROL_TC_VERIFY
:
1469 if (r
->in
.level
!= 2) {
1470 return WERR_INVALID_PARAMETER
;
1472 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1473 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1474 if (r
->in
.level
!= 1) {
1475 return WERR_INVALID_PARAMETER
;
1477 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1482 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1483 __func__
, r
->in
.function_code
));
1484 return WERR_NOT_SUPPORTED
;
1487 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1488 struct winbind_GetForestTrustInformation
*r
)
1490 TALLOC_CTX
*frame
= talloc_stackframe();
1491 NTSTATUS status
, result
;
1492 struct winbindd_domain
*domain
;
1493 struct rpc_pipe_client
*netlogon_pipe
;
1494 struct dcerpc_binding_handle
*b
;
1496 struct lsa_String trusted_domain_name
= {};
1497 struct lsa_StringLarge trusted_domain_name_l
= {};
1498 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1499 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1500 struct lsa_ForestTrustInformation _old_fti
= {};
1501 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1502 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1503 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1504 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1505 bool update_fti
= false;
1506 struct rpc_pipe_client
*local_lsa_pipe
;
1507 struct policy_handle local_lsa_policy
;
1508 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1510 domain
= wb_child_domain();
1511 if (domain
== NULL
) {
1513 return WERR_NO_SUCH_DOMAIN
;
1517 * checking for domain->internal and domain->primary
1518 * makes sure we only do some work when running as DC.
1521 if (domain
->internal
) {
1523 return WERR_NO_SUCH_DOMAIN
;
1526 if (domain
->primary
) {
1528 return WERR_NO_SUCH_DOMAIN
;
1531 trusted_domain_name
.string
= domain
->name
;
1532 trusted_domain_name_l
.string
= domain
->name
;
1534 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1536 if (!NT_STATUS_IS_OK(status
)) {
1537 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1538 __location__
, __func__
, nt_errstr(status
)));
1540 return WERR_INTERNAL_ERROR
;
1542 local_lsa
= local_lsa_pipe
->binding_handle
;
1544 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1546 &trusted_domain_name
,
1547 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1549 if (!NT_STATUS_IS_OK(status
)) {
1550 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1551 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1553 return WERR_INTERNAL_ERROR
;
1555 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1556 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1557 __location__
, __func__
, domain
->name
));
1559 return WERR_NO_SUCH_DOMAIN
;
1561 if (!NT_STATUS_IS_OK(result
)) {
1562 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1563 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1565 return WERR_INTERNAL_ERROR
;
1568 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1569 "returned no trusted domain information\n",
1570 __location__
, __func__
));
1572 return WERR_INTERNAL_ERROR
;
1575 tdo
= &tdi
->info_ex
;
1577 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1578 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1579 __func__
, tdo
->netbios_name
.string
,
1580 tdo
->domain_name
.string
,
1581 (unsigned)tdo
->trust_attributes
));
1583 return WERR_NO_SUCH_DOMAIN
;
1586 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1588 return WERR_INVALID_FLAGS
;
1592 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1593 reset_cm_connection_on_error(domain
, status
);
1594 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1595 status
= NT_STATUS_NO_LOGON_SERVERS
;
1597 if (!NT_STATUS_IS_OK(status
)) {
1598 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1599 nt_errstr(status
)));
1601 return ntstatus_to_werror(status
);
1603 b
= netlogon_pipe
->binding_handle
;
1605 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1608 if (!NT_STATUS_IS_OK(status
)) {
1609 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1610 invalidate_cm_connection(domain
);
1614 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1615 domain
->name
, nt_errstr(status
)));
1617 return ntstatus_to_werror(status
);
1620 *r
->out
.forest_trust_info
= new_fti
;
1622 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1626 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1628 &trusted_domain_name
,
1629 LSA_FOREST_TRUST_DOMAIN_INFO
,
1631 if (!NT_STATUS_IS_OK(status
)) {
1632 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1633 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1635 return WERR_INTERNAL_ERROR
;
1637 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1638 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1639 __func__
, domain
->name
));
1641 old_fti
= &_old_fti
;
1642 result
= NT_STATUS_OK
;
1644 if (!NT_STATUS_IS_OK(result
)) {
1645 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1646 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1648 return WERR_INTERNAL_ERROR
;
1651 if (old_fti
== NULL
) {
1652 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1653 "returned success without returning forest trust information\n",
1654 __location__
, __func__
));
1656 return WERR_INTERNAL_ERROR
;
1663 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1665 if (!NT_STATUS_IS_OK(status
)) {
1666 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1667 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1669 return ntstatus_to_werror(status
);
1672 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1674 &trusted_domain_name_l
,
1675 LSA_FOREST_TRUST_DOMAIN_INFO
,
1677 0, /* check_only=0 => store it! */
1680 if (!NT_STATUS_IS_OK(status
)) {
1681 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1682 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1684 return WERR_INTERNAL_ERROR
;
1686 if (!NT_STATUS_IS_OK(result
)) {
1687 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1688 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1690 return ntstatus_to_werror(result
);
1694 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));