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"
36 #include "rpc_client/cli_netlogon.h"
37 #include "rpc_client/util_netlogon.h"
39 void _wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
41 *r
->out
.out_data
= r
->in
.in_data
;
44 bool reset_cm_connection_on_error(struct winbindd_domain
*domain
,
45 struct dcerpc_binding_handle
*b
,
48 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) ||
49 NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
) ||
50 NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
)) {
51 invalidate_cm_connection(domain
);
52 domain
->conn
.netlogon_force_reauth
= true;
56 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
57 NT_STATUS_EQUAL(status
, NT_STATUS_IO_DEVICE_ERROR
))
59 invalidate_cm_connection(domain
);
60 /* We invalidated the connection. */
64 if (b
!= NULL
&& !dcerpc_binding_handle_is_connected(b
)) {
65 invalidate_cm_connection(domain
);
72 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
74 struct winbindd_domain
*domain
= wb_child_domain();
77 enum lsa_SidType type
;
81 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
84 status
= wb_cache_sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
85 &dom_name
, &name
, &type
);
86 reset_cm_connection_on_error(domain
, NULL
, status
);
87 if (!NT_STATUS_IS_OK(status
)) {
91 *r
->out
.domain
= dom_name
;
97 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
99 struct winbindd_domain
*domain
= wb_child_domain();
100 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
103 if (domain
== NULL
) {
104 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
108 * This breaks the winbindd_domain->methods abstraction: This
109 * is only called for remote domains, and both winbindd_msrpc
110 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
111 * 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 reset_cm_connection_on_error(domain
, NULL
, status
);
124 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
126 struct winbindd_domain
*domain
= wb_child_domain();
129 if (domain
== NULL
) {
130 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
133 status
= wb_cache_name_to_sid(domain
, p
->mem_ctx
, r
->in
.domain
,
134 r
->in
.name
, r
->in
.flags
,
135 r
->out
.sid
, r
->out
.type
);
136 reset_cm_connection_on_error(domain
, NULL
, status
);
140 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
141 struct wbint_Sids2UnixIDs
*r
)
145 struct lsa_DomainInfo
*d
;
146 struct wbint_TransID
*ids
;
149 struct id_map
**id_map_ptrs
= NULL
;
150 struct idmap_domain
*dom
;
151 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
153 if (r
->in
.domains
->count
!= 1) {
154 return NT_STATUS_INVALID_PARAMETER
;
157 d
= &r
->in
.domains
->domains
[0];
158 ids
= r
->in
.ids
->ids
;
159 num_ids
= r
->in
.ids
->num_ids
;
161 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
163 DEBUG(10, ("idmap domain %s:%s not found\n",
164 d
->name
.string
, sid_string_dbg(d
->sid
)));
166 for (i
=0; i
<num_ids
; i
++) {
168 ids
[i
].xid
= (struct unixid
) {
170 .type
= ID_TYPE_NOT_SPECIFIED
177 id_map_ptrs
= id_map_ptrs_init(talloc_tos(), num_ids
);
178 if (id_map_ptrs
== NULL
) {
183 * Convert the input data into a list of id_map structs
184 * suitable for handing in to the idmap sids_to_unixids
188 for (i
=0; i
<num_ids
; i
++) {
189 struct id_map
*m
= id_map_ptrs
[i
];
191 sid_compose(m
->sid
, d
->sid
, ids
[i
].rid
);
192 m
->status
= ID_UNKNOWN
;
193 m
->xid
= (struct unixid
) { .type
= ids
[i
].type
};
196 status
= dom
->methods
->sids_to_unixids(dom
, id_map_ptrs
);
198 if (!NT_STATUS_IS_OK(status
)) {
199 DEBUG(10, ("sids_to_unixids returned %s\n",
205 * Extract the results for handing them back to the caller.
208 for (i
=0; i
<num_ids
; i
++) {
209 struct id_map
*m
= id_map_ptrs
[i
];
211 if (!idmap_unix_id_is_in_range(m
->xid
.id
, dom
)) {
212 DBG_DEBUG("id %"PRIu32
" is out of range "
213 "%"PRIu32
"-%"PRIu32
" for domain %s\n",
214 m
->xid
.id
, dom
->low_id
, dom
->high_id
,
216 m
->status
= ID_UNMAPPED
;
219 if (m
->status
== ID_MAPPED
) {
222 ids
[i
].xid
.id
= UINT32_MAX
;
223 ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
229 status
= NT_STATUS_NO_MEMORY
;
231 TALLOC_FREE(id_map_ptrs
);
235 NTSTATUS
_wbint_UnixIDs2Sids(struct pipes_struct
*p
,
236 struct wbint_UnixIDs2Sids
*r
)
238 struct id_map
**maps
;
242 maps
= id_map_ptrs_init(talloc_tos(), r
->in
.num_ids
);
244 return NT_STATUS_NO_MEMORY
;
247 for (i
=0; i
<r
->in
.num_ids
; i
++) {
248 maps
[i
]->status
= ID_UNKNOWN
;
249 maps
[i
]->xid
= r
->in
.xids
[i
];
252 status
= idmap_backend_unixids_to_sids(maps
, r
->in
.domain_name
,
254 if (!NT_STATUS_IS_OK(status
)) {
259 for (i
=0; i
<r
->in
.num_ids
; i
++) {
260 r
->out
.xids
[i
] = maps
[i
]->xid
;
261 sid_copy(&r
->out
.sids
[i
], maps
[i
]->sid
);
269 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
274 status
= idmap_allocate_uid(&xid
);
275 if (!NT_STATUS_IS_OK(status
)) {
278 *r
->out
.uid
= xid
.id
;
282 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
287 status
= idmap_allocate_gid(&xid
);
288 if (!NT_STATUS_IS_OK(status
)) {
291 *r
->out
.gid
= xid
.id
;
295 NTSTATUS
_wbint_GetNssInfo(struct pipes_struct
*p
, struct wbint_GetNssInfo
*r
)
297 struct idmap_domain
*domain
;
300 domain
= idmap_find_domain(r
->in
.info
->domain_name
);
301 if ((domain
== NULL
) || (domain
->query_user
== NULL
)) {
302 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
305 status
= domain
->query_user(domain
, r
->in
.info
);
309 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
310 struct wbint_LookupUserAliases
*r
)
312 struct winbindd_domain
*domain
= wb_child_domain();
315 if (domain
== NULL
) {
316 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
319 status
= wb_cache_lookup_useraliases(domain
, p
->mem_ctx
,
320 r
->in
.sids
->num_sids
,
322 &r
->out
.rids
->num_rids
,
324 reset_cm_connection_on_error(domain
, NULL
, status
);
328 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
329 struct wbint_LookupUserGroups
*r
)
331 struct winbindd_domain
*domain
= wb_child_domain();
334 if (domain
== NULL
) {
335 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
338 status
= wb_cache_lookup_usergroups(domain
, p
->mem_ctx
, r
->in
.sid
,
339 &r
->out
.sids
->num_sids
,
341 reset_cm_connection_on_error(domain
, NULL
, status
);
345 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
346 struct wbint_QuerySequenceNumber
*r
)
348 struct winbindd_domain
*domain
= wb_child_domain();
351 if (domain
== NULL
) {
352 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
355 status
= wb_cache_sequence_number(domain
, r
->out
.sequence
);
356 reset_cm_connection_on_error(domain
, NULL
, status
);
360 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
361 struct wbint_LookupGroupMembers
*r
)
363 struct winbindd_domain
*domain
= wb_child_domain();
364 uint32_t i
, num_names
;
365 struct dom_sid
*sid_mem
;
367 uint32_t *name_types
;
370 if (domain
== NULL
) {
371 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
374 status
= wb_cache_lookup_groupmem(domain
, p
->mem_ctx
, r
->in
.sid
,
375 r
->in
.type
, &num_names
, &sid_mem
,
376 &names
, &name_types
);
377 reset_cm_connection_on_error(domain
, NULL
, status
);
378 if (!NT_STATUS_IS_OK(status
)) {
382 r
->out
.members
->num_principals
= num_names
;
383 r
->out
.members
->principals
= talloc_array(
384 r
->out
.members
, struct wbint_Principal
, num_names
);
385 if (r
->out
.members
->principals
== NULL
) {
386 return NT_STATUS_NO_MEMORY
;
389 for (i
=0; i
<num_names
; i
++) {
390 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
391 sid_copy(&m
->sid
, &sid_mem
[i
]);
392 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
393 m
->type
= (enum lsa_SidType
)name_types
[i
];
399 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
400 struct wbint_QueryGroupList
*r
)
402 TALLOC_CTX
*frame
= NULL
;
403 struct winbindd_domain
*domain
= wb_child_domain();
405 uint32_t num_local_groups
= 0;
406 struct wb_acct_info
*local_groups
= NULL
;
407 uint32_t num_dom_groups
= 0;
408 struct wb_acct_info
*dom_groups
= NULL
;
410 uint64_t num_total
= 0;
411 struct wbint_Principal
*result
;
412 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
413 bool include_local_groups
= false;
415 if (domain
== NULL
) {
416 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
419 frame
= talloc_stackframe();
421 switch (lp_server_role()) {
422 case ROLE_ACTIVE_DIRECTORY_DC
:
423 if (domain
->internal
) {
425 * we want to include local groups
426 * for BUILTIN and WORKGROUP
428 include_local_groups
= true;
433 * We might include local groups in more
434 * setups later, but that requires more work
440 if (include_local_groups
) {
441 status
= wb_cache_enum_local_groups(domain
, frame
,
444 reset_cm_connection_on_error(domain
, NULL
, status
);
445 if (!NT_STATUS_IS_OK(status
)) {
450 status
= wb_cache_enum_dom_groups(domain
, frame
,
453 reset_cm_connection_on_error(domain
, NULL
, status
);
454 if (!NT_STATUS_IS_OK(status
)) {
458 num_total
= num_local_groups
+ num_dom_groups
;
459 if (num_total
> UINT32_MAX
) {
460 status
= NT_STATUS_INTERNAL_ERROR
;
464 result
= talloc_array(frame
, struct wbint_Principal
, num_total
);
465 if (result
== NULL
) {
466 status
= 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
) {
478 status
= NT_STATUS_NO_MEMORY
;
482 num_local_groups
= 0;
484 for (i
= 0; i
< num_dom_groups
; i
++) {
485 struct wb_acct_info
*dg
= &dom_groups
[i
];
486 struct wbint_Principal
*rg
= &result
[ti
++];
488 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
489 rg
->type
= SID_NAME_DOM_GRP
;
490 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
491 if (rg
->name
== NULL
) {
492 status
= NT_STATUS_NO_MEMORY
;
498 r
->out
.groups
->num_principals
= ti
;
499 r
->out
.groups
->principals
= talloc_move(r
->out
.groups
, &result
);
501 status
= NT_STATUS_OK
;
507 NTSTATUS
_wbint_QueryUserRidList(struct pipes_struct
*p
,
508 struct wbint_QueryUserRidList
*r
)
510 struct winbindd_domain
*domain
= wb_child_domain();
513 if (domain
== NULL
) {
514 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
518 * Right now this is overkill. We should add a backend call
519 * just querying the rids.
522 status
= wb_cache_query_user_list(domain
, p
->mem_ctx
,
524 reset_cm_connection_on_error(domain
, NULL
, status
);
526 if (!NT_STATUS_IS_OK(status
)) {
530 r
->out
.rids
->num_rids
= talloc_array_length(r
->out
.rids
->rids
);
535 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
537 struct winbindd_domain
*domain
= wb_child_domain();
538 struct rpc_pipe_client
*netlogon_pipe
;
539 struct netr_DsRGetDCNameInfo
*dc_info
;
542 unsigned int orig_timeout
;
543 struct dcerpc_binding_handle
*b
;
545 if (domain
== NULL
) {
546 return dsgetdcname(p
->mem_ctx
, server_messaging_context(),
547 r
->in
.domain_name
, r
->in
.domain_guid
,
548 r
->in
.site_name
? r
->in
.site_name
: "",
553 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
555 reset_cm_connection_on_error(domain
, NULL
, status
);
556 if (!NT_STATUS_IS_OK(status
)) {
557 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
561 b
= netlogon_pipe
->binding_handle
;
563 /* This call can take a long time - allow the server to time out.
564 35 seconds should do it. */
566 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
568 if (domain
->active_directory
) {
569 status
= dcerpc_netr_DsRGetDCName(b
,
570 p
->mem_ctx
, domain
->dcname
,
571 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
572 r
->in
.flags
, r
->out
.dc_info
, &werr
);
573 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
576 if (reset_cm_connection_on_error(domain
, NULL
, status
)) {
578 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
580 reset_cm_connection_on_error(domain
, NULL
, status
);
581 if (!NT_STATUS_IS_OK(status
)) {
582 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
586 b
= netlogon_pipe
->binding_handle
;
588 /* This call can take a long time - allow the server to time out.
589 35 seconds should do it. */
591 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
596 * Fallback to less capable methods
599 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
600 if (dc_info
== NULL
) {
601 status
= NT_STATUS_NO_MEMORY
;
605 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
606 status
= dcerpc_netr_GetDcName(b
,
607 p
->mem_ctx
, domain
->dcname
,
608 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
610 status
= dcerpc_netr_GetAnyDCName(b
,
611 p
->mem_ctx
, domain
->dcname
,
612 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
615 reset_cm_connection_on_error(domain
, NULL
, status
);
616 if (!NT_STATUS_IS_OK(status
)) {
617 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
621 if (!W_ERROR_IS_OK(werr
)) {
622 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
624 status
= werror_to_ntstatus(werr
);
628 *r
->out
.dc_info
= dc_info
;
629 status
= NT_STATUS_OK
;
632 /* And restore our original timeout. */
633 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
638 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
640 struct winbindd_domain
*domain
= wb_child_domain();
643 enum lsa_SidType
*types
;
644 struct wbint_Principal
*result
;
648 if (domain
== NULL
) {
649 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
652 status
= wb_cache_rids_to_names(domain
, talloc_tos(), r
->in
.domain_sid
,
653 r
->in
.rids
->rids
, r
->in
.rids
->num_rids
,
654 &domain_name
, &names
, &types
);
655 reset_cm_connection_on_error(domain
, NULL
, status
);
656 if (!NT_STATUS_IS_OK(status
)) {
660 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
662 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
663 r
->in
.rids
->num_rids
);
664 if (result
== NULL
) {
665 return NT_STATUS_NO_MEMORY
;
668 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
669 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
670 r
->in
.rids
->rids
[i
]);
671 result
[i
].type
= types
[i
];
672 result
[i
].name
= talloc_move(result
, &names
[i
]);
677 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
678 r
->out
.names
->principals
= result
;
682 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
683 struct wbint_CheckMachineAccount
*r
)
685 struct winbindd_domain
*domain
;
689 domain
= wb_child_domain();
690 if (domain
== NULL
) {
691 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
695 invalidate_cm_connection(domain
);
696 domain
->conn
.netlogon_force_reauth
= true;
699 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
700 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
701 status
= cm_connect_netlogon_secure(domain
,
703 &netlogon_creds_ctx
);
706 /* There is a race condition between fetching the trust account
707 password and the periodic machine password change. So it's
708 possible that the trust account password has been changed on us.
709 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
711 #define MAX_RETRIES 3
713 if ((num_retries
< MAX_RETRIES
)
714 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
719 if (!NT_STATUS_IS_OK(status
)) {
720 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
724 /* Pass back result code - zero for success, other values for
725 specific failures. */
727 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
728 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
731 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
732 ("Checking the trust account password for domain %s returned %s\n",
733 domain
->name
, nt_errstr(status
)));
738 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
739 struct wbint_ChangeMachineAccount
*r
)
741 struct messaging_context
*msg_ctx
= server_messaging_context();
742 struct winbindd_domain
*domain
;
744 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
745 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
747 domain
= wb_child_domain();
748 if (domain
== NULL
) {
749 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
752 status
= cm_connect_netlogon_secure(domain
,
754 &netlogon_creds_ctx
);
755 if (!NT_STATUS_IS_OK(status
)) {
756 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
760 status
= trust_pw_change(netlogon_creds_ctx
,
762 netlogon_pipe
->binding_handle
,
767 /* Pass back result code - zero for success, other values for
768 specific failures. */
770 DEBUG(3,("domain %s secret %s\n", domain
->name
,
771 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
774 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
775 ("Changing the trust account password for domain %s returned %s\n",
776 domain
->name
, nt_errstr(status
)));
781 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
784 struct winbindd_domain
*domain
;
785 struct rpc_pipe_client
*netlogon_pipe
;
786 union netr_CONTROL_QUERY_INFORMATION info
;
788 fstring logon_server
;
789 struct dcerpc_binding_handle
*b
;
792 domain
= wb_child_domain();
793 if (domain
== NULL
) {
794 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
798 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
799 reset_cm_connection_on_error(domain
, NULL
, status
);
800 if (!NT_STATUS_IS_OK(status
)) {
801 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
806 b
= netlogon_pipe
->binding_handle
;
808 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
809 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
810 if (*r
->out
.dcname
== NULL
) {
811 DEBUG(2, ("Could not allocate memory\n"));
812 return NT_STATUS_NO_MEMORY
;
816 * This provokes a WERR_NOT_SUPPORTED error message. This is
817 * documented in the wspp docs. I could not get a successful
818 * call to work, but the main point here is testing that the
819 * netlogon pipe works.
821 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
822 logon_server
, NETLOGON_CONTROL_QUERY
,
825 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
830 if (!NT_STATUS_IS_OK(status
)) {
831 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
836 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
837 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
838 "WERR_NOT_SUPPORTED\n",
840 return werror_to_ntstatus(werr
);
843 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
847 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
848 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
850 struct winbindd_domain
*domain
;
852 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
853 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
855 domain
= wb_child_domain();
856 if (domain
== NULL
) {
857 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
860 status
= cm_connect_netlogon_secure(domain
,
862 &netlogon_creds_ctx
);
863 if (!NT_STATUS_IS_OK(status
)) {
864 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
868 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx
,
869 netlogon_pipe
->binding_handle
,
874 /* Pass back result code - zero for success, other values for
875 specific failures. */
877 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
878 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
881 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
882 ("Update of DNS records via RW DC %s returned %s\n",
883 domain
->name
, nt_errstr(status
)));
888 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
889 struct winbind_SamLogon
*r
)
891 struct winbindd_domain
*domain
;
893 struct netr_IdentityInfo
*identity_info
= NULL
;
894 const uint8_t chal_zero
[8] = {0, };
895 const uint8_t *challenge
= chal_zero
;
896 DATA_BLOB lm_response
, nt_response
;
898 uint16_t validation_level
;
899 union netr_Validation
*validation
= NULL
;
900 bool interactive
= false;
902 domain
= wb_child_domain();
903 if (domain
== NULL
) {
904 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
907 switch (r
->in
.validation_level
) {
912 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
915 switch (r
->in
.logon_level
) {
916 case NetlogonInteractiveInformation
:
917 case NetlogonServiceInformation
:
918 case NetlogonInteractiveTransitiveInformation
:
919 case NetlogonServiceTransitiveInformation
:
920 if (r
->in
.logon
.password
== NULL
) {
921 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
925 identity_info
= &r
->in
.logon
.password
->identity_info
;
927 challenge
= chal_zero
;
928 lm_response
= data_blob_talloc(p
->mem_ctx
,
929 r
->in
.logon
.password
->lmpassword
.hash
,
930 sizeof(r
->in
.logon
.password
->lmpassword
.hash
));
931 nt_response
= data_blob_talloc(p
->mem_ctx
,
932 r
->in
.logon
.password
->ntpassword
.hash
,
933 sizeof(r
->in
.logon
.password
->ntpassword
.hash
));
936 case NetlogonNetworkInformation
:
937 case NetlogonNetworkTransitiveInformation
:
938 if (r
->in
.logon
.network
== NULL
) {
939 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
943 identity_info
= &r
->in
.logon
.network
->identity_info
;
945 challenge
= r
->in
.logon
.network
->challenge
;
946 lm_response
= data_blob_talloc(p
->mem_ctx
,
947 r
->in
.logon
.network
->lm
.data
,
948 r
->in
.logon
.network
->lm
.length
);
949 nt_response
= data_blob_talloc(p
->mem_ctx
,
950 r
->in
.logon
.network
->nt
.data
,
951 r
->in
.logon
.network
->nt
.length
);
954 case NetlogonGenericInformation
:
955 if (r
->in
.logon
.generic
== NULL
) {
956 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
959 identity_info
= &r
->in
.logon
.generic
->identity_info
;
961 * Not implemented here...
963 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
966 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
969 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
971 identity_info
->parameter_control
,
972 identity_info
->account_name
.string
,
973 identity_info
->domain_name
.string
,
974 identity_info
->workstation
.string
,
976 lm_response
, nt_response
,
977 &r
->out
.authoritative
,
982 if (!NT_STATUS_IS_OK(status
)) {
985 switch (r
->in
.validation_level
) {
987 status
= map_validation_to_info3(p
->mem_ctx
,
990 &r
->out
.validation
.sam3
);
991 TALLOC_FREE(validation
);
992 if (!NT_STATUS_IS_OK(status
)) {
997 status
= map_validation_to_info6(p
->mem_ctx
,
1000 &r
->out
.validation
.sam6
);
1001 TALLOC_FREE(validation
);
1002 if (!NT_STATUS_IS_OK(status
)) {
1005 return NT_STATUS_OK
;
1008 smb_panic(__location__
);
1009 return NT_STATUS_INTERNAL_ERROR
;
1012 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
1013 struct winbindd_domain
*domain
,
1014 struct winbind_LogonControl
*r
)
1017 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1018 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1019 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1020 WERROR check_result
= WERR_INTERNAL_ERROR
;
1022 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1023 if (info2
== NULL
) {
1024 return WERR_NOT_ENOUGH_MEMORY
;
1027 if (domain
->internal
) {
1028 check_result
= WERR_OK
;
1033 * For now we just force a reconnect
1035 * TODO: take care of the optional '\dcname'
1037 invalidate_cm_connection(domain
);
1038 domain
->conn
.netlogon_force_reauth
= true;
1039 status
= cm_connect_netlogon_secure(domain
,
1041 &netlogon_creds_ctx
);
1042 reset_cm_connection_on_error(domain
, NULL
, status
);
1043 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1044 status
= NT_STATUS_NO_LOGON_SERVERS
;
1046 if (!NT_STATUS_IS_OK(status
)) {
1047 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1048 __func__
, domain
->name
, domain
->alt_name
,
1049 nt_errstr(status
)));
1051 * Here we return a top level error!
1052 * This is different than TC_QUERY or TC_VERIFY.
1054 return ntstatus_to_werror(status
);
1056 check_result
= WERR_OK
;
1059 info2
->pdc_connection_status
= WERR_OK
;
1060 if (domain
->dcname
!= NULL
) {
1061 info2
->flags
|= NETLOGON_HAS_IP
;
1062 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1063 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1065 if (info2
->trusted_dc_name
== NULL
) {
1066 return WERR_NOT_ENOUGH_MEMORY
;
1069 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1070 if (info2
->trusted_dc_name
== NULL
) {
1071 return WERR_NOT_ENOUGH_MEMORY
;
1074 info2
->tc_connection_status
= check_result
;
1076 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1077 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1078 "pdc_connection[%s] tc_connection[%s]\n",
1079 __func__
, domain
->name
, domain
->alt_name
,
1081 win_errstr(info2
->pdc_connection_status
),
1082 win_errstr(info2
->tc_connection_status
)));
1085 r
->out
.query
->info2
= info2
;
1087 DEBUG(5, ("%s: succeeded.\n", __func__
));
1091 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
1092 struct winbindd_domain
*domain
,
1093 struct winbind_LogonControl
*r
)
1096 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1097 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1098 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1099 WERROR check_result
= WERR_INTERNAL_ERROR
;
1101 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1102 if (info2
== NULL
) {
1103 return WERR_NOT_ENOUGH_MEMORY
;
1106 if (domain
->internal
) {
1107 check_result
= WERR_OK
;
1111 status
= cm_connect_netlogon_secure(domain
,
1113 &netlogon_creds_ctx
);
1114 reset_cm_connection_on_error(domain
, NULL
, status
);
1115 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1116 status
= NT_STATUS_NO_LOGON_SERVERS
;
1118 if (!NT_STATUS_IS_OK(status
)) {
1119 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1120 nt_errstr(status
)));
1121 check_result
= ntstatus_to_werror(status
);
1124 check_result
= WERR_OK
;
1127 info2
->pdc_connection_status
= WERR_OK
;
1128 if (domain
->dcname
!= NULL
) {
1129 info2
->flags
|= NETLOGON_HAS_IP
;
1130 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1131 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1133 if (info2
->trusted_dc_name
== NULL
) {
1134 return WERR_NOT_ENOUGH_MEMORY
;
1137 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1138 if (info2
->trusted_dc_name
== NULL
) {
1139 return WERR_NOT_ENOUGH_MEMORY
;
1142 info2
->tc_connection_status
= check_result
;
1144 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1145 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1146 "pdc_connection[%s] tc_connection[%s]\n",
1147 __func__
, domain
->name
, domain
->alt_name
,
1149 win_errstr(info2
->pdc_connection_status
),
1150 win_errstr(info2
->tc_connection_status
)));
1153 r
->out
.query
->info2
= info2
;
1155 DEBUG(5, ("%s: succeeded.\n", __func__
));
1159 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1160 struct winbindd_domain
*domain
,
1161 struct winbind_LogonControl
*r
)
1163 TALLOC_CTX
*frame
= talloc_stackframe();
1166 struct lsa_String trusted_domain_name
= {};
1167 struct lsa_StringLarge trusted_domain_name_l
= {};
1168 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1169 struct policy_handle local_lsa_policy
= {};
1170 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1171 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1172 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1173 struct cli_credentials
*creds
= NULL
;
1174 struct samr_Password
*cur_nt_hash
= NULL
;
1175 uint32_t trust_attributes
= 0;
1176 struct samr_Password new_owf_password
= {};
1178 struct samr_Password old_owf_password
= {};
1180 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1181 bool fetch_fti
= false;
1182 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1183 struct netr_TrustInfo
*trust_info
= NULL
;
1184 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1185 struct dcerpc_binding_handle
*b
= NULL
;
1186 WERROR check_result
= WERR_INTERNAL_ERROR
;
1187 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1190 trusted_domain_name
.string
= domain
->name
;
1191 trusted_domain_name_l
.string
= domain
->name
;
1193 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1194 if (info2
== NULL
) {
1196 return WERR_NOT_ENOUGH_MEMORY
;
1199 if (domain
->internal
) {
1200 check_result
= WERR_OK
;
1204 status
= pdb_get_trust_credentials(domain
->name
,
1208 if (NT_STATUS_IS_OK(status
)) {
1209 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1213 if (!domain
->primary
) {
1214 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1216 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1218 if (!NT_STATUS_IS_OK(status
)) {
1219 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1220 __location__
, __func__
, nt_errstr(status
)));
1222 return WERR_INTERNAL_ERROR
;
1224 local_lsa
= local_lsa_pipe
->binding_handle
;
1226 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1228 &trusted_domain_name
,
1229 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1231 if (!NT_STATUS_IS_OK(status
)) {
1232 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1233 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1235 return WERR_INTERNAL_ERROR
;
1237 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1238 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1239 __location__
, __func__
, domain
->name
));
1241 return WERR_NO_SUCH_DOMAIN
;
1243 if (!NT_STATUS_IS_OK(result
)) {
1244 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1245 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1247 return WERR_INTERNAL_ERROR
;
1250 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1251 "returned no trusted domain information\n",
1252 __location__
, __func__
));
1254 return WERR_INTERNAL_ERROR
;
1257 local_tdo
= &tdi
->info_ex
;
1258 trust_attributes
= local_tdo
->trust_attributes
;
1261 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1262 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1264 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1266 &trusted_domain_name
,
1267 LSA_FOREST_TRUST_DOMAIN_INFO
,
1269 if (!NT_STATUS_IS_OK(status
)) {
1270 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1271 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1273 return WERR_INTERNAL_ERROR
;
1275 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1276 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1277 __func__
, domain
->name
));
1280 result
= NT_STATUS_OK
;
1282 if (!NT_STATUS_IS_OK(result
)) {
1283 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1284 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1286 return WERR_INTERNAL_ERROR
;
1289 TALLOC_FREE(old_fti
);
1293 status
= cm_connect_netlogon_secure(domain
,
1295 &netlogon_creds_ctx
);
1296 reset_cm_connection_on_error(domain
, NULL
, status
);
1297 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1298 status
= NT_STATUS_NO_LOGON_SERVERS
;
1300 if (!NT_STATUS_IS_OK(status
)) {
1301 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1302 nt_errstr(status
)));
1303 check_result
= ntstatus_to_werror(status
);
1306 check_result
= WERR_OK
;
1307 b
= netlogon_pipe
->binding_handle
;
1309 if (cur_nt_hash
== NULL
) {
1310 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1315 status
= netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx
,
1318 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1319 status
= NT_STATUS_NOT_SUPPORTED
;
1321 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1323 status
= NT_STATUS_OK
;
1325 if (!NT_STATUS_IS_OK(status
)) {
1327 reset_cm_connection_on_error(domain
, b
, status
))
1332 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1334 domain
->name
, nt_errstr(status
)));
1335 check_result
= ntstatus_to_werror(status
);
1340 if (new_fti
!= NULL
) {
1341 struct lsa_ForestTrustInformation old_fti
= {};
1342 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1343 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1345 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1348 if (!NT_STATUS_IS_OK(status
)) {
1349 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1350 __location__
, __func__
,
1351 domain
->name
, nt_errstr(status
)));
1353 return ntstatus_to_werror(status
);
1356 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1358 &trusted_domain_name_l
,
1359 LSA_FOREST_TRUST_DOMAIN_INFO
,
1361 0, /* check_only=0 => store it! */
1364 if (!NT_STATUS_IS_OK(status
)) {
1365 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1366 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1368 return WERR_INTERNAL_ERROR
;
1370 if (!NT_STATUS_IS_OK(result
)) {
1371 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1372 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1374 return ntstatus_to_werror(result
);
1378 status
= netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx
,
1383 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1384 status
= NT_STATUS_NOT_SUPPORTED
;
1386 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1387 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1388 nt_errstr(status
)));
1389 verify_result
= WERR_OK
;
1392 if (!NT_STATUS_IS_OK(status
)) {
1393 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1397 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1398 nt_errstr(status
)));
1400 if (!dcerpc_binding_handle_is_connected(b
)) {
1401 check_result
= ntstatus_to_werror(status
);
1404 verify_result
= ntstatus_to_werror(status
);
1409 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1410 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1412 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1413 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1418 cmp_new
= memcmp(new_owf_password
.hash
,
1420 sizeof(cur_nt_hash
->hash
));
1421 cmp_old
= memcmp(old_owf_password
.hash
,
1423 sizeof(cur_nt_hash
->hash
));
1424 if (cmp_new
!= 0 && cmp_old
!= 0) {
1425 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1426 "any password known to dcname[%s]\n",
1427 __func__
, domain
->name
, domain
->alt_name
,
1429 verify_result
= WERR_WRONG_PASSWORD
;
1434 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1435 "against the old password known to dcname[%s]\n",
1436 __func__
, domain
->name
, domain
->alt_name
,
1440 verify_result
= WERR_OK
;
1444 verify_result
= check_result
;
1446 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1447 info2
->pdc_connection_status
= verify_result
;
1448 if (domain
->dcname
!= NULL
) {
1449 info2
->flags
|= NETLOGON_HAS_IP
;
1450 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1451 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1453 if (info2
->trusted_dc_name
== NULL
) {
1455 return WERR_NOT_ENOUGH_MEMORY
;
1458 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1459 if (info2
->trusted_dc_name
== NULL
) {
1461 return WERR_NOT_ENOUGH_MEMORY
;
1464 info2
->tc_connection_status
= check_result
;
1466 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
)) {
1467 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1468 "pdc_connection[%s] tc_connection[%s]\n",
1469 __func__
, domain
->name
, domain
->alt_name
,
1471 win_errstr(info2
->pdc_connection_status
),
1472 win_errstr(info2
->tc_connection_status
)));
1475 r
->out
.query
->info2
= info2
;
1477 DEBUG(5, ("%s: succeeded.\n", __func__
));
1482 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1483 struct winbindd_domain
*domain
,
1484 struct winbind_LogonControl
*r
)
1486 struct messaging_context
*msg_ctx
= server_messaging_context();
1488 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1489 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1490 struct cli_credentials
*creds
= NULL
;
1491 struct samr_Password
*cur_nt_hash
= NULL
;
1492 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1493 struct dcerpc_binding_handle
*b
;
1494 WERROR change_result
= WERR_OK
;
1497 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1498 if (info1
== NULL
) {
1499 return WERR_NOT_ENOUGH_MEMORY
;
1502 if (domain
->internal
) {
1503 return WERR_NOT_SUPPORTED
;
1506 status
= pdb_get_trust_credentials(domain
->name
,
1510 if (NT_STATUS_IS_OK(status
)) {
1511 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1516 status
= cm_connect_netlogon_secure(domain
,
1518 &netlogon_creds_ctx
);
1519 reset_cm_connection_on_error(domain
, NULL
, status
);
1520 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1521 status
= NT_STATUS_NO_LOGON_SERVERS
;
1523 if (!NT_STATUS_IS_OK(status
)) {
1524 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1525 __func__
, domain
->name
, domain
->alt_name
,
1526 nt_errstr(status
)));
1528 * Here we return a top level error!
1529 * This is different than TC_QUERY or TC_VERIFY.
1531 return ntstatus_to_werror(status
);
1533 b
= netlogon_pipe
->binding_handle
;
1535 if (cur_nt_hash
== NULL
) {
1536 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1539 TALLOC_FREE(cur_nt_hash
);
1541 status
= trust_pw_change(netlogon_creds_ctx
,
1542 msg_ctx
, b
, domain
->name
,
1545 if (!NT_STATUS_IS_OK(status
)) {
1546 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1551 DEBUG(1, ("trust_pw_change(%s): %s\n",
1552 domain
->name
, nt_errstr(status
)));
1554 change_result
= ntstatus_to_werror(status
);
1558 change_result
= WERR_OK
;
1561 info1
->pdc_connection_status
= change_result
;
1563 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1564 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1565 "pdc_connection[%s]\n",
1566 __func__
, domain
->name
, domain
->alt_name
,
1568 win_errstr(info1
->pdc_connection_status
)));
1571 r
->out
.query
->info1
= info1
;
1573 DEBUG(5, ("%s: succeeded.\n", __func__
));
1577 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1578 struct winbind_LogonControl
*r
)
1580 struct winbindd_domain
*domain
;
1582 domain
= wb_child_domain();
1583 if (domain
== NULL
) {
1584 return WERR_NO_SUCH_DOMAIN
;
1587 switch (r
->in
.function_code
) {
1588 case NETLOGON_CONTROL_REDISCOVER
:
1589 if (r
->in
.level
!= 2) {
1590 return WERR_INVALID_PARAMETER
;
1592 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1593 case NETLOGON_CONTROL_TC_QUERY
:
1594 if (r
->in
.level
!= 2) {
1595 return WERR_INVALID_PARAMETER
;
1597 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1598 case NETLOGON_CONTROL_TC_VERIFY
:
1599 if (r
->in
.level
!= 2) {
1600 return WERR_INVALID_PARAMETER
;
1602 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1603 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1604 if (r
->in
.level
!= 1) {
1605 return WERR_INVALID_PARAMETER
;
1607 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1612 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1613 __func__
, r
->in
.function_code
));
1614 return WERR_NOT_SUPPORTED
;
1617 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1618 struct winbind_GetForestTrustInformation
*r
)
1620 TALLOC_CTX
*frame
= talloc_stackframe();
1621 NTSTATUS status
, result
;
1622 struct winbindd_domain
*domain
;
1623 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1624 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1625 struct dcerpc_binding_handle
*b
;
1627 struct lsa_String trusted_domain_name
= {};
1628 struct lsa_StringLarge trusted_domain_name_l
= {};
1629 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1630 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1631 struct lsa_ForestTrustInformation _old_fti
= {};
1632 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1633 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1634 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1635 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1636 bool update_fti
= false;
1637 struct rpc_pipe_client
*local_lsa_pipe
;
1638 struct policy_handle local_lsa_policy
;
1639 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1641 domain
= wb_child_domain();
1642 if (domain
== NULL
) {
1644 return WERR_NO_SUCH_DOMAIN
;
1648 * checking for domain->internal and domain->primary
1649 * makes sure we only do some work when running as DC.
1652 if (domain
->internal
) {
1654 return WERR_NO_SUCH_DOMAIN
;
1657 if (domain
->primary
) {
1659 return WERR_NO_SUCH_DOMAIN
;
1662 trusted_domain_name
.string
= domain
->name
;
1663 trusted_domain_name_l
.string
= domain
->name
;
1665 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1667 if (!NT_STATUS_IS_OK(status
)) {
1668 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1669 __location__
, __func__
, nt_errstr(status
)));
1671 return WERR_INTERNAL_ERROR
;
1673 local_lsa
= local_lsa_pipe
->binding_handle
;
1675 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1677 &trusted_domain_name
,
1678 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1680 if (!NT_STATUS_IS_OK(status
)) {
1681 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1682 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1684 return WERR_INTERNAL_ERROR
;
1686 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1687 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1688 __location__
, __func__
, domain
->name
));
1690 return WERR_NO_SUCH_DOMAIN
;
1692 if (!NT_STATUS_IS_OK(result
)) {
1693 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1694 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1696 return WERR_INTERNAL_ERROR
;
1699 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1700 "returned no trusted domain information\n",
1701 __location__
, __func__
));
1703 return WERR_INTERNAL_ERROR
;
1706 tdo
= &tdi
->info_ex
;
1708 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1709 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1710 __func__
, tdo
->netbios_name
.string
,
1711 tdo
->domain_name
.string
,
1712 (unsigned)tdo
->trust_attributes
));
1714 return WERR_NO_SUCH_DOMAIN
;
1717 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1719 return WERR_INVALID_FLAGS
;
1723 status
= cm_connect_netlogon_secure(domain
,
1725 &netlogon_creds_ctx
);
1726 reset_cm_connection_on_error(domain
, NULL
, status
);
1727 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1728 status
= NT_STATUS_NO_LOGON_SERVERS
;
1730 if (!NT_STATUS_IS_OK(status
)) {
1731 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1732 nt_errstr(status
)));
1734 return ntstatus_to_werror(status
);
1736 b
= netlogon_pipe
->binding_handle
;
1738 status
= netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx
,
1741 if (!NT_STATUS_IS_OK(status
)) {
1742 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1746 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1747 domain
->name
, nt_errstr(status
)));
1749 return ntstatus_to_werror(status
);
1752 *r
->out
.forest_trust_info
= new_fti
;
1754 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1758 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1760 &trusted_domain_name
,
1761 LSA_FOREST_TRUST_DOMAIN_INFO
,
1763 if (!NT_STATUS_IS_OK(status
)) {
1764 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1765 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1767 return WERR_INTERNAL_ERROR
;
1769 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1770 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1771 __func__
, domain
->name
));
1773 old_fti
= &_old_fti
;
1774 result
= NT_STATUS_OK
;
1776 if (!NT_STATUS_IS_OK(result
)) {
1777 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1778 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1780 return WERR_INTERNAL_ERROR
;
1783 if (old_fti
== NULL
) {
1784 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1785 "returned success without returning forest trust information\n",
1786 __location__
, __func__
));
1788 return WERR_INTERNAL_ERROR
;
1795 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1797 if (!NT_STATUS_IS_OK(status
)) {
1798 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1799 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1801 return ntstatus_to_werror(status
);
1804 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1806 &trusted_domain_name_l
,
1807 LSA_FOREST_TRUST_DOMAIN_INFO
,
1809 0, /* check_only=0 => store it! */
1812 if (!NT_STATUS_IS_OK(status
)) {
1813 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1814 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1816 return WERR_INTERNAL_ERROR
;
1818 if (!NT_STATUS_IS_OK(result
)) {
1819 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1820 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1822 return ntstatus_to_werror(result
);
1826 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
1831 NTSTATUS
_winbind_SendToSam(struct pipes_struct
*p
, struct winbind_SendToSam
*r
)
1833 struct winbindd_domain
*domain
;
1835 struct rpc_pipe_client
*netlogon_pipe
;
1836 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1838 DEBUG(5, ("_winbind_SendToSam received\n"));
1839 domain
= wb_child_domain();
1840 if (domain
== NULL
) {
1841 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1844 status
= cm_connect_netlogon_secure(domain
,
1846 &netlogon_creds_ctx
);
1847 if (!NT_STATUS_IS_OK(status
)) {
1848 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1852 status
= netlogon_creds_cli_SendToSam(netlogon_creds_ctx
,
1853 netlogon_pipe
->binding_handle
,