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
)
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 (m
->status
== ID_MAPPED
) {
195 ids
[i
].xid
.id
= UINT32_MAX
;
196 ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
202 status
= NT_STATUS_NO_MEMORY
;
204 TALLOC_FREE(id_map_ptrs
);
208 NTSTATUS
_wbint_UnixIDs2Sids(struct pipes_struct
*p
,
209 struct wbint_UnixIDs2Sids
*r
)
211 struct id_map
**maps
;
215 maps
= id_map_ptrs_init(talloc_tos(), r
->in
.num_ids
);
217 return NT_STATUS_NO_MEMORY
;
220 for (i
=0; i
<r
->in
.num_ids
; i
++) {
221 maps
[i
]->status
= ID_UNKNOWN
;
222 maps
[i
]->xid
= r
->in
.xids
[i
];
225 status
= idmap_backend_unixids_to_sids(maps
, r
->in
.domain_name
);
226 if (!NT_STATUS_IS_OK(status
)) {
231 for (i
=0; i
<r
->in
.num_ids
; i
++) {
232 sid_copy(&r
->out
.sids
[i
], maps
[i
]->sid
);
240 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
245 status
= idmap_allocate_uid(&xid
);
246 if (!NT_STATUS_IS_OK(status
)) {
249 *r
->out
.uid
= xid
.id
;
253 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
258 status
= idmap_allocate_gid(&xid
);
259 if (!NT_STATUS_IS_OK(status
)) {
262 *r
->out
.gid
= xid
.id
;
266 NTSTATUS
_wbint_QueryUser(struct pipes_struct
*p
, struct wbint_QueryUser
*r
)
268 struct winbindd_domain
*domain
= wb_child_domain();
271 if (domain
== NULL
) {
272 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
275 status
= domain
->methods
->query_user(domain
, p
->mem_ctx
, r
->in
.sid
,
277 reset_cm_connection_on_error(domain
, status
);
281 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
282 struct wbint_LookupUserAliases
*r
)
284 struct winbindd_domain
*domain
= wb_child_domain();
287 if (domain
== NULL
) {
288 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
291 status
= domain
->methods
->lookup_useraliases(
292 domain
, p
->mem_ctx
, r
->in
.sids
->num_sids
, r
->in
.sids
->sids
,
293 &r
->out
.rids
->num_rids
, &r
->out
.rids
->rids
);
294 reset_cm_connection_on_error(domain
, status
);
298 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
299 struct wbint_LookupUserGroups
*r
)
301 struct winbindd_domain
*domain
= wb_child_domain();
304 if (domain
== NULL
) {
305 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
308 status
= domain
->methods
->lookup_usergroups(
309 domain
, p
->mem_ctx
, r
->in
.sid
,
310 &r
->out
.sids
->num_sids
, &r
->out
.sids
->sids
);
311 reset_cm_connection_on_error(domain
, status
);
315 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
316 struct wbint_QuerySequenceNumber
*r
)
318 struct winbindd_domain
*domain
= wb_child_domain();
321 if (domain
== NULL
) {
322 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
325 status
= domain
->methods
->sequence_number(domain
, r
->out
.sequence
);
326 reset_cm_connection_on_error(domain
, status
);
330 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
331 struct wbint_LookupGroupMembers
*r
)
333 struct winbindd_domain
*domain
= wb_child_domain();
334 uint32_t i
, num_names
;
335 struct dom_sid
*sid_mem
;
337 uint32_t *name_types
;
340 if (domain
== NULL
) {
341 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
344 status
= domain
->methods
->lookup_groupmem(
345 domain
, p
->mem_ctx
, r
->in
.sid
, r
->in
.type
,
346 &num_names
, &sid_mem
, &names
, &name_types
);
347 reset_cm_connection_on_error(domain
, status
);
348 if (!NT_STATUS_IS_OK(status
)) {
352 r
->out
.members
->num_principals
= num_names
;
353 r
->out
.members
->principals
= talloc_array(
354 r
->out
.members
, struct wbint_Principal
, num_names
);
355 if (r
->out
.members
->principals
== NULL
) {
356 return NT_STATUS_NO_MEMORY
;
359 for (i
=0; i
<num_names
; i
++) {
360 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
361 sid_copy(&m
->sid
, &sid_mem
[i
]);
362 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
363 m
->type
= (enum lsa_SidType
)name_types
[i
];
369 NTSTATUS
_wbint_QueryUserList(struct pipes_struct
*p
,
370 struct wbint_QueryUserList
*r
)
372 struct winbindd_domain
*domain
= wb_child_domain();
375 if (domain
== NULL
) {
376 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
379 status
= domain
->methods
->query_user_list(
380 domain
, p
->mem_ctx
, &r
->out
.users
->num_userinfos
,
381 &r
->out
.users
->userinfos
);
382 reset_cm_connection_on_error(domain
, status
);
386 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
387 struct wbint_QueryGroupList
*r
)
389 struct winbindd_domain
*domain
= wb_child_domain();
391 uint32_t num_local_groups
= 0;
392 struct wb_acct_info
*local_groups
= NULL
;
393 uint32_t num_dom_groups
= 0;
394 struct wb_acct_info
*dom_groups
= NULL
;
396 uint64_t num_total
= 0;
397 struct wbint_Principal
*result
;
399 bool include_local_groups
= false;
401 if (domain
== NULL
) {
402 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
405 switch (lp_server_role()) {
406 case ROLE_ACTIVE_DIRECTORY_DC
:
407 if (domain
->internal
) {
409 * we want to include local groups
410 * for BUILTIN and WORKGROUP
412 include_local_groups
= true;
417 * We might include local groups in more
418 * setups later, but that requires more work
424 if (include_local_groups
) {
425 status
= domain
->methods
->enum_local_groups(domain
, talloc_tos(),
428 reset_cm_connection_on_error(domain
, status
);
429 if (!NT_STATUS_IS_OK(status
)) {
434 status
= domain
->methods
->enum_dom_groups(domain
, talloc_tos(),
437 reset_cm_connection_on_error(domain
, status
);
438 if (!NT_STATUS_IS_OK(status
)) {
442 num_total
= num_local_groups
+ num_dom_groups
;
443 if (num_total
> UINT32_MAX
) {
444 return NT_STATUS_INTERNAL_ERROR
;
447 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
449 if (result
== NULL
) {
450 return NT_STATUS_NO_MEMORY
;
453 for (i
= 0; i
< num_local_groups
; i
++) {
454 struct wb_acct_info
*lg
= &local_groups
[i
];
455 struct wbint_Principal
*rg
= &result
[ti
++];
457 sid_compose(&rg
->sid
, &domain
->sid
, lg
->rid
);
458 rg
->type
= SID_NAME_ALIAS
;
459 rg
->name
= talloc_strdup(result
, lg
->acct_name
);
460 if (rg
->name
== NULL
) {
462 TALLOC_FREE(dom_groups
);
463 TALLOC_FREE(local_groups
);
464 return NT_STATUS_NO_MEMORY
;
467 num_local_groups
= 0;
468 TALLOC_FREE(local_groups
);
470 for (i
= 0; i
< num_dom_groups
; i
++) {
471 struct wb_acct_info
*dg
= &dom_groups
[i
];
472 struct wbint_Principal
*rg
= &result
[ti
++];
474 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
475 rg
->type
= SID_NAME_DOM_GRP
;
476 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
477 if (rg
->name
== NULL
) {
479 TALLOC_FREE(dom_groups
);
480 TALLOC_FREE(local_groups
);
481 return NT_STATUS_NO_MEMORY
;
485 TALLOC_FREE(dom_groups
);
487 r
->out
.groups
->num_principals
= ti
;
488 r
->out
.groups
->principals
= result
;
493 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
495 struct winbindd_domain
*domain
= wb_child_domain();
496 struct rpc_pipe_client
*netlogon_pipe
;
497 struct netr_DsRGetDCNameInfo
*dc_info
;
500 unsigned int orig_timeout
;
501 struct dcerpc_binding_handle
*b
;
503 if (domain
== NULL
) {
504 return dsgetdcname(p
->mem_ctx
, winbind_messaging_context(),
505 r
->in
.domain_name
, r
->in
.domain_guid
,
506 r
->in
.site_name
? r
->in
.site_name
: "",
511 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
513 reset_cm_connection_on_error(domain
, status
);
514 if (!NT_STATUS_IS_OK(status
)) {
515 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
519 b
= netlogon_pipe
->binding_handle
;
521 /* This call can take a long time - allow the server to time out.
522 35 seconds should do it. */
524 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
526 if (domain
->active_directory
) {
527 status
= dcerpc_netr_DsRGetDCName(b
,
528 p
->mem_ctx
, domain
->dcname
,
529 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
530 r
->in
.flags
, r
->out
.dc_info
, &werr
);
531 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
534 if (reset_cm_connection_on_error(domain
, status
)) {
536 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
538 reset_cm_connection_on_error(domain
, status
);
539 if (!NT_STATUS_IS_OK(status
)) {
540 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
544 b
= netlogon_pipe
->binding_handle
;
546 /* This call can take a long time - allow the server to time out.
547 35 seconds should do it. */
549 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
554 * Fallback to less capable methods
557 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
558 if (dc_info
== NULL
) {
559 status
= NT_STATUS_NO_MEMORY
;
563 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
564 status
= dcerpc_netr_GetDcName(b
,
565 p
->mem_ctx
, domain
->dcname
,
566 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
568 status
= dcerpc_netr_GetAnyDCName(b
,
569 p
->mem_ctx
, domain
->dcname
,
570 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
573 reset_cm_connection_on_error(domain
, status
);
574 if (!NT_STATUS_IS_OK(status
)) {
575 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
579 if (!W_ERROR_IS_OK(werr
)) {
580 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
582 status
= werror_to_ntstatus(werr
);
586 *r
->out
.dc_info
= dc_info
;
587 status
= NT_STATUS_OK
;
590 /* And restore our original timeout. */
591 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
596 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
598 struct winbindd_domain
*domain
= wb_child_domain();
601 enum lsa_SidType
*types
;
602 struct wbint_Principal
*result
;
606 if (domain
== NULL
) {
607 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
610 status
= domain
->methods
->rids_to_names(
611 domain
, talloc_tos(), r
->in
.domain_sid
, r
->in
.rids
->rids
,
612 r
->in
.rids
->num_rids
, &domain_name
, &names
, &types
);
613 reset_cm_connection_on_error(domain
, status
);
614 if (!NT_STATUS_IS_OK(status
)) {
618 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
620 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
621 r
->in
.rids
->num_rids
);
622 if (result
== NULL
) {
623 return NT_STATUS_NO_MEMORY
;
626 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
627 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
628 r
->in
.rids
->rids
[i
]);
629 result
[i
].type
= types
[i
];
630 result
[i
].name
= talloc_move(result
, &names
[i
]);
635 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
636 r
->out
.names
->principals
= result
;
640 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
641 struct wbint_CheckMachineAccount
*r
)
643 struct winbindd_domain
*domain
;
647 domain
= wb_child_domain();
648 if (domain
== NULL
) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
653 invalidate_cm_connection(domain
);
654 domain
->conn
.netlogon_force_reauth
= true;
657 struct rpc_pipe_client
*netlogon_pipe
;
658 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
661 /* There is a race condition between fetching the trust account
662 password and the periodic machine password change. So it's
663 possible that the trust account password has been changed on us.
664 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
666 #define MAX_RETRIES 3
668 if ((num_retries
< MAX_RETRIES
)
669 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
674 if (!NT_STATUS_IS_OK(status
)) {
675 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
679 /* Pass back result code - zero for success, other values for
680 specific failures. */
682 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
683 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
686 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
687 ("Checking the trust account password for domain %s returned %s\n",
688 domain
->name
, nt_errstr(status
)));
693 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
694 struct wbint_ChangeMachineAccount
*r
)
696 struct messaging_context
*msg_ctx
= winbind_messaging_context();
697 struct winbindd_domain
*domain
;
699 struct rpc_pipe_client
*netlogon_pipe
;
701 domain
= wb_child_domain();
702 if (domain
== NULL
) {
703 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
706 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
707 if (!NT_STATUS_IS_OK(status
)) {
708 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
712 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
714 netlogon_pipe
->binding_handle
,
718 /* Pass back result code - zero for success, other values for
719 specific failures. */
721 DEBUG(3,("domain %s secret %s\n", domain
->name
,
722 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
725 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
726 ("Changing the trust account password for domain %s returned %s\n",
727 domain
->name
, nt_errstr(status
)));
732 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
735 struct winbindd_domain
*domain
;
736 struct rpc_pipe_client
*netlogon_pipe
;
737 union netr_CONTROL_QUERY_INFORMATION info
;
739 fstring logon_server
;
740 struct dcerpc_binding_handle
*b
;
743 domain
= wb_child_domain();
744 if (domain
== NULL
) {
745 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
749 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
750 reset_cm_connection_on_error(domain
, status
);
751 if (!NT_STATUS_IS_OK(status
)) {
752 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
757 b
= netlogon_pipe
->binding_handle
;
759 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
760 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
761 if (*r
->out
.dcname
== NULL
) {
762 DEBUG(2, ("Could not allocate memory\n"));
763 return NT_STATUS_NO_MEMORY
;
767 * This provokes a WERR_NOT_SUPPORTED error message. This is
768 * documented in the wspp docs. I could not get a successful
769 * call to work, but the main point here is testing that the
770 * netlogon pipe works.
772 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
773 logon_server
, NETLOGON_CONTROL_QUERY
,
776 if (!dcerpc_binding_handle_is_connected(b
) && !retry
) {
777 DEBUG(10, ("Session might have expired. "
778 "Reconnect and retry once.\n"));
779 invalidate_cm_connection(domain
);
784 reset_cm_connection_on_error(domain
, status
);
785 if (!NT_STATUS_IS_OK(status
)) {
786 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
791 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
792 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
793 "WERR_NOT_SUPPORTED\n",
795 return werror_to_ntstatus(werr
);
798 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
802 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
803 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
805 struct winbindd_domain
*domain
;
807 struct rpc_pipe_client
*netlogon_pipe
;
809 domain
= wb_child_domain();
810 if (domain
== NULL
) {
811 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
814 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
815 if (!NT_STATUS_IS_OK(status
)) {
816 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
820 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain
->conn
.netlogon_creds
,
821 netlogon_pipe
->binding_handle
,
826 /* Pass back result code - zero for success, other values for
827 specific failures. */
829 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
830 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
833 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
834 ("Update of DNS records via RW DC %s returned %s\n",
835 domain
->name
, nt_errstr(status
)));
840 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
841 struct winbind_SamLogon
*r
)
843 struct winbindd_domain
*domain
;
845 DATA_BLOB lm_response
, nt_response
;
846 domain
= wb_child_domain();
847 if (domain
== NULL
) {
848 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
851 /* TODO: Handle interactive logons here */
852 if (r
->in
.validation_level
!= 3 ||
853 r
->in
.logon
.network
== NULL
||
854 (r
->in
.logon_level
!= NetlogonNetworkInformation
855 && r
->in
.logon_level
!= NetlogonNetworkTransitiveInformation
)) {
856 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
860 lm_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->lm
.data
, r
->in
.logon
.network
->lm
.length
);
861 nt_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->nt
.data
, r
->in
.logon
.network
->nt
.length
);
863 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
864 r
->in
.logon
.network
->identity_info
.parameter_control
,
865 r
->in
.logon
.network
->identity_info
.account_name
.string
,
866 r
->in
.logon
.network
->identity_info
.domain_name
.string
,
867 r
->in
.logon
.network
->identity_info
.workstation
.string
,
868 r
->in
.logon
.network
->challenge
,
869 lm_response
, nt_response
, &r
->out
.validation
.sam3
);
873 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
874 struct winbindd_domain
*domain
,
875 struct winbind_LogonControl
*r
)
878 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
879 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
880 WERROR check_result
= WERR_INTERNAL_ERROR
;
882 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
887 if (domain
->internal
) {
888 check_result
= WERR_OK
;
893 * For now we just force a reconnect
895 * TODO: take care of the optional '\dcname'
897 invalidate_cm_connection(domain
);
898 domain
->conn
.netlogon_force_reauth
= true;
899 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
900 reset_cm_connection_on_error(domain
, status
);
901 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
902 status
= NT_STATUS_NO_LOGON_SERVERS
;
904 if (!NT_STATUS_IS_OK(status
)) {
905 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
906 __func__
, domain
->name
, domain
->alt_name
,
909 * Here we return a top level error!
910 * This is different than TC_QUERY or TC_VERIFY.
912 return ntstatus_to_werror(status
);
914 check_result
= WERR_OK
;
917 info2
->pdc_connection_status
= WERR_OK
;
918 if (domain
->dcname
!= NULL
) {
919 info2
->flags
|= NETLOGON_HAS_IP
;
920 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
921 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
923 if (info2
->trusted_dc_name
== NULL
) {
927 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
928 if (info2
->trusted_dc_name
== NULL
) {
932 info2
->tc_connection_status
= check_result
;
934 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
935 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
936 "pdc_connection[%s] tc_connection[%s]\n",
937 __func__
, domain
->name
, domain
->alt_name
,
939 win_errstr(info2
->pdc_connection_status
),
940 win_errstr(info2
->tc_connection_status
)));
943 r
->out
.query
->info2
= info2
;
945 DEBUG(5, ("%s: succeeded.\n", __func__
));
949 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
950 struct winbindd_domain
*domain
,
951 struct winbind_LogonControl
*r
)
954 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
955 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
956 WERROR check_result
= WERR_INTERNAL_ERROR
;
958 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
963 if (domain
->internal
) {
964 check_result
= WERR_OK
;
968 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
969 reset_cm_connection_on_error(domain
, status
);
970 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
971 status
= NT_STATUS_NO_LOGON_SERVERS
;
973 if (!NT_STATUS_IS_OK(status
)) {
974 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
976 check_result
= ntstatus_to_werror(status
);
979 check_result
= WERR_OK
;
982 info2
->pdc_connection_status
= WERR_OK
;
983 if (domain
->dcname
!= NULL
) {
984 info2
->flags
|= NETLOGON_HAS_IP
;
985 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
986 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
988 if (info2
->trusted_dc_name
== NULL
) {
992 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
993 if (info2
->trusted_dc_name
== NULL
) {
997 info2
->tc_connection_status
= check_result
;
999 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1000 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1001 "pdc_connection[%s] tc_connection[%s]\n",
1002 __func__
, domain
->name
, domain
->alt_name
,
1004 win_errstr(info2
->pdc_connection_status
),
1005 win_errstr(info2
->tc_connection_status
)));
1008 r
->out
.query
->info2
= info2
;
1010 DEBUG(5, ("%s: succeeded.\n", __func__
));
1014 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1015 struct winbindd_domain
*domain
,
1016 struct winbind_LogonControl
*r
)
1018 TALLOC_CTX
*frame
= talloc_stackframe();
1021 struct lsa_String trusted_domain_name
= {};
1022 struct lsa_StringLarge trusted_domain_name_l
= {};
1023 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1024 struct policy_handle local_lsa_policy
= {};
1025 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1026 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1027 struct cli_credentials
*creds
= NULL
;
1028 struct samr_Password
*cur_nt_hash
= NULL
;
1029 uint32_t trust_attributes
= 0;
1030 struct samr_Password new_owf_password
= {};
1032 struct samr_Password old_owf_password
= {};
1034 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1035 bool fetch_fti
= false;
1036 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1037 struct netr_TrustInfo
*trust_info
= NULL
;
1038 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1039 struct dcerpc_binding_handle
*b
= NULL
;
1040 WERROR check_result
= WERR_INTERNAL_ERROR
;
1041 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1044 trusted_domain_name
.string
= domain
->name
;
1045 trusted_domain_name_l
.string
= domain
->name
;
1047 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1048 if (info2
== NULL
) {
1053 if (domain
->internal
) {
1054 check_result
= WERR_OK
;
1058 status
= pdb_get_trust_credentials(domain
->name
,
1062 if (NT_STATUS_IS_OK(status
)) {
1063 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1067 if (!domain
->primary
) {
1068 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1070 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1072 if (!NT_STATUS_IS_OK(status
)) {
1073 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1074 __location__
, __func__
, nt_errstr(status
)));
1076 return WERR_INTERNAL_ERROR
;
1078 local_lsa
= local_lsa_pipe
->binding_handle
;
1080 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1082 &trusted_domain_name
,
1083 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1085 if (!NT_STATUS_IS_OK(status
)) {
1086 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1087 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1089 return WERR_INTERNAL_ERROR
;
1091 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1092 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1093 __location__
, __func__
, domain
->name
));
1095 return WERR_NO_SUCH_DOMAIN
;
1097 if (!NT_STATUS_IS_OK(result
)) {
1098 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1099 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1101 return WERR_INTERNAL_ERROR
;
1104 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1105 "returned no trusted domain information\n",
1106 __location__
, __func__
));
1108 return WERR_INTERNAL_ERROR
;
1111 local_tdo
= &tdi
->info_ex
;
1112 trust_attributes
= local_tdo
->trust_attributes
;
1115 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1116 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1118 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1120 &trusted_domain_name
,
1121 LSA_FOREST_TRUST_DOMAIN_INFO
,
1123 if (!NT_STATUS_IS_OK(status
)) {
1124 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1125 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1127 return WERR_INTERNAL_ERROR
;
1129 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1130 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1131 __func__
, domain
->name
));
1134 result
= NT_STATUS_OK
;
1136 if (!NT_STATUS_IS_OK(result
)) {
1137 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1138 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1140 return WERR_INTERNAL_ERROR
;
1143 TALLOC_FREE(old_fti
);
1147 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1148 reset_cm_connection_on_error(domain
, status
);
1149 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1150 status
= NT_STATUS_NO_LOGON_SERVERS
;
1152 if (!NT_STATUS_IS_OK(status
)) {
1153 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1154 nt_errstr(status
)));
1155 check_result
= ntstatus_to_werror(status
);
1158 check_result
= WERR_OK
;
1159 b
= netlogon_pipe
->binding_handle
;
1161 if (cur_nt_hash
== NULL
) {
1162 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1167 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1170 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1171 status
= NT_STATUS_NOT_SUPPORTED
;
1173 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1175 status
= NT_STATUS_OK
;
1177 if (!NT_STATUS_IS_OK(status
)) {
1178 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1179 invalidate_cm_connection(domain
);
1183 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1185 domain
->name
, nt_errstr(status
)));
1186 check_result
= ntstatus_to_werror(status
);
1191 if (new_fti
!= NULL
) {
1192 struct lsa_ForestTrustInformation old_fti
= {};
1193 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1194 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1196 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1199 if (!NT_STATUS_IS_OK(status
)) {
1200 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1201 __location__
, __func__
,
1202 domain
->name
, nt_errstr(status
)));
1204 return ntstatus_to_werror(status
);
1207 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1209 &trusted_domain_name_l
,
1210 LSA_FOREST_TRUST_DOMAIN_INFO
,
1212 0, /* check_only=0 => store it! */
1215 if (!NT_STATUS_IS_OK(status
)) {
1216 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1217 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1219 return WERR_INTERNAL_ERROR
;
1221 if (!NT_STATUS_IS_OK(result
)) {
1222 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1223 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1225 return ntstatus_to_werror(result
);
1229 status
= netlogon_creds_cli_ServerGetTrustInfo(domain
->conn
.netlogon_creds
,
1234 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1235 status
= NT_STATUS_NOT_SUPPORTED
;
1237 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1238 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1239 nt_errstr(status
)));
1240 verify_result
= WERR_OK
;
1243 if (!NT_STATUS_IS_OK(status
)) {
1244 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1245 invalidate_cm_connection(domain
);
1249 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1250 nt_errstr(status
)));
1252 if (!dcerpc_binding_handle_is_connected(b
)) {
1253 check_result
= ntstatus_to_werror(status
);
1256 verify_result
= ntstatus_to_werror(status
);
1261 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1262 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1264 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1265 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1270 cmp_new
= memcmp(new_owf_password
.hash
,
1272 sizeof(cur_nt_hash
->hash
));
1273 cmp_old
= memcmp(old_owf_password
.hash
,
1275 sizeof(cur_nt_hash
->hash
));
1276 if (cmp_new
!= 0 && cmp_old
!= 0) {
1277 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1278 "any password known to dcname[%s]\n",
1279 __func__
, domain
->name
, domain
->alt_name
,
1281 verify_result
= WERR_WRONG_PASSWORD
;
1286 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1287 "against the old password known to dcname[%s]\n",
1288 __func__
, domain
->name
, domain
->alt_name
,
1292 verify_result
= WERR_OK
;
1296 verify_result
= check_result
;
1298 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1299 info2
->pdc_connection_status
= verify_result
;
1300 if (domain
->dcname
!= NULL
) {
1301 info2
->flags
|= NETLOGON_HAS_IP
;
1302 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1303 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1305 if (info2
->trusted_dc_name
== NULL
) {
1310 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1311 if (info2
->trusted_dc_name
== NULL
) {
1316 info2
->tc_connection_status
= check_result
;
1318 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1319 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1320 "pdc_connection[%s] tc_connection[%s]\n",
1321 __func__
, domain
->name
, domain
->alt_name
,
1323 win_errstr(info2
->pdc_connection_status
),
1324 win_errstr(info2
->tc_connection_status
)));
1327 r
->out
.query
->info2
= info2
;
1329 DEBUG(5, ("%s: succeeded.\n", __func__
));
1334 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1335 struct winbindd_domain
*domain
,
1336 struct winbind_LogonControl
*r
)
1338 struct messaging_context
*msg_ctx
= winbind_messaging_context();
1340 struct rpc_pipe_client
*netlogon_pipe
;
1341 struct cli_credentials
*creds
= NULL
;
1342 struct samr_Password
*cur_nt_hash
= NULL
;
1343 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1344 struct dcerpc_binding_handle
*b
;
1345 WERROR change_result
= WERR_OK
;
1348 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1349 if (info1
== NULL
) {
1353 if (domain
->internal
) {
1354 return WERR_NOT_SUPPORTED
;
1357 status
= pdb_get_trust_credentials(domain
->name
,
1361 if (NT_STATUS_IS_OK(status
)) {
1362 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1367 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1368 reset_cm_connection_on_error(domain
, status
);
1369 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1370 status
= NT_STATUS_NO_LOGON_SERVERS
;
1372 if (!NT_STATUS_IS_OK(status
)) {
1373 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1374 __func__
, domain
->name
, domain
->alt_name
,
1375 nt_errstr(status
)));
1377 * Here we return a top level error!
1378 * This is different than TC_QUERY or TC_VERIFY.
1380 return ntstatus_to_werror(status
);
1382 b
= netlogon_pipe
->binding_handle
;
1384 if (cur_nt_hash
== NULL
) {
1385 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1388 TALLOC_FREE(cur_nt_hash
);
1390 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
1391 msg_ctx
, b
, domain
->name
,
1393 if (!NT_STATUS_IS_OK(status
)) {
1394 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1395 invalidate_cm_connection(domain
);
1400 DEBUG(1, ("trust_pw_change(%s): %s\n",
1401 domain
->name
, nt_errstr(status
)));
1403 change_result
= ntstatus_to_werror(status
);
1407 change_result
= WERR_OK
;
1410 info1
->pdc_connection_status
= change_result
;
1412 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1413 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1414 "pdc_connection[%s]\n",
1415 __func__
, domain
->name
, domain
->alt_name
,
1417 win_errstr(info1
->pdc_connection_status
)));
1420 r
->out
.query
->info1
= info1
;
1422 DEBUG(5, ("%s: succeeded.\n", __func__
));
1426 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1427 struct winbind_LogonControl
*r
)
1429 struct winbindd_domain
*domain
;
1431 domain
= wb_child_domain();
1432 if (domain
== NULL
) {
1433 return WERR_NO_SUCH_DOMAIN
;
1436 switch (r
->in
.function_code
) {
1437 case NETLOGON_CONTROL_REDISCOVER
:
1438 if (r
->in
.level
!= 2) {
1439 return WERR_INVALID_PARAMETER
;
1441 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1442 case NETLOGON_CONTROL_TC_QUERY
:
1443 if (r
->in
.level
!= 2) {
1444 return WERR_INVALID_PARAMETER
;
1446 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1447 case NETLOGON_CONTROL_TC_VERIFY
:
1448 if (r
->in
.level
!= 2) {
1449 return WERR_INVALID_PARAMETER
;
1451 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1452 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1453 if (r
->in
.level
!= 1) {
1454 return WERR_INVALID_PARAMETER
;
1456 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1461 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1462 __func__
, r
->in
.function_code
));
1463 return WERR_NOT_SUPPORTED
;
1466 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1467 struct winbind_GetForestTrustInformation
*r
)
1469 TALLOC_CTX
*frame
= talloc_stackframe();
1470 NTSTATUS status
, result
;
1471 struct winbindd_domain
*domain
;
1472 struct rpc_pipe_client
*netlogon_pipe
;
1473 struct dcerpc_binding_handle
*b
;
1475 struct lsa_String trusted_domain_name
= {};
1476 struct lsa_StringLarge trusted_domain_name_l
= {};
1477 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1478 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1479 struct lsa_ForestTrustInformation _old_fti
= {};
1480 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1481 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1482 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1483 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1484 bool update_fti
= false;
1485 struct rpc_pipe_client
*local_lsa_pipe
;
1486 struct policy_handle local_lsa_policy
;
1487 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1489 domain
= wb_child_domain();
1490 if (domain
== NULL
) {
1492 return WERR_NO_SUCH_DOMAIN
;
1496 * checking for domain->internal and domain->primary
1497 * makes sure we only do some work when running as DC.
1500 if (domain
->internal
) {
1502 return WERR_NO_SUCH_DOMAIN
;
1505 if (domain
->primary
) {
1507 return WERR_NO_SUCH_DOMAIN
;
1510 trusted_domain_name
.string
= domain
->name
;
1511 trusted_domain_name_l
.string
= domain
->name
;
1513 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1515 if (!NT_STATUS_IS_OK(status
)) {
1516 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1517 __location__
, __func__
, nt_errstr(status
)));
1519 return WERR_INTERNAL_ERROR
;
1521 local_lsa
= local_lsa_pipe
->binding_handle
;
1523 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1525 &trusted_domain_name
,
1526 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1528 if (!NT_STATUS_IS_OK(status
)) {
1529 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1530 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1532 return WERR_INTERNAL_ERROR
;
1534 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1535 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1536 __location__
, __func__
, domain
->name
));
1538 return WERR_NO_SUCH_DOMAIN
;
1540 if (!NT_STATUS_IS_OK(result
)) {
1541 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1542 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1544 return WERR_INTERNAL_ERROR
;
1547 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1548 "returned no trusted domain information\n",
1549 __location__
, __func__
));
1551 return WERR_INTERNAL_ERROR
;
1554 tdo
= &tdi
->info_ex
;
1556 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1557 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1558 __func__
, tdo
->netbios_name
.string
,
1559 tdo
->domain_name
.string
,
1560 (unsigned)tdo
->trust_attributes
));
1562 return WERR_NO_SUCH_DOMAIN
;
1565 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1567 return WERR_INVALID_FLAGS
;
1571 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1572 reset_cm_connection_on_error(domain
, status
);
1573 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1574 status
= NT_STATUS_NO_LOGON_SERVERS
;
1576 if (!NT_STATUS_IS_OK(status
)) {
1577 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1578 nt_errstr(status
)));
1580 return ntstatus_to_werror(status
);
1582 b
= netlogon_pipe
->binding_handle
;
1584 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1587 if (!NT_STATUS_IS_OK(status
)) {
1588 if (!retry
&& dcerpc_binding_handle_is_connected(b
)) {
1589 invalidate_cm_connection(domain
);
1593 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1594 domain
->name
, nt_errstr(status
)));
1596 return ntstatus_to_werror(status
);
1599 *r
->out
.forest_trust_info
= new_fti
;
1601 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1605 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1607 &trusted_domain_name
,
1608 LSA_FOREST_TRUST_DOMAIN_INFO
,
1610 if (!NT_STATUS_IS_OK(status
)) {
1611 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1612 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1614 return WERR_INTERNAL_ERROR
;
1616 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1617 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1618 __func__
, domain
->name
));
1620 old_fti
= &_old_fti
;
1621 result
= NT_STATUS_OK
;
1623 if (!NT_STATUS_IS_OK(result
)) {
1624 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1625 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1627 return WERR_INTERNAL_ERROR
;
1630 if (old_fti
== NULL
) {
1631 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1632 "returned success without returning forest trust information\n",
1633 __location__
, __func__
));
1635 return WERR_INTERNAL_ERROR
;
1642 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1644 if (!NT_STATUS_IS_OK(status
)) {
1645 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1646 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1648 return ntstatus_to_werror(status
);
1651 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1653 &trusted_domain_name_l
,
1654 LSA_FOREST_TRUST_DOMAIN_INFO
,
1656 0, /* check_only=0 => store it! */
1659 if (!NT_STATUS_IS_OK(status
)) {
1660 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1661 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1663 return WERR_INTERNAL_ERROR
;
1665 if (!NT_STATUS_IS_OK(result
)) {
1666 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1667 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1669 return ntstatus_to_werror(result
);
1673 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));