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 bool reset_cm_connection_on_error(struct winbindd_domain
*domain
,
43 struct dcerpc_binding_handle
*b
,
46 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) ||
47 NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
) ||
48 NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
)) {
49 invalidate_cm_connection(domain
);
50 domain
->conn
.netlogon_force_reauth
= true;
54 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
55 NT_STATUS_EQUAL(status
, NT_STATUS_IO_DEVICE_ERROR
))
57 invalidate_cm_connection(domain
);
58 /* We invalidated the connection. */
62 if (b
!= NULL
&& !dcerpc_binding_handle_is_connected(b
)) {
63 invalidate_cm_connection(domain
);
70 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
72 struct winbindd_domain
*domain
= wb_child_domain();
75 enum lsa_SidType type
;
79 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
82 status
= wb_cache_sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
83 &dom_name
, &name
, &type
);
84 reset_cm_connection_on_error(domain
, NULL
, status
);
85 if (!NT_STATUS_IS_OK(status
)) {
89 *r
->out
.domain
= dom_name
;
95 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
97 struct winbindd_domain
*domain
= wb_child_domain();
98 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
102 if (domain
== NULL
) {
103 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
107 * This breaks the winbindd_domain->methods abstraction: This
108 * is only called for remote domains, and both winbindd_msrpc
109 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
110 * done at the wbint RPC layer.
113 status
= rpc_lookup_sids(p
->mem_ctx
, domain
, r
->in
.sids
,
114 &domains
, &r
->out
.names
);
116 if (domains
!= NULL
) {
117 r
->out
.domains
= domains
;
120 if (!retry
&& reset_cm_connection_on_error(domain
, NULL
, status
)) {
128 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
130 struct winbindd_domain
*domain
= wb_child_domain();
133 if (domain
== NULL
) {
134 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
137 status
= wb_cache_name_to_sid(domain
, p
->mem_ctx
, r
->in
.domain
,
138 r
->in
.name
, r
->in
.flags
,
139 r
->out
.sid
, r
->out
.type
);
140 reset_cm_connection_on_error(domain
, NULL
, status
);
144 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
145 struct wbint_Sids2UnixIDs
*r
)
149 struct lsa_DomainInfo
*d
;
150 struct wbint_TransID
*ids
;
153 struct id_map
**id_map_ptrs
= NULL
;
154 struct idmap_domain
*dom
;
155 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
157 if (r
->in
.domains
->count
!= 1) {
158 return NT_STATUS_INVALID_PARAMETER
;
161 d
= &r
->in
.domains
->domains
[0];
162 ids
= r
->in
.ids
->ids
;
163 num_ids
= r
->in
.ids
->num_ids
;
165 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
167 DEBUG(10, ("idmap domain %s:%s not found\n",
168 d
->name
.string
, sid_string_dbg(d
->sid
)));
170 for (i
=0; i
<num_ids
; i
++) {
172 ids
[i
].xid
= (struct unixid
) {
174 .type
= ID_TYPE_NOT_SPECIFIED
181 id_map_ptrs
= id_map_ptrs_init(talloc_tos(), num_ids
);
182 if (id_map_ptrs
== NULL
) {
187 * Convert the input data into a list of id_map structs
188 * suitable for handing in to the idmap sids_to_unixids
192 for (i
=0; i
<num_ids
; i
++) {
193 struct id_map
*m
= id_map_ptrs
[i
];
195 sid_compose(m
->sid
, d
->sid
, ids
[i
].rid
);
196 m
->status
= ID_UNKNOWN
;
197 m
->xid
= (struct unixid
) { .type
= ids
[i
].type
};
200 status
= dom
->methods
->sids_to_unixids(dom
, id_map_ptrs
);
202 if (!NT_STATUS_IS_OK(status
)) {
203 DEBUG(10, ("sids_to_unixids returned %s\n",
209 * Extract the results for handing them back to the caller.
212 for (i
=0; i
<num_ids
; i
++) {
213 struct id_map
*m
= id_map_ptrs
[i
];
215 if (!idmap_unix_id_is_in_range(m
->xid
.id
, dom
)) {
216 DBG_DEBUG("id %"PRIu32
" is out of range "
217 "%"PRIu32
"-%"PRIu32
" for domain %s\n",
218 m
->xid
.id
, dom
->low_id
, dom
->high_id
,
220 m
->status
= ID_UNMAPPED
;
223 if (m
->status
== ID_MAPPED
) {
226 ids
[i
].xid
.id
= UINT32_MAX
;
227 ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
233 status
= NT_STATUS_NO_MEMORY
;
235 TALLOC_FREE(id_map_ptrs
);
239 NTSTATUS
_wbint_UnixIDs2Sids(struct pipes_struct
*p
,
240 struct wbint_UnixIDs2Sids
*r
)
242 struct id_map
**maps
;
246 maps
= id_map_ptrs_init(talloc_tos(), r
->in
.num_ids
);
248 return NT_STATUS_NO_MEMORY
;
251 for (i
=0; i
<r
->in
.num_ids
; i
++) {
252 maps
[i
]->status
= ID_UNKNOWN
;
253 maps
[i
]->xid
= r
->in
.xids
[i
];
256 status
= idmap_backend_unixids_to_sids(maps
, r
->in
.domain_name
,
258 if (!NT_STATUS_IS_OK(status
)) {
263 for (i
=0; i
<r
->in
.num_ids
; i
++) {
264 r
->out
.xids
[i
] = maps
[i
]->xid
;
265 sid_copy(&r
->out
.sids
[i
], maps
[i
]->sid
);
273 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
278 status
= idmap_allocate_uid(&xid
);
279 if (!NT_STATUS_IS_OK(status
)) {
282 *r
->out
.uid
= xid
.id
;
286 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
291 status
= idmap_allocate_gid(&xid
);
292 if (!NT_STATUS_IS_OK(status
)) {
295 *r
->out
.gid
= xid
.id
;
299 NTSTATUS
_wbint_GetNssInfo(struct pipes_struct
*p
, struct wbint_GetNssInfo
*r
)
301 struct idmap_domain
*domain
;
304 domain
= idmap_find_domain(r
->in
.info
->domain_name
);
305 if ((domain
== NULL
) || (domain
->query_user
== NULL
)) {
306 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
309 status
= domain
->query_user(domain
, r
->in
.info
);
313 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
314 struct wbint_LookupUserAliases
*r
)
316 struct winbindd_domain
*domain
= wb_child_domain();
319 if (domain
== NULL
) {
320 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
323 status
= wb_cache_lookup_useraliases(domain
, p
->mem_ctx
,
324 r
->in
.sids
->num_sids
,
326 &r
->out
.rids
->num_rids
,
328 reset_cm_connection_on_error(domain
, NULL
, status
);
332 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
333 struct wbint_LookupUserGroups
*r
)
335 struct winbindd_domain
*domain
= wb_child_domain();
338 if (domain
== NULL
) {
339 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
342 status
= wb_cache_lookup_usergroups(domain
, p
->mem_ctx
, r
->in
.sid
,
343 &r
->out
.sids
->num_sids
,
345 reset_cm_connection_on_error(domain
, NULL
, status
);
349 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
350 struct wbint_QuerySequenceNumber
*r
)
352 struct winbindd_domain
*domain
= wb_child_domain();
355 if (domain
== NULL
) {
356 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
359 status
= wb_cache_sequence_number(domain
, r
->out
.sequence
);
360 reset_cm_connection_on_error(domain
, NULL
, status
);
364 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
365 struct wbint_LookupGroupMembers
*r
)
367 struct winbindd_domain
*domain
= wb_child_domain();
368 uint32_t i
, num_names
;
369 struct dom_sid
*sid_mem
;
371 uint32_t *name_types
;
374 if (domain
== NULL
) {
375 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
378 status
= wb_cache_lookup_groupmem(domain
, p
->mem_ctx
, r
->in
.sid
,
379 r
->in
.type
, &num_names
, &sid_mem
,
380 &names
, &name_types
);
381 reset_cm_connection_on_error(domain
, NULL
, status
);
382 if (!NT_STATUS_IS_OK(status
)) {
386 r
->out
.members
->num_principals
= num_names
;
387 r
->out
.members
->principals
= talloc_array(
388 r
->out
.members
, struct wbint_Principal
, num_names
);
389 if (r
->out
.members
->principals
== NULL
) {
390 return NT_STATUS_NO_MEMORY
;
393 for (i
=0; i
<num_names
; i
++) {
394 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
395 sid_copy(&m
->sid
, &sid_mem
[i
]);
396 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
397 m
->type
= (enum lsa_SidType
)name_types
[i
];
403 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
404 struct wbint_QueryGroupList
*r
)
406 struct winbindd_domain
*domain
= wb_child_domain();
408 uint32_t num_local_groups
= 0;
409 struct wb_acct_info
*local_groups
= NULL
;
410 uint32_t num_dom_groups
= 0;
411 struct wb_acct_info
*dom_groups
= NULL
;
413 uint64_t num_total
= 0;
414 struct wbint_Principal
*result
;
416 bool include_local_groups
= false;
418 if (domain
== NULL
) {
419 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
422 switch (lp_server_role()) {
423 case ROLE_ACTIVE_DIRECTORY_DC
:
424 if (domain
->internal
) {
426 * we want to include local groups
427 * for BUILTIN and WORKGROUP
429 include_local_groups
= true;
434 * We might include local groups in more
435 * setups later, but that requires more work
441 if (include_local_groups
) {
442 status
= wb_cache_enum_local_groups(domain
, talloc_tos(),
445 reset_cm_connection_on_error(domain
, NULL
, status
);
446 if (!NT_STATUS_IS_OK(status
)) {
451 status
= wb_cache_enum_dom_groups(domain
, talloc_tos(),
454 reset_cm_connection_on_error(domain
, NULL
, status
);
455 if (!NT_STATUS_IS_OK(status
)) {
459 num_total
= num_local_groups
+ num_dom_groups
;
460 if (num_total
> UINT32_MAX
) {
461 return NT_STATUS_INTERNAL_ERROR
;
464 result
= talloc_array(r
->out
.groups
, struct wbint_Principal
,
466 if (result
== NULL
) {
467 return NT_STATUS_NO_MEMORY
;
470 for (i
= 0; i
< num_local_groups
; i
++) {
471 struct wb_acct_info
*lg
= &local_groups
[i
];
472 struct wbint_Principal
*rg
= &result
[ti
++];
474 sid_compose(&rg
->sid
, &domain
->sid
, lg
->rid
);
475 rg
->type
= SID_NAME_ALIAS
;
476 rg
->name
= talloc_strdup(result
, lg
->acct_name
);
477 if (rg
->name
== NULL
) {
479 TALLOC_FREE(dom_groups
);
480 TALLOC_FREE(local_groups
);
481 return NT_STATUS_NO_MEMORY
;
484 num_local_groups
= 0;
485 TALLOC_FREE(local_groups
);
487 for (i
= 0; i
< num_dom_groups
; i
++) {
488 struct wb_acct_info
*dg
= &dom_groups
[i
];
489 struct wbint_Principal
*rg
= &result
[ti
++];
491 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
492 rg
->type
= SID_NAME_DOM_GRP
;
493 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
494 if (rg
->name
== NULL
) {
496 TALLOC_FREE(dom_groups
);
497 TALLOC_FREE(local_groups
);
498 return NT_STATUS_NO_MEMORY
;
502 TALLOC_FREE(dom_groups
);
504 r
->out
.groups
->num_principals
= ti
;
505 r
->out
.groups
->principals
= result
;
510 NTSTATUS
_wbint_QueryUserRidList(struct pipes_struct
*p
,
511 struct wbint_QueryUserRidList
*r
)
513 struct winbindd_domain
*domain
= wb_child_domain();
516 if (domain
== NULL
) {
517 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
521 * Right now this is overkill. We should add a backend call
522 * just querying the rids.
525 status
= wb_cache_query_user_list(domain
, p
->mem_ctx
,
527 reset_cm_connection_on_error(domain
, NULL
, status
);
529 if (!NT_STATUS_IS_OK(status
)) {
533 r
->out
.rids
->num_rids
= talloc_array_length(r
->out
.rids
->rids
);
538 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
540 struct winbindd_domain
*domain
= wb_child_domain();
541 struct rpc_pipe_client
*netlogon_pipe
;
542 struct netr_DsRGetDCNameInfo
*dc_info
;
545 unsigned int orig_timeout
;
546 struct dcerpc_binding_handle
*b
;
548 bool try_dsrgetdcname
= false;
550 if (domain
== NULL
) {
551 return dsgetdcname(p
->mem_ctx
, server_messaging_context(),
552 r
->in
.domain_name
, r
->in
.domain_guid
,
553 r
->in
.site_name
? r
->in
.site_name
: "",
558 if (domain
->active_directory
) {
559 try_dsrgetdcname
= true;
563 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
565 reset_cm_connection_on_error(domain
, NULL
, status
);
566 if (!NT_STATUS_IS_OK(status
)) {
567 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
571 b
= netlogon_pipe
->binding_handle
;
573 /* This call can take a long time - allow the server to time out.
574 35 seconds should do it. */
576 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
578 if (try_dsrgetdcname
) {
579 status
= dcerpc_netr_DsRGetDCName(b
,
580 p
->mem_ctx
, domain
->dcname
,
581 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
582 r
->in
.flags
, r
->out
.dc_info
, &werr
);
583 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
587 reset_cm_connection_on_error(domain
, NULL
, status
))
592 try_dsrgetdcname
= false;
597 * Fallback to less capable methods
600 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
601 if (dc_info
== NULL
) {
602 status
= NT_STATUS_NO_MEMORY
;
606 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
607 status
= dcerpc_netr_GetDcName(b
,
608 p
->mem_ctx
, domain
->dcname
,
609 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
611 status
= dcerpc_netr_GetAnyDCName(b
,
612 p
->mem_ctx
, domain
->dcname
,
613 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
616 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
620 if (!NT_STATUS_IS_OK(status
)) {
621 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
625 if (!W_ERROR_IS_OK(werr
)) {
626 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
628 status
= werror_to_ntstatus(werr
);
632 *r
->out
.dc_info
= dc_info
;
633 status
= NT_STATUS_OK
;
636 /* And restore our original timeout. */
637 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
642 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
644 struct winbindd_domain
*domain
= wb_child_domain();
647 enum lsa_SidType
*types
;
648 struct wbint_Principal
*result
;
652 if (domain
== NULL
) {
653 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
656 status
= wb_cache_rids_to_names(domain
, talloc_tos(), r
->in
.domain_sid
,
657 r
->in
.rids
->rids
, r
->in
.rids
->num_rids
,
658 &domain_name
, &names
, &types
);
659 reset_cm_connection_on_error(domain
, NULL
, status
);
660 if (!NT_STATUS_IS_OK(status
)) {
664 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
666 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
667 r
->in
.rids
->num_rids
);
668 if (result
== NULL
) {
669 return NT_STATUS_NO_MEMORY
;
672 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
673 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
674 r
->in
.rids
->rids
[i
]);
675 result
[i
].type
= types
[i
];
676 result
[i
].name
= talloc_move(result
, &names
[i
]);
681 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
682 r
->out
.names
->principals
= result
;
686 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
687 struct wbint_CheckMachineAccount
*r
)
689 struct winbindd_domain
*domain
;
693 domain
= wb_child_domain();
694 if (domain
== NULL
) {
695 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
699 invalidate_cm_connection(domain
);
700 domain
->conn
.netlogon_force_reauth
= true;
703 struct rpc_pipe_client
*netlogon_pipe
;
704 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
707 /* There is a race condition between fetching the trust account
708 password and the periodic machine password change. So it's
709 possible that the trust account password has been changed on us.
710 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
712 #define MAX_RETRIES 3
714 if ((num_retries
< MAX_RETRIES
)
715 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
720 if (!NT_STATUS_IS_OK(status
)) {
721 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
725 /* Pass back result code - zero for success, other values for
726 specific failures. */
728 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
729 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
732 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
733 ("Checking the trust account password for domain %s returned %s\n",
734 domain
->name
, nt_errstr(status
)));
739 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
740 struct wbint_ChangeMachineAccount
*r
)
742 struct messaging_context
*msg_ctx
= server_messaging_context();
743 struct winbindd_domain
*domain
;
745 struct rpc_pipe_client
*netlogon_pipe
;
747 domain
= wb_child_domain();
748 if (domain
== NULL
) {
749 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
752 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
753 if (!NT_STATUS_IS_OK(status
)) {
754 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
758 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
760 netlogon_pipe
->binding_handle
,
765 /* Pass back result code - zero for success, other values for
766 specific failures. */
768 DEBUG(3,("domain %s secret %s\n", domain
->name
,
769 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
772 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
773 ("Changing the trust account password for domain %s returned %s\n",
774 domain
->name
, nt_errstr(status
)));
779 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
782 struct winbindd_domain
*domain
;
783 struct rpc_pipe_client
*netlogon_pipe
;
784 union netr_CONTROL_QUERY_INFORMATION info
;
786 fstring logon_server
;
787 struct dcerpc_binding_handle
*b
;
790 domain
= wb_child_domain();
791 if (domain
== NULL
) {
792 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
796 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
797 reset_cm_connection_on_error(domain
, NULL
, status
);
798 if (!NT_STATUS_IS_OK(status
)) {
799 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
804 b
= netlogon_pipe
->binding_handle
;
806 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
807 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
808 if (*r
->out
.dcname
== NULL
) {
809 DEBUG(2, ("Could not allocate memory\n"));
810 return NT_STATUS_NO_MEMORY
;
814 * This provokes a WERR_NOT_SUPPORTED error message. This is
815 * documented in the wspp docs. I could not get a successful
816 * call to work, but the main point here is testing that the
817 * netlogon pipe works.
819 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
820 logon_server
, NETLOGON_CONTROL_QUERY
,
823 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
828 if (!NT_STATUS_IS_OK(status
)) {
829 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
834 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
835 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
836 "WERR_NOT_SUPPORTED\n",
838 return werror_to_ntstatus(werr
);
841 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
845 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
846 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
848 struct winbindd_domain
*domain
;
850 struct rpc_pipe_client
*netlogon_pipe
;
851 struct dcerpc_binding_handle
*b
= NULL
;
854 domain
= wb_child_domain();
855 if (domain
== NULL
) {
856 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
860 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
861 if (!NT_STATUS_IS_OK(status
)) {
862 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
866 b
= netlogon_pipe
->binding_handle
;
868 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(domain
->conn
.netlogon_creds
,
869 netlogon_pipe
->binding_handle
,
874 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
879 /* Pass back result code - zero for success, other values for
880 specific failures. */
882 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
883 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
886 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
887 ("Update of DNS records via RW DC %s returned %s\n",
888 domain
->name
, nt_errstr(status
)));
893 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
894 struct winbind_SamLogon
*r
)
896 struct winbindd_domain
*domain
;
898 DATA_BLOB lm_response
, nt_response
;
901 domain
= wb_child_domain();
902 if (domain
== NULL
) {
903 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
906 /* TODO: Handle interactive logons here */
907 if (r
->in
.validation_level
!= 3 ||
908 r
->in
.logon
.network
== NULL
||
909 (r
->in
.logon_level
!= NetlogonNetworkInformation
910 && r
->in
.logon_level
!= NetlogonNetworkTransitiveInformation
)) {
911 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
915 lm_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->lm
.data
, r
->in
.logon
.network
->lm
.length
);
916 nt_response
= data_blob_talloc(p
->mem_ctx
, r
->in
.logon
.network
->nt
.data
, r
->in
.logon
.network
->nt
.length
);
918 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
919 r
->in
.logon
.network
->identity_info
.parameter_control
,
920 r
->in
.logon
.network
->identity_info
.account_name
.string
,
921 r
->in
.logon
.network
->identity_info
.domain_name
.string
,
922 r
->in
.logon
.network
->identity_info
.workstation
.string
,
923 r
->in
.logon
.network
->challenge
,
924 lm_response
, nt_response
,
925 &r
->out
.authoritative
,
928 &r
->out
.validation
.sam3
);
932 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
933 struct winbindd_domain
*domain
,
934 struct winbind_LogonControl
*r
)
937 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
938 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
939 WERROR check_result
= WERR_INTERNAL_ERROR
;
941 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
943 return WERR_NOT_ENOUGH_MEMORY
;
946 if (domain
->internal
) {
947 check_result
= WERR_OK
;
952 * For now we just force a reconnect
954 * TODO: take care of the optional '\dcname'
956 invalidate_cm_connection(domain
);
957 domain
->conn
.netlogon_force_reauth
= true;
958 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
959 reset_cm_connection_on_error(domain
, NULL
, status
);
960 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
961 status
= NT_STATUS_NO_LOGON_SERVERS
;
963 if (!NT_STATUS_IS_OK(status
)) {
964 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
965 __func__
, domain
->name
, domain
->alt_name
,
968 * Here we return a top level error!
969 * This is different than TC_QUERY or TC_VERIFY.
971 return ntstatus_to_werror(status
);
973 check_result
= WERR_OK
;
976 info2
->pdc_connection_status
= WERR_OK
;
977 if (domain
->dcname
!= NULL
) {
978 info2
->flags
|= NETLOGON_HAS_IP
;
979 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
980 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
982 if (info2
->trusted_dc_name
== NULL
) {
983 return WERR_NOT_ENOUGH_MEMORY
;
986 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
987 if (info2
->trusted_dc_name
== NULL
) {
988 return WERR_NOT_ENOUGH_MEMORY
;
991 info2
->tc_connection_status
= check_result
;
993 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
994 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
995 "pdc_connection[%s] tc_connection[%s]\n",
996 __func__
, domain
->name
, domain
->alt_name
,
998 win_errstr(info2
->pdc_connection_status
),
999 win_errstr(info2
->tc_connection_status
)));
1002 r
->out
.query
->info2
= info2
;
1004 DEBUG(5, ("%s: succeeded.\n", __func__
));
1008 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
1009 struct winbindd_domain
*domain
,
1010 struct winbind_LogonControl
*r
)
1013 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1014 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1015 WERROR check_result
= WERR_INTERNAL_ERROR
;
1017 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1018 if (info2
== NULL
) {
1019 return WERR_NOT_ENOUGH_MEMORY
;
1022 if (domain
->internal
) {
1023 check_result
= WERR_OK
;
1027 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1028 reset_cm_connection_on_error(domain
, NULL
, status
);
1029 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1030 status
= NT_STATUS_NO_LOGON_SERVERS
;
1032 if (!NT_STATUS_IS_OK(status
)) {
1033 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1034 nt_errstr(status
)));
1035 check_result
= ntstatus_to_werror(status
);
1038 check_result
= WERR_OK
;
1041 info2
->pdc_connection_status
= WERR_OK
;
1042 if (domain
->dcname
!= NULL
) {
1043 info2
->flags
|= NETLOGON_HAS_IP
;
1044 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1045 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1047 if (info2
->trusted_dc_name
== NULL
) {
1048 return WERR_NOT_ENOUGH_MEMORY
;
1051 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1052 if (info2
->trusted_dc_name
== NULL
) {
1053 return WERR_NOT_ENOUGH_MEMORY
;
1056 info2
->tc_connection_status
= check_result
;
1058 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1059 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1060 "pdc_connection[%s] tc_connection[%s]\n",
1061 __func__
, domain
->name
, domain
->alt_name
,
1063 win_errstr(info2
->pdc_connection_status
),
1064 win_errstr(info2
->tc_connection_status
)));
1067 r
->out
.query
->info2
= info2
;
1069 DEBUG(5, ("%s: succeeded.\n", __func__
));
1073 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1074 struct winbindd_domain
*domain
,
1075 struct winbind_LogonControl
*r
)
1077 TALLOC_CTX
*frame
= talloc_stackframe();
1080 struct lsa_String trusted_domain_name
= {};
1081 struct lsa_StringLarge trusted_domain_name_l
= {};
1082 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1083 struct policy_handle local_lsa_policy
= {};
1084 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1085 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1086 struct cli_credentials
*creds
= NULL
;
1087 struct samr_Password
*cur_nt_hash
= NULL
;
1088 uint32_t trust_attributes
= 0;
1089 struct samr_Password new_owf_password
= {};
1091 struct samr_Password old_owf_password
= {};
1093 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1094 bool fetch_fti
= false;
1095 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1096 struct netr_TrustInfo
*trust_info
= NULL
;
1097 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1098 struct dcerpc_binding_handle
*b
= NULL
;
1099 WERROR check_result
= WERR_INTERNAL_ERROR
;
1100 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1103 trusted_domain_name
.string
= domain
->name
;
1104 trusted_domain_name_l
.string
= domain
->name
;
1106 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1107 if (info2
== NULL
) {
1109 return WERR_NOT_ENOUGH_MEMORY
;
1112 if (domain
->internal
) {
1113 check_result
= WERR_OK
;
1117 status
= pdb_get_trust_credentials(domain
->name
,
1121 if (NT_STATUS_IS_OK(status
)) {
1122 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1126 if (!domain
->primary
) {
1127 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1129 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1131 if (!NT_STATUS_IS_OK(status
)) {
1132 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1133 __location__
, __func__
, nt_errstr(status
)));
1135 return WERR_INTERNAL_ERROR
;
1137 local_lsa
= local_lsa_pipe
->binding_handle
;
1139 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1141 &trusted_domain_name
,
1142 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1144 if (!NT_STATUS_IS_OK(status
)) {
1145 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%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_OBJECT_NAME_NOT_FOUND
)) {
1151 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1152 __location__
, __func__
, domain
->name
));
1154 return WERR_NO_SUCH_DOMAIN
;
1156 if (!NT_STATUS_IS_OK(result
)) {
1157 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1158 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1160 return WERR_INTERNAL_ERROR
;
1163 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1164 "returned no trusted domain information\n",
1165 __location__
, __func__
));
1167 return WERR_INTERNAL_ERROR
;
1170 local_tdo
= &tdi
->info_ex
;
1171 trust_attributes
= local_tdo
->trust_attributes
;
1174 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1175 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1177 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1179 &trusted_domain_name
,
1180 LSA_FOREST_TRUST_DOMAIN_INFO
,
1182 if (!NT_STATUS_IS_OK(status
)) {
1183 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1184 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1186 return WERR_INTERNAL_ERROR
;
1188 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1189 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1190 __func__
, domain
->name
));
1193 result
= NT_STATUS_OK
;
1195 if (!NT_STATUS_IS_OK(result
)) {
1196 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1197 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1199 return WERR_INTERNAL_ERROR
;
1202 TALLOC_FREE(old_fti
);
1206 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1207 reset_cm_connection_on_error(domain
, NULL
, status
);
1208 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1209 status
= NT_STATUS_NO_LOGON_SERVERS
;
1211 if (!NT_STATUS_IS_OK(status
)) {
1212 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1213 nt_errstr(status
)));
1214 check_result
= ntstatus_to_werror(status
);
1217 check_result
= WERR_OK
;
1218 b
= netlogon_pipe
->binding_handle
;
1220 if (cur_nt_hash
== NULL
) {
1221 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1226 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1229 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1230 status
= NT_STATUS_NOT_SUPPORTED
;
1232 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1234 status
= NT_STATUS_OK
;
1236 if (!NT_STATUS_IS_OK(status
)) {
1238 reset_cm_connection_on_error(domain
, b
, status
))
1243 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1245 domain
->name
, nt_errstr(status
)));
1246 check_result
= ntstatus_to_werror(status
);
1251 if (new_fti
!= NULL
) {
1252 struct lsa_ForestTrustInformation old_fti
= {};
1253 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1254 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1256 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1259 if (!NT_STATUS_IS_OK(status
)) {
1260 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1261 __location__
, __func__
,
1262 domain
->name
, nt_errstr(status
)));
1264 return ntstatus_to_werror(status
);
1267 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1269 &trusted_domain_name_l
,
1270 LSA_FOREST_TRUST_DOMAIN_INFO
,
1272 0, /* check_only=0 => store it! */
1275 if (!NT_STATUS_IS_OK(status
)) {
1276 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1277 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1279 return WERR_INTERNAL_ERROR
;
1281 if (!NT_STATUS_IS_OK(result
)) {
1282 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1283 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1285 return ntstatus_to_werror(result
);
1289 status
= netlogon_creds_cli_ServerGetTrustInfo(domain
->conn
.netlogon_creds
,
1294 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1295 status
= NT_STATUS_NOT_SUPPORTED
;
1297 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1298 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1299 nt_errstr(status
)));
1300 verify_result
= WERR_OK
;
1303 if (!NT_STATUS_IS_OK(status
)) {
1304 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1308 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1309 nt_errstr(status
)));
1311 if (!dcerpc_binding_handle_is_connected(b
)) {
1312 check_result
= ntstatus_to_werror(status
);
1315 verify_result
= ntstatus_to_werror(status
);
1320 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1321 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1323 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1324 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1329 cmp_new
= memcmp(new_owf_password
.hash
,
1331 sizeof(cur_nt_hash
->hash
));
1332 cmp_old
= memcmp(old_owf_password
.hash
,
1334 sizeof(cur_nt_hash
->hash
));
1335 if (cmp_new
!= 0 && cmp_old
!= 0) {
1336 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1337 "any password known to dcname[%s]\n",
1338 __func__
, domain
->name
, domain
->alt_name
,
1340 verify_result
= WERR_WRONG_PASSWORD
;
1345 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1346 "against the old password known to dcname[%s]\n",
1347 __func__
, domain
->name
, domain
->alt_name
,
1351 verify_result
= WERR_OK
;
1355 verify_result
= check_result
;
1357 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1358 info2
->pdc_connection_status
= verify_result
;
1359 if (domain
->dcname
!= NULL
) {
1360 info2
->flags
|= NETLOGON_HAS_IP
;
1361 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1362 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1364 if (info2
->trusted_dc_name
== NULL
) {
1366 return WERR_NOT_ENOUGH_MEMORY
;
1369 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1370 if (info2
->trusted_dc_name
== NULL
) {
1372 return WERR_NOT_ENOUGH_MEMORY
;
1375 info2
->tc_connection_status
= check_result
;
1377 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1378 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1379 "pdc_connection[%s] tc_connection[%s]\n",
1380 __func__
, domain
->name
, domain
->alt_name
,
1382 win_errstr(info2
->pdc_connection_status
),
1383 win_errstr(info2
->tc_connection_status
)));
1386 r
->out
.query
->info2
= info2
;
1388 DEBUG(5, ("%s: succeeded.\n", __func__
));
1393 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1394 struct winbindd_domain
*domain
,
1395 struct winbind_LogonControl
*r
)
1397 struct messaging_context
*msg_ctx
= server_messaging_context();
1399 struct rpc_pipe_client
*netlogon_pipe
;
1400 struct cli_credentials
*creds
= NULL
;
1401 struct samr_Password
*cur_nt_hash
= NULL
;
1402 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1403 struct dcerpc_binding_handle
*b
;
1404 WERROR change_result
= WERR_OK
;
1407 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1408 if (info1
== NULL
) {
1409 return WERR_NOT_ENOUGH_MEMORY
;
1412 if (domain
->internal
) {
1413 return WERR_NOT_SUPPORTED
;
1416 status
= pdb_get_trust_credentials(domain
->name
,
1420 if (NT_STATUS_IS_OK(status
)) {
1421 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1426 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1427 reset_cm_connection_on_error(domain
, NULL
, status
);
1428 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1429 status
= NT_STATUS_NO_LOGON_SERVERS
;
1431 if (!NT_STATUS_IS_OK(status
)) {
1432 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1433 __func__
, domain
->name
, domain
->alt_name
,
1434 nt_errstr(status
)));
1436 * Here we return a top level error!
1437 * This is different than TC_QUERY or TC_VERIFY.
1439 return ntstatus_to_werror(status
);
1441 b
= netlogon_pipe
->binding_handle
;
1443 if (cur_nt_hash
== NULL
) {
1444 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1447 TALLOC_FREE(cur_nt_hash
);
1449 status
= trust_pw_change(domain
->conn
.netlogon_creds
,
1450 msg_ctx
, b
, domain
->name
,
1453 if (!NT_STATUS_IS_OK(status
)) {
1454 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1459 DEBUG(1, ("trust_pw_change(%s): %s\n",
1460 domain
->name
, nt_errstr(status
)));
1462 change_result
= ntstatus_to_werror(status
);
1466 change_result
= WERR_OK
;
1469 info1
->pdc_connection_status
= change_result
;
1471 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1472 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1473 "pdc_connection[%s]\n",
1474 __func__
, domain
->name
, domain
->alt_name
,
1476 win_errstr(info1
->pdc_connection_status
)));
1479 r
->out
.query
->info1
= info1
;
1481 DEBUG(5, ("%s: succeeded.\n", __func__
));
1485 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1486 struct winbind_LogonControl
*r
)
1488 struct winbindd_domain
*domain
;
1490 domain
= wb_child_domain();
1491 if (domain
== NULL
) {
1492 return WERR_NO_SUCH_DOMAIN
;
1495 switch (r
->in
.function_code
) {
1496 case NETLOGON_CONTROL_REDISCOVER
:
1497 if (r
->in
.level
!= 2) {
1498 return WERR_INVALID_PARAMETER
;
1500 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1501 case NETLOGON_CONTROL_TC_QUERY
:
1502 if (r
->in
.level
!= 2) {
1503 return WERR_INVALID_PARAMETER
;
1505 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1506 case NETLOGON_CONTROL_TC_VERIFY
:
1507 if (r
->in
.level
!= 2) {
1508 return WERR_INVALID_PARAMETER
;
1510 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1511 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1512 if (r
->in
.level
!= 1) {
1513 return WERR_INVALID_PARAMETER
;
1515 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1520 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1521 __func__
, r
->in
.function_code
));
1522 return WERR_NOT_SUPPORTED
;
1525 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1526 struct winbind_GetForestTrustInformation
*r
)
1528 TALLOC_CTX
*frame
= talloc_stackframe();
1529 NTSTATUS status
, result
;
1530 struct winbindd_domain
*domain
;
1531 struct rpc_pipe_client
*netlogon_pipe
;
1532 struct dcerpc_binding_handle
*b
;
1534 struct lsa_String trusted_domain_name
= {};
1535 struct lsa_StringLarge trusted_domain_name_l
= {};
1536 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1537 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1538 struct lsa_ForestTrustInformation _old_fti
= {};
1539 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1540 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1541 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1542 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1543 bool update_fti
= false;
1544 struct rpc_pipe_client
*local_lsa_pipe
;
1545 struct policy_handle local_lsa_policy
;
1546 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1548 domain
= wb_child_domain();
1549 if (domain
== NULL
) {
1551 return WERR_NO_SUCH_DOMAIN
;
1555 * checking for domain->internal and domain->primary
1556 * makes sure we only do some work when running as DC.
1559 if (domain
->internal
) {
1561 return WERR_NO_SUCH_DOMAIN
;
1564 if (domain
->primary
) {
1566 return WERR_NO_SUCH_DOMAIN
;
1569 trusted_domain_name
.string
= domain
->name
;
1570 trusted_domain_name_l
.string
= domain
->name
;
1572 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1574 if (!NT_STATUS_IS_OK(status
)) {
1575 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1576 __location__
, __func__
, nt_errstr(status
)));
1578 return WERR_INTERNAL_ERROR
;
1580 local_lsa
= local_lsa_pipe
->binding_handle
;
1582 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1584 &trusted_domain_name
,
1585 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1587 if (!NT_STATUS_IS_OK(status
)) {
1588 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1589 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1591 return WERR_INTERNAL_ERROR
;
1593 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1594 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1595 __location__
, __func__
, domain
->name
));
1597 return WERR_NO_SUCH_DOMAIN
;
1599 if (!NT_STATUS_IS_OK(result
)) {
1600 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1601 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1603 return WERR_INTERNAL_ERROR
;
1606 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1607 "returned no trusted domain information\n",
1608 __location__
, __func__
));
1610 return WERR_INTERNAL_ERROR
;
1613 tdo
= &tdi
->info_ex
;
1615 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1616 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1617 __func__
, tdo
->netbios_name
.string
,
1618 tdo
->domain_name
.string
,
1619 (unsigned)tdo
->trust_attributes
));
1621 return WERR_NO_SUCH_DOMAIN
;
1624 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1626 return WERR_INVALID_FLAGS
;
1630 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1631 reset_cm_connection_on_error(domain
, NULL
, status
);
1632 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1633 status
= NT_STATUS_NO_LOGON_SERVERS
;
1635 if (!NT_STATUS_IS_OK(status
)) {
1636 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1637 nt_errstr(status
)));
1639 return ntstatus_to_werror(status
);
1641 b
= netlogon_pipe
->binding_handle
;
1643 status
= netlogon_creds_cli_GetForestTrustInformation(domain
->conn
.netlogon_creds
,
1646 if (!NT_STATUS_IS_OK(status
)) {
1647 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1651 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1652 domain
->name
, nt_errstr(status
)));
1654 return ntstatus_to_werror(status
);
1657 *r
->out
.forest_trust_info
= new_fti
;
1659 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1663 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1665 &trusted_domain_name
,
1666 LSA_FOREST_TRUST_DOMAIN_INFO
,
1668 if (!NT_STATUS_IS_OK(status
)) {
1669 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1670 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1672 return WERR_INTERNAL_ERROR
;
1674 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1675 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1676 __func__
, domain
->name
));
1678 old_fti
= &_old_fti
;
1679 result
= NT_STATUS_OK
;
1681 if (!NT_STATUS_IS_OK(result
)) {
1682 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1683 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1685 return WERR_INTERNAL_ERROR
;
1688 if (old_fti
== NULL
) {
1689 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1690 "returned success without returning forest trust information\n",
1691 __location__
, __func__
));
1693 return WERR_INTERNAL_ERROR
;
1700 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1702 if (!NT_STATUS_IS_OK(status
)) {
1703 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1704 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1706 return ntstatus_to_werror(status
);
1709 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1711 &trusted_domain_name_l
,
1712 LSA_FOREST_TRUST_DOMAIN_INFO
,
1714 0, /* check_only=0 => store it! */
1717 if (!NT_STATUS_IS_OK(status
)) {
1718 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1719 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1721 return WERR_INTERNAL_ERROR
;
1723 if (!NT_STATUS_IS_OK(result
)) {
1724 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1725 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1727 return ntstatus_to_werror(result
);
1731 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1736 NTSTATUS
_winbind_SendToSam(struct pipes_struct
*p
, struct winbind_SendToSam
*r
)
1738 struct winbindd_domain
*domain
;
1740 struct rpc_pipe_client
*netlogon_pipe
;
1741 struct dcerpc_binding_handle
*b
= NULL
;
1744 DEBUG(5, ("_winbind_SendToSam received\n"));
1745 domain
= wb_child_domain();
1746 if (domain
== NULL
) {
1747 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1751 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
1752 if (!NT_STATUS_IS_OK(status
)) {
1753 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1757 b
= netlogon_pipe
->binding_handle
;
1759 status
= netlogon_creds_cli_SendToSam(domain
->conn
.netlogon_creds
,
1760 netlogon_pipe
->binding_handle
,
1762 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {