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
->in
.dom_name
? r
->in
.dom_name
: "",
227 r
->out
.sid
, r
->in
.uid
);
230 NTSTATUS
_wbint_Gid2Sid(struct pipes_struct
*p
, struct wbint_Gid2Sid
*r
)
232 return idmap_gid_to_sid(r
->in
.dom_name
? r
->in
.dom_name
: "",
233 r
->out
.sid
, r
->in
.gid
);
236 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
241 status
= idmap_allocate_uid(&xid
);
242 if (!NT_STATUS_IS_OK(status
)) {
245 *r
->out
.uid
= xid
.id
;
249 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
254 status
= idmap_allocate_gid(&xid
);
255 if (!NT_STATUS_IS_OK(status
)) {
258 *r
->out
.gid
= xid
.id
;
262 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
264 struct winbindd_domain
*domain
= wb_child_domain();
267 if (domain
== NULL
) {
268 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
271 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
273 reset_cm_connection_on_error(domain
, status
);
277 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
278 struct wbint_LookupUserAliases
*r
)
280 struct winbindd_domain
*domain
= wb_child_domain();
283 if (domain
== NULL
) {
284 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
287 status
= domain
->methods
->lookup_useraliases(
288 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
289 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
290 reset_cm_connection_on_error(domain
, status
);
294 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
295 struct wbint_LookupUserGroups
*r
)
297 struct winbindd_domain
*domain
= wb_child_domain();
300 if (domain
== NULL
) {
301 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
304 status
= domain
->methods
->lookup_usergroups(
305 domain
, p
->mem_ctx
, r
->in
.sid
,
306 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
307 reset_cm_connection_on_error(domain
, status
);
311 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
312 struct wbint_QuerySequenceNumber
*r
)
314 struct winbindd_domain
*domain
= wb_child_domain();
317 if (domain
== NULL
) {
318 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
321 status
= domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
322 reset_cm_connection_on_error(domain
, status
);
326 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
327 struct wbint_LookupGroupMembers
*r
)
329 struct winbindd_domain
*domain
= wb_child_domain();
330 uint32_t i
, num_names
;
331 struct dom_sid
*sid_mem
;
333 uint32_t *name_types
;
336 if (domain
== NULL
) {
337 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
340 status
= domain
->methods
->lookup_groupmem(
341 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
342 &num_names
, &sid_mem
, &names
, &name_types
);
343 reset_cm_connection_on_error(domain
, status
);
344 if (!NT_STATUS_IS_OK(status
)) {
348 r
->out
.members
->num_principals
= num_names
;
349 r
->out
.members
->principals
= talloc_array(
350 r
->out
.members
, struct wbint_Principal
, num_names
);
351 if (r
->out
.members
->principals
== NULL
) {
352 return NT_STATUS_NO_MEMORY
;
355 for (i
=0; i
<num_names
; i
++) {
356 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
357 sid_copy(&m
->sid
, &sid_mem
[i
]);
358 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
359 m
->type
= (enum lsa_SidType
)name_types
[i
];
365 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
366 struct wbint_QueryUserList
*r
)
368 struct winbindd_domain
*domain
= wb_child_domain();
371 if (domain
== NULL
) {
372 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
375 status
= domain
->methods
->query_user_list(
376 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
377 &r
->out
.users
->userinfos
);
378 reset_cm_connection_on_error(domain
, status
);
382 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
383 struct wbint_QueryGroupList
*r
)
385 struct winbindd_domain
*domain
= wb_child_domain();
387 uint32_t num_local_groups
= 0;
388 struct wb_acct_info
*local_groups
= NULL
;
389 uint32_t num_dom_groups
= 0;
390 struct wb_acct_info
*dom_groups
= NULL
;
392 uint64_t num_total
= 0;
393 struct wbint_Principal
*result
;
395 bool include_local_groups
= false;
397 if (domain
== NULL
) {
398 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
401 switch (lp_server_role()) {
402 case ROLE_ACTIVE_DIRECTORY_DC
:
403 if (domain
->internal
) {
405 * we want to include local groups
406 * for BUILTIN and WORKGROUP
408 include_local_groups
= true;
413 * We might include local groups in more
414 * setups later, but that requires more work
420 if (include_local_groups
) {
421 status
= domain
->methods
->enum_local_groups(domain
, talloc_tos(),
424 reset_cm_connection_on_error(domain
, status
);
425 if (!NT_STATUS_IS_OK(status
)) {
430 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
433 reset_cm_connection_on_error(domain
, status
);
434 if (!NT_STATUS_IS_OK(status
)) {
438 num_total
= num_local_groups
+ num_dom_groups
;
439 if (num_total
> UINT32_MAX
) {
440 return NT_STATUS_INTERNAL_ERROR
;
443 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
445 if (result
== NULL
) {
446 return NT_STATUS_NO_MEMORY
;
449 for (i
= 0; i
< num_local_groups
; i
++) {
450 struct wb_acct_info
*lg
= &local_groups
[i
];
451 struct wbint_Principal
*rg
= &result
[ti
++];
453 sid_compose(&rg
->sid
, &domain
->sid
, lg
->rid
);
454 rg
->type
= SID_NAME_ALIAS
;
455 rg
->name
= talloc_strdup(result
, lg
->acct_name
);
456 if (rg
->name
== NULL
) {
458 TALLOC_FREE(dom_groups
);
459 TALLOC_FREE(local_groups
);
460 return NT_STATUS_NO_MEMORY
;
463 num_local_groups
= 0;
464 TALLOC_FREE(local_groups
);
466 for (i
= 0; i
< num_dom_groups
; i
++) {
467 struct wb_acct_info
*dg
= &dom_groups
[i
];
468 struct wbint_Principal
*rg
= &result
[ti
++];
470 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
471 rg
->type
= SID_NAME_DOM_GRP
;
472 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
473 if (rg
->name
== NULL
) {
475 TALLOC_FREE(dom_groups
);
476 TALLOC_FREE(local_groups
);
477 return NT_STATUS_NO_MEMORY
;
481 TALLOC_FREE(dom_groups
);
483 r
->out
.groups
->num_principals
= ti
;
484 r
->out
.groups
->principals
= result
;
489 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
491 struct winbindd_domain
*domain
= wb_child_domain();
492 struct rpc_pipe_client
*netlogon_pipe
;
493 struct netr_DsRGetDCNameInfo
*dc_info
;
496 unsigned int orig_timeout
;
497 struct dcerpc_binding_handle
*b
;
499 if (domain
== NULL
) {
500 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
501 r
->in
.domain_name
, r
->in
.domain_guid
,
502 r
->in
.site_name
? r
->in
.site_name
: "",
507 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
509 reset_cm_connection_on_error(domain
, status
);
510 if (!NT_STATUS_IS_OK(status
)) {
511 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
515 b
= netlogon_pipe
->binding_handle
;
517 /* This call can take a long time - allow the server to time out.
518 35 seconds should do it. */
520 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
522 if (domain
->active_directory
) {
523 status
= dcerpc_netr_DsRGetDCName(b
,
524 p
->mem_ctx
, domain
->dcname
,
525 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
526 r
->in
.flags
, r
->out
.dc_info
, &werr
);
527 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
530 if (reset_cm_connection_on_error(domain
, status
)) {
532 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
534 reset_cm_connection_on_error(domain
, status
);
535 if (!NT_STATUS_IS_OK(status
)) {
536 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
540 b
= netlogon_pipe
->binding_handle
;
542 /* This call can take a long time - allow the server to time out.
543 35 seconds should do it. */
545 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
550 * Fallback to less capable methods
553 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
554 if (dc_info
== NULL
) {
555 status
= NT_STATUS_NO_MEMORY
;
559 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
560 status
= dcerpc_netr_GetDcName(b
,
561 p
->mem_ctx
, domain
->dcname
,
562 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
564 status
= dcerpc_netr_GetAnyDCName(b
,
565 p
->mem_ctx
, domain
->dcname
,
566 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
569 reset_cm_connection_on_error(domain
, status
);
570 if (!NT_STATUS_IS_OK(status
)) {
571 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
575 if (!W_ERROR_IS_OK(werr
)) {
576 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
578 status
= werror_to_ntstatus(werr
);
582 *r
->out
.dc_info
= dc_info
;
583 status
= NT_STATUS_OK
;
586 /* And restore our original timeout. */
587 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
592 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
594 struct winbindd_domain
*domain
= wb_child_domain();
597 enum lsa_SidType
*types
;
598 struct wbint_Principal
*result
;
602 if (domain
== NULL
) {
603 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
606 status
= domain
->methods
->rids_to_names(
607 domain
, talloc_tos(), r
->in
.domain_sid
, r
->in
.rids
->rids
,
608 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
609 reset_cm_connection_on_error(domain
, status
);
610 if (!NT_STATUS_IS_OK(status
)) {
614 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
616 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
617 r
->in
.rids
->num_rids
);
618 if (result
== NULL
) {
619 return NT_STATUS_NO_MEMORY
;
622 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
623 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
624 r
->in
.rids
->rids
[i
]);
625 result
[i
].type
= types
[i
];
626 result
[i
].name
= talloc_move(result
, &names
[i
]);
631 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
632 r
->out
.names
->principals
= result
;
636 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
637 struct wbint_CheckMachineAccount
*r
)
639 struct winbindd_domain
*domain
;
643 domain
= wb_child_domain();
644 if (domain
== NULL
) {
645 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
649 invalidate_cm_connection(domain
);
650 domain
->conn
.netlogon_force_reauth
= true;
653 struct rpc_pipe_client
*netlogon_pipe
;
654 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
657 /* There is a race condition between fetching the trust account
658 password and the periodic machine password change. So it's
659 possible that the trust account password has been changed on us.
660 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
662 #define MAX_RETRIES 3
664 if ((num_retries
< MAX_RETRIES
)
665 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
670 if (!NT_STATUS_IS_OK(status
)) {
671 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
675 /* Pass back result code - zero for success, other values for
676 specific failures. */
678 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
679 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
682 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
683 ("Checking the trust account password for domain %s returned %s\n",
684 domain
->name
, nt_errstr(status
)));
689 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
690 struct wbint_ChangeMachineAccount
*r
)
692 struct messaging_context
*msg_ctx
= winbind_messaging_context();
693 struct winbindd_domain
*domain
;
695 struct rpc_pipe_client
*netlogon_pipe
;
697 domain
= wb_child_domain();
698 if (domain
== NULL
) {
699 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
702 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
703 if (!NT_STATUS_IS_OK(status
)) {
704 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
708 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
710 netlogon_pipe
->binding_handle
,
714 /* Pass back result code - zero for success, other values for
715 specific failures. */
717 DEBUG(3,("domain %s secret %s\n", domain
->name
,
718 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
721 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
722 ("Changing the trust account password for domain %s returned %s\n",
723 domain
->name
, nt_errstr(status
)));
728 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
731 struct winbindd_domain
*domain
;
732 struct rpc_pipe_client
*netlogon_pipe
;
733 union netr_CONTROL_QUERY_INFORMATION info
;
735 fstring logon_server
;
736 struct dcerpc_binding_handle
*b
;
739 domain
= wb_child_domain();
740 if (domain
== NULL
) {
741 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
745 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
746 if (NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
748 * Retry to open new connection with new kerberos ticket.
750 invalidate_cm_connection(domain
);
751 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
754 reset_cm_connection_on_error(domain
, status
);
755 if (!NT_STATUS_IS_OK(status
)) {
756 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
761 b
= netlogon_pipe
->binding_handle
;
763 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
764 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
765 if (*r
->out
.dcname
== NULL
) {
766 DEBUG(2, ("Could not allocate memory\n"));
767 return NT_STATUS_NO_MEMORY
;
771 * This provokes a WERR_NOT_SUPPORTED error message. This is
772 * documented in the wspp docs. I could not get a successful
773 * call to work, but the main point here is testing that the
774 * netlogon pipe works.
776 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
777 logon_server
, NETLOGON_CONTROL_QUERY
,
780 if (!dcerpc_binding_handle_is_connected(b
) && !retry
) {
781 DEBUG(10, ("Session might have expired. "
782 "Reconnect and retry once.\n"));
783 invalidate_cm_connection(domain
);
788 reset_cm_connection_on_error(domain
, status
);
789 if (!NT_STATUS_IS_OK(status
)) {
790 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
795 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
796 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
797 "WERR_NOT_SUPPORTED\n",
799 return werror_to_ntstatus(werr
);
802 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
806 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
807 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
809 struct winbindd_domain
*domain
;
811 struct rpc_pipe_client
*netlogon_pipe
;
813 domain
= wb_child_domain();
814 if (domain
== NULL
) {
815 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
818 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
819 if (!NT_STATUS_IS_OK(status
)) {
820 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
824 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain
->conn
.netlogon_creds
,
825 netlogon_pipe
->binding_handle
,
830 /* Pass back result code - zero for success, other values for
831 specific failures. */
833 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
834 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
837 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
838 ("Update of DNS records via RW DC %s returned %s\n",
839 domain
->name
, nt_errstr(status
)));
844 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
845 struct winbind_SamLogon
*r
)
847 struct winbindd_domain
*domain
;
849 DATA_BLOB lm_response
, nt_response
;
850 domain
= wb_child_domain();
851 if (domain
== NULL
) {
852 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
855 /* TODO: Handle interactive logons here */
856 if (r
->in
.validation_level
!= 3 ||
857 r
->in
.logon
.network
== NULL
||
858 (r
->in
.logon_level
!= NetlogonNetworkInformation
859 && r
->in
.logon_level
!= NetlogonNetworkTransitiveInformation
)) {
860 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
864 lm_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->lm
.data
, r
->in
.logon
.network
->lm
.length
);
865 nt_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->nt
.data
, r
->in
.logon
.network
->nt
.length
);
867 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
868 r
->in
.logon
.network
->identity_info
.parameter_control
,
869 r
->in
.logon
.network
->identity_info
.account_name
.string
,
870 r
->in
.logon
.network
->identity_info
.domain_name
.string
,
871 r
->in
.logon
.network
->identity_info
.workstation
.string
,
872 r
->in
.logon
.network
->challenge
,
873 lm_response
, nt_response
, &r
->out
.validation
.sam3
);
877 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
878 struct winbindd_domain
*domain
,
879 struct winbind_LogonControl
*r
)
882 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
883 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
884 WERROR check_result
= WERR_INTERNAL_ERROR
;
886 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
891 if (domain
->internal
) {
892 check_result
= WERR_OK
;
897 * For now we just force a reconnect
899 * TODO: take care of the optional '\dcname'
901 invalidate_cm_connection(domain
);
902 domain
->conn
.netlogon_force_reauth
= true;
903 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
904 reset_cm_connection_on_error(domain
, status
);
905 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
906 status
= NT_STATUS_NO_LOGON_SERVERS
;
908 if (!NT_STATUS_IS_OK(status
)) {
909 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
910 __func__
, domain
->name
, domain
->alt_name
,
913 * Here we return a top level error!
914 * This is different than TC_QUERY or TC_VERIFY.
916 return ntstatus_to_werror(status
);
918 check_result
= WERR_OK
;
921 info2
->pdc_connection_status
= WERR_OK
;
922 if (domain
->dcname
!= NULL
) {
923 info2
->flags
|= NETLOGON_HAS_IP
;
924 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
925 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
927 if (info2
->trusted_dc_name
== NULL
) {
931 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
932 if (info2
->trusted_dc_name
== NULL
) {
936 info2
->tc_connection_status
= check_result
;
938 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
939 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
940 "pdc_connection[%s] tc_connection[%s]\n",
941 __func__
, domain
->name
, domain
->alt_name
,
943 win_errstr(info2
->pdc_connection_status
),
944 win_errstr(info2
->tc_connection_status
)));
947 r
->out
.query
->info2
= info2
;
949 DEBUG(5, ("%s: succeeded.\n", __func__
));
953 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
954 struct winbindd_domain
*domain
,
955 struct winbind_LogonControl
*r
)
958 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
959 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
960 WERROR check_result
= WERR_INTERNAL_ERROR
;
962 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
967 if (domain
->internal
) {
968 check_result
= WERR_OK
;
972 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
973 reset_cm_connection_on_error(domain
, status
);
974 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
975 status
= NT_STATUS_NO_LOGON_SERVERS
;
977 if (!NT_STATUS_IS_OK(status
)) {
978 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
980 check_result
= ntstatus_to_werror(status
);
983 check_result
= WERR_OK
;
986 info2
->pdc_connection_status
= WERR_OK
;
987 if (domain
->dcname
!= NULL
) {
988 info2
->flags
|= NETLOGON_HAS_IP
;
989 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
990 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
992 if (info2
->trusted_dc_name
== NULL
) {
996 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
997 if (info2
->trusted_dc_name
== NULL
) {
1001 info2
->tc_connection_status
= check_result
;
1003 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1004 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1005 "pdc_connection[%s] tc_connection[%s]\n",
1006 __func__
, domain
->name
, domain
->alt_name
,
1008 win_errstr(info2
->pdc_connection_status
),
1009 win_errstr(info2
->tc_connection_status
)));
1012 r
->out
.query
->info2
= info2
;
1014 DEBUG(5, ("%s: succeeded.\n", __func__
));
1018 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1019 struct winbindd_domain
*domain
,
1020 struct winbind_LogonControl
*r
)
1022 TALLOC_CTX
*frame
= talloc_stackframe();
1025 struct lsa_String trusted_domain_name
= {};
1026 struct lsa_StringLarge trusted_domain_name_l
= {};
1027 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1028 struct policy_handle local_lsa_policy
= {};
1029 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1030 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1031 struct cli_credentials
*creds
= NULL
;
1032 struct samr_Password
*cur_nt_hash
= NULL
;
1033 uint32_t trust_attributes
= 0;
1034 struct samr_Password new_owf_password
= {};
1036 struct samr_Password old_owf_password
= {};
1038 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1039 bool fetch_fti
= false;
1040 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1041 struct netr_TrustInfo
*trust_info
= NULL
;
1042 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1043 struct dcerpc_binding_handle
*b
= NULL
;
1044 WERROR check_result
= WERR_INTERNAL_ERROR
;
1045 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1048 trusted_domain_name
.string
= domain
->name
;
1049 trusted_domain_name_l
.string
= domain
->name
;
1051 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1052 if (info2
== NULL
) {
1057 if (domain
->internal
) {
1058 check_result
= WERR_OK
;
1062 status
= pdb_get_trust_credentials(domain
->name
,
1066 if (NT_STATUS_IS_OK(status
)) {
1067 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1071 if (!domain
->primary
) {
1072 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1074 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1076 if (!NT_STATUS_IS_OK(status
)) {
1077 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1078 __location__
, __func__
, nt_errstr(status
)));
1080 return WERR_INTERNAL_ERROR
;
1082 local_lsa
= local_lsa_pipe
->binding_handle
;
1084 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1086 &trusted_domain_name
,
1087 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1089 if (!NT_STATUS_IS_OK(status
)) {
1090 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1091 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1093 return WERR_INTERNAL_ERROR
;
1095 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1096 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1097 __location__
, __func__
, domain
->name
));
1099 return WERR_NO_SUCH_DOMAIN
;
1101 if (!NT_STATUS_IS_OK(result
)) {
1102 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1103 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1105 return WERR_INTERNAL_ERROR
;
1108 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1109 "returned no trusted domain information\n",
1110 __location__
, __func__
));
1112 return WERR_INTERNAL_ERROR
;
1115 local_tdo
= &tdi
->info_ex
;
1116 trust_attributes
= local_tdo
->trust_attributes
;
1119 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1120 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1122 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1124 &trusted_domain_name
,
1125 LSA_FOREST_TRUST_DOMAIN_INFO
,
1127 if (!NT_STATUS_IS_OK(status
)) {
1128 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1129 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1131 return WERR_INTERNAL_ERROR
;
1133 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1134 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1135 __func__
, domain
->name
));
1138 result
= NT_STATUS_OK
;
1140 if (!NT_STATUS_IS_OK(result
)) {
1141 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1142 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1144 return WERR_INTERNAL_ERROR
;
1147 TALLOC_FREE(old_fti
);
1151 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1152 reset_cm_connection_on_error(domain
, status
);
1153 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1154 status
= NT_STATUS_NO_LOGON_SERVERS
;
1156 if (!NT_STATUS_IS_OK(status
)) {
1157 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1158 nt_errstr(status
)));
1159 check_result
= ntstatus_to_werror(status
);
1162 check_result
= WERR_OK
;
1163 b
= netlogon_pipe
->binding_handle
;
1165 if (cur_nt_hash
== NULL
) {
1166 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1171 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1174 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1175 status
= NT_STATUS_NOT_SUPPORTED
;
1177 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1179 status
= NT_STATUS_OK
;
1181 if (!NT_STATUS_IS_OK(status
)) {
1182 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1183 invalidate_cm_connection(domain
);
1187 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1189 domain
->name
, nt_errstr(status
)));
1190 check_result
= ntstatus_to_werror(status
);
1195 if (new_fti
!= NULL
) {
1196 struct lsa_ForestTrustInformation old_fti
= {};
1197 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1198 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1200 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1203 if (!NT_STATUS_IS_OK(status
)) {
1204 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1205 __location__
, __func__
,
1206 domain
->name
, nt_errstr(status
)));
1208 return ntstatus_to_werror(status
);
1211 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1213 &trusted_domain_name_l
,
1214 LSA_FOREST_TRUST_DOMAIN_INFO
,
1216 0, /* check_only=0 => store it! */
1219 if (!NT_STATUS_IS_OK(status
)) {
1220 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1221 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1223 return WERR_INTERNAL_ERROR
;
1225 if (!NT_STATUS_IS_OK(result
)) {
1226 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1227 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1229 return ntstatus_to_werror(result
);
1233 status
= netlogon_creds_cli_ServerGetTrustInfo(domain
->conn
.netlogon_creds
,
1238 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1239 status
= NT_STATUS_NOT_SUPPORTED
;
1241 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1242 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1243 nt_errstr(status
)));
1244 verify_result
= WERR_OK
;
1247 if (!NT_STATUS_IS_OK(status
)) {
1248 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1249 invalidate_cm_connection(domain
);
1253 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1254 nt_errstr(status
)));
1256 if (!dcerpc_binding_handle_is_connected(b
)) {
1257 check_result
= ntstatus_to_werror(status
);
1260 verify_result
= ntstatus_to_werror(status
);
1265 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1266 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1268 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1269 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1274 cmp_new
= memcmp(new_owf_password
.hash
,
1276 sizeof(cur_nt_hash
->hash
));
1277 cmp_old
= memcmp(old_owf_password
.hash
,
1279 sizeof(cur_nt_hash
->hash
));
1280 if (cmp_new
!= 0 && cmp_old
!= 0) {
1281 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1282 "any password known to dcname[%s]\n",
1283 __func__
, domain
->name
, domain
->alt_name
,
1285 verify_result
= WERR_WRONG_PASSWORD
;
1290 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1291 "against the old password known to dcname[%s]\n",
1292 __func__
, domain
->name
, domain
->alt_name
,
1296 verify_result
= WERR_OK
;
1300 verify_result
= check_result
;
1302 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1303 info2
->pdc_connection_status
= verify_result
;
1304 if (domain
->dcname
!= NULL
) {
1305 info2
->flags
|= NETLOGON_HAS_IP
;
1306 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1307 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1309 if (info2
->trusted_dc_name
== NULL
) {
1314 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1315 if (info2
->trusted_dc_name
== NULL
) {
1320 info2
->tc_connection_status
= check_result
;
1322 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1323 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1324 "pdc_connection[%s] tc_connection[%s]\n",
1325 __func__
, domain
->name
, domain
->alt_name
,
1327 win_errstr(info2
->pdc_connection_status
),
1328 win_errstr(info2
->tc_connection_status
)));
1331 r
->out
.query
->info2
= info2
;
1333 DEBUG(5, ("%s: succeeded.\n", __func__
));
1338 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1339 struct winbindd_domain
*domain
,
1340 struct winbind_LogonControl
*r
)
1342 struct messaging_context
*msg_ctx
= winbind_messaging_context();
1344 struct rpc_pipe_client
*netlogon_pipe
;
1345 struct cli_credentials
*creds
= NULL
;
1346 struct samr_Password
*cur_nt_hash
= NULL
;
1347 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1348 struct dcerpc_binding_handle
*b
;
1349 WERROR change_result
= WERR_OK
;
1352 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1353 if (info1
== NULL
) {
1357 if (domain
->internal
) {
1358 return WERR_NOT_SUPPORTED
;
1361 status
= pdb_get_trust_credentials(domain
->name
,
1365 if (NT_STATUS_IS_OK(status
)) {
1366 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1371 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1372 reset_cm_connection_on_error(domain
, status
);
1373 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1374 status
= NT_STATUS_NO_LOGON_SERVERS
;
1376 if (!NT_STATUS_IS_OK(status
)) {
1377 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1378 __func__
, domain
->name
, domain
->alt_name
,
1379 nt_errstr(status
)));
1381 * Here we return a top level error!
1382 * This is different than TC_QUERY or TC_VERIFY.
1384 return ntstatus_to_werror(status
);
1386 b
= netlogon_pipe
->binding_handle
;
1388 if (cur_nt_hash
== NULL
) {
1389 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1392 TALLOC_FREE(cur_nt_hash
);
1394 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
1395 msg_ctx
, b
, domain
->name
,
1397 if (!NT_STATUS_IS_OK(status
)) {
1398 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1399 invalidate_cm_connection(domain
);
1404 DEBUG(1, ("trust_pw_change(%s): %s\n",
1405 domain
->name
, nt_errstr(status
)));
1407 change_result
= ntstatus_to_werror(status
);
1411 change_result
= WERR_OK
;
1414 info1
->pdc_connection_status
= change_result
;
1416 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1417 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1418 "pdc_connection[%s]\n",
1419 __func__
, domain
->name
, domain
->alt_name
,
1421 win_errstr(info1
->pdc_connection_status
)));
1424 r
->out
.query
->info1
= info1
;
1426 DEBUG(5, ("%s: succeeded.\n", __func__
));
1430 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1431 struct winbind_LogonControl
*r
)
1433 struct winbindd_domain
*domain
;
1435 domain
= wb_child_domain();
1436 if (domain
== NULL
) {
1437 return WERR_NO_SUCH_DOMAIN
;
1440 switch (r
->in
.function_code
) {
1441 case NETLOGON_CONTROL_REDISCOVER
:
1442 if (r
->in
.level
!= 2) {
1443 return WERR_INVALID_PARAMETER
;
1445 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1446 case NETLOGON_CONTROL_TC_QUERY
:
1447 if (r
->in
.level
!= 2) {
1448 return WERR_INVALID_PARAMETER
;
1450 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1451 case NETLOGON_CONTROL_TC_VERIFY
:
1452 if (r
->in
.level
!= 2) {
1453 return WERR_INVALID_PARAMETER
;
1455 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1456 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1457 if (r
->in
.level
!= 1) {
1458 return WERR_INVALID_PARAMETER
;
1460 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1465 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1466 __func__
, r
->in
.function_code
));
1467 return WERR_NOT_SUPPORTED
;
1470 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1471 struct winbind_GetForestTrustInformation
*r
)
1473 TALLOC_CTX
*frame
= talloc_stackframe();
1474 NTSTATUS status
, result
;
1475 struct winbindd_domain
*domain
;
1476 struct rpc_pipe_client
*netlogon_pipe
;
1477 struct dcerpc_binding_handle
*b
;
1479 struct lsa_String trusted_domain_name
= {};
1480 struct lsa_StringLarge trusted_domain_name_l
= {};
1481 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1482 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1483 struct lsa_ForestTrustInformation _old_fti
= {};
1484 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1485 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1486 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1487 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1488 bool update_fti
= false;
1489 struct rpc_pipe_client
*local_lsa_pipe
;
1490 struct policy_handle local_lsa_policy
;
1491 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1493 domain
= wb_child_domain();
1494 if (domain
== NULL
) {
1496 return WERR_NO_SUCH_DOMAIN
;
1500 * checking for domain->internal and domain->primary
1501 * makes sure we only do some work when running as DC.
1504 if (domain
->internal
) {
1506 return WERR_NO_SUCH_DOMAIN
;
1509 if (domain
->primary
) {
1511 return WERR_NO_SUCH_DOMAIN
;
1514 trusted_domain_name
.string
= domain
->name
;
1515 trusted_domain_name_l
.string
= domain
->name
;
1517 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1519 if (!NT_STATUS_IS_OK(status
)) {
1520 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1521 __location__
, __func__
, nt_errstr(status
)));
1523 return WERR_INTERNAL_ERROR
;
1525 local_lsa
= local_lsa_pipe
->binding_handle
;
1527 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1529 &trusted_domain_name
,
1530 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1532 if (!NT_STATUS_IS_OK(status
)) {
1533 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1534 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1536 return WERR_INTERNAL_ERROR
;
1538 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1539 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1540 __location__
, __func__
, domain
->name
));
1542 return WERR_NO_SUCH_DOMAIN
;
1544 if (!NT_STATUS_IS_OK(result
)) {
1545 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1546 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1548 return WERR_INTERNAL_ERROR
;
1551 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1552 "returned no trusted domain information\n",
1553 __location__
, __func__
));
1555 return WERR_INTERNAL_ERROR
;
1558 tdo
= &tdi
->info_ex
;
1560 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1561 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1562 __func__
, tdo
->netbios_name
.string
,
1563 tdo
->domain_name
.string
,
1564 (unsigned)tdo
->trust_attributes
));
1566 return WERR_NO_SUCH_DOMAIN
;
1569 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1571 return WERR_INVALID_FLAGS
;
1575 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1576 reset_cm_connection_on_error(domain
, status
);
1577 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1578 status
= NT_STATUS_NO_LOGON_SERVERS
;
1580 if (!NT_STATUS_IS_OK(status
)) {
1581 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1582 nt_errstr(status
)));
1584 return ntstatus_to_werror(status
);
1586 b
= netlogon_pipe
->binding_handle
;
1588 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1591 if (!NT_STATUS_IS_OK(status
)) {
1592 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1593 invalidate_cm_connection(domain
);
1597 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1598 domain
->name
, nt_errstr(status
)));
1600 return ntstatus_to_werror(status
);
1603 *r
->out
.forest_trust_info
= new_fti
;
1605 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1609 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1611 &trusted_domain_name
,
1612 LSA_FOREST_TRUST_DOMAIN_INFO
,
1614 if (!NT_STATUS_IS_OK(status
)) {
1615 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1616 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1618 return WERR_INTERNAL_ERROR
;
1620 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1621 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1622 __func__
, domain
->name
));
1624 old_fti
= &_old_fti
;
1625 result
= NT_STATUS_OK
;
1627 if (!NT_STATUS_IS_OK(result
)) {
1628 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1629 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1631 return WERR_INTERNAL_ERROR
;
1634 if (old_fti
== NULL
) {
1635 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1636 "returned success without returning forest trust information\n",
1637 __location__
, __func__
));
1639 return WERR_INTERNAL_ERROR
;
1646 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1648 if (!NT_STATUS_IS_OK(status
)) {
1649 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1650 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1652 return ntstatus_to_werror(status
);
1655 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1657 &trusted_domain_name_l
,
1658 LSA_FOREST_TRUST_DOMAIN_INFO
,
1660 0, /* check_only=0 => store it! */
1663 if (!NT_STATUS_IS_OK(status
)) {
1664 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1665 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1667 return WERR_INTERNAL_ERROR
;
1669 if (!NT_STATUS_IS_OK(result
)) {
1670 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1671 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1673 return ntstatus_to_werror(result
);
1677 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));