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/rpc/dcesrv_core.h"
29 #include "librpc/gen_ndr/ndr_winbind.h"
30 #include "librpc/gen_ndr/ndr_winbind_scompat.h"
31 #include "../librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "../librpc/gen_ndr/ndr_lsa_c.h"
34 #include "../libcli/security/security.h"
35 #include "../libcli/auth/netlogon_creds_cli.h"
37 #include "../source4/dsdb/samdb/samdb.h"
38 #include "rpc_client/cli_netlogon.h"
39 #include "rpc_client/util_netlogon.h"
40 #include "libsmb/dsgetdcname.h"
41 #include "lib/global_contexts.h"
43 NTSTATUS
_wbint_Ping(struct pipes_struct
*p
, struct wbint_Ping
*r
)
45 *r
->out
.out_data
= r
->in
.in_data
;
49 NTSTATUS
_wbint_InitConnection(struct pipes_struct
*p
,
50 struct wbint_InitConnection
*r
)
52 struct winbindd_domain
*domain
= wb_child_domain();
54 if (r
->in
.dcname
!= NULL
&& strlen(r
->in
.dcname
) > 0) {
55 TALLOC_FREE(domain
->dcname
);
56 domain
->dcname
= talloc_strdup(domain
, r
->in
.dcname
);
57 if (domain
->dcname
== NULL
) {
58 return NT_STATUS_NO_MEMORY
;
62 init_dc_connection(domain
, false);
64 if (!domain
->initialized
) {
66 * If we return error here we can't do any cached
67 * authentication, but we may be in disconnected mode and can't
68 * initialize correctly. Do what the previous code did and just
69 * return without initialization, once we go online we'll
72 DBG_INFO("%s returning without initialization online = %d\n",
73 domain
->name
, (int)domain
->online
);
76 *r
->out
.name
= talloc_strdup(p
->mem_ctx
, domain
->name
);
77 if (*r
->out
.name
== NULL
) {
78 return NT_STATUS_NO_MEMORY
;
81 if (domain
->alt_name
!= NULL
) {
82 *r
->out
.alt_name
= talloc_strdup(p
->mem_ctx
, domain
->alt_name
);
83 if (*r
->out
.alt_name
== NULL
) {
84 return NT_STATUS_NO_MEMORY
;
88 r
->out
.sid
= dom_sid_dup(p
->mem_ctx
, &domain
->sid
);
89 if (r
->out
.sid
== NULL
) {
90 return NT_STATUS_NO_MEMORY
;
94 if (domain
->active_directory
) {
95 *r
->out
.flags
|= WB_DOMINFO_DOMAIN_AD
;
96 *r
->out
.flags
|= WB_DOMINFO_DOMAIN_NATIVE
;
98 if (domain
->primary
) {
99 *r
->out
.flags
|= WB_DOMINFO_DOMAIN_PRIMARY
;
105 bool reset_cm_connection_on_error(struct winbindd_domain
*domain
,
106 struct dcerpc_binding_handle
*b
,
109 if (NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
) ||
110 NT_STATUS_EQUAL(status
, NT_STATUS_RPC_SEC_PKG_ERROR
) ||
111 NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_ACCESS_DENIED
)) {
112 invalidate_cm_connection(domain
);
113 domain
->conn
.netlogon_force_reauth
= true;
117 if (NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
) ||
118 NT_STATUS_EQUAL(status
, NT_STATUS_IO_DEVICE_ERROR
))
120 invalidate_cm_connection(domain
);
121 /* We invalidated the connection. */
125 if (b
!= NULL
&& !dcerpc_binding_handle_is_connected(b
)) {
126 invalidate_cm_connection(domain
);
133 NTSTATUS
_wbint_LookupSid(struct pipes_struct
*p
, struct wbint_LookupSid
*r
)
135 struct winbindd_domain
*domain
= wb_child_domain();
138 enum lsa_SidType type
;
141 if (domain
== NULL
) {
142 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
145 status
= wb_cache_sid_to_name(domain
, p
->mem_ctx
, r
->in
.sid
,
146 &dom_name
, &name
, &type
);
147 reset_cm_connection_on_error(domain
, NULL
, status
);
148 if (!NT_STATUS_IS_OK(status
)) {
152 *r
->out
.domain
= dom_name
;
158 NTSTATUS
_wbint_LookupSids(struct pipes_struct
*p
, struct wbint_LookupSids
*r
)
160 struct winbindd_domain
*domain
= wb_child_domain();
161 struct lsa_RefDomainList
*domains
= r
->out
.domains
;
165 if (domain
== NULL
) {
166 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
170 * This breaks the winbindd_domain->methods abstraction: This
171 * is only called for remote domains, and both winbindd_msrpc
172 * and winbindd_ad call into lsa_lookupsids anyway. Caching is
173 * done at the wbint RPC layer.
176 status
= rpc_lookup_sids(p
->mem_ctx
, domain
, r
->in
.sids
,
177 &domains
, &r
->out
.names
);
179 if (domains
!= NULL
) {
180 r
->out
.domains
= domains
;
183 if (!retry
&& reset_cm_connection_on_error(domain
, NULL
, status
)) {
191 NTSTATUS
_wbint_LookupName(struct pipes_struct
*p
, struct wbint_LookupName
*r
)
193 struct winbindd_domain
*domain
= wb_child_domain();
196 if (domain
== NULL
) {
197 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
200 status
= wb_cache_name_to_sid(domain
, p
->mem_ctx
, r
->in
.domain
,
201 r
->in
.name
, r
->in
.flags
,
202 r
->out
.sid
, r
->out
.type
);
203 reset_cm_connection_on_error(domain
, NULL
, status
);
207 NTSTATUS
_wbint_Sids2UnixIDs(struct pipes_struct
*p
,
208 struct wbint_Sids2UnixIDs
*r
)
212 struct lsa_DomainInfo
*d
;
213 struct wbint_TransID
*ids
;
216 struct id_map
**id_map_ptrs
= NULL
;
217 struct idmap_domain
*dom
;
218 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
220 if (r
->in
.domains
->count
!= 1) {
221 return NT_STATUS_INVALID_PARAMETER
;
224 d
= &r
->in
.domains
->domains
[0];
225 ids
= r
->in
.ids
->ids
;
226 num_ids
= r
->in
.ids
->num_ids
;
228 dom
= idmap_find_domain_with_sid(d
->name
.string
, d
->sid
);
230 struct dom_sid_buf buf
;
231 DEBUG(10, ("idmap domain %s:%s not found\n",
233 dom_sid_str_buf(d
->sid
, &buf
)));
235 for (i
=0; i
<num_ids
; i
++) {
237 ids
[i
].xid
= (struct unixid
) {
239 .type
= ID_TYPE_NOT_SPECIFIED
246 id_map_ptrs
= id_map_ptrs_init(talloc_tos(), num_ids
);
247 if (id_map_ptrs
== NULL
) {
252 * Convert the input data into a list of id_map structs
253 * suitable for handing in to the idmap sids_to_unixids
257 for (i
=0; i
<num_ids
; i
++) {
258 struct id_map
*m
= id_map_ptrs
[i
];
260 sid_compose(m
->sid
, d
->sid
, ids
[i
].rid
);
261 m
->status
= ID_UNKNOWN
;
262 m
->xid
= (struct unixid
) { .type
= ids
[i
].type_hint
};
265 status
= dom
->methods
->sids_to_unixids(dom
, id_map_ptrs
);
267 if (NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
)) {
269 * This is okay. We need to transfer the mapped ones
270 * up to our caller. The individual mappings carry the
271 * information whether they are mapped or not.
273 status
= NT_STATUS_OK
;
276 if (!NT_STATUS_IS_OK(status
)) {
277 DEBUG(10, ("sids_to_unixids returned %s\n",
283 * Extract the results for handing them back to the caller.
286 for (i
=0; i
<num_ids
; i
++) {
287 struct id_map
*m
= id_map_ptrs
[i
];
289 if (m
->status
== ID_REQUIRE_TYPE
) {
290 ids
[i
].xid
.id
= UINT32_MAX
;
291 ids
[i
].xid
.type
= ID_TYPE_WB_REQUIRE_TYPE
;
295 if (!idmap_unix_id_is_in_range(m
->xid
.id
, dom
)) {
296 DBG_DEBUG("id %"PRIu32
" is out of range "
297 "%"PRIu32
"-%"PRIu32
" for domain %s\n",
298 m
->xid
.id
, dom
->low_id
, dom
->high_id
,
300 m
->status
= ID_UNMAPPED
;
303 if (m
->status
== ID_MAPPED
) {
306 ids
[i
].xid
.id
= UINT32_MAX
;
307 ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
313 status
= NT_STATUS_NO_MEMORY
;
315 TALLOC_FREE(id_map_ptrs
);
319 NTSTATUS
_wbint_UnixIDs2Sids(struct pipes_struct
*p
,
320 struct wbint_UnixIDs2Sids
*r
)
322 struct id_map
**maps
;
326 maps
= id_map_ptrs_init(talloc_tos(), r
->in
.num_ids
);
328 return NT_STATUS_NO_MEMORY
;
331 for (i
=0; i
<r
->in
.num_ids
; i
++) {
332 maps
[i
]->status
= ID_UNKNOWN
;
333 maps
[i
]->xid
= r
->in
.xids
[i
];
336 status
= idmap_backend_unixids_to_sids(maps
, r
->in
.domain_name
,
338 if (!NT_STATUS_IS_OK(status
)) {
343 for (i
=0; i
<r
->in
.num_ids
; i
++) {
344 if (maps
[i
]->status
== ID_MAPPED
) {
345 r
->out
.xids
[i
] = maps
[i
]->xid
;
346 sid_copy(&r
->out
.sids
[i
], maps
[i
]->sid
);
348 r
->out
.sids
[i
] = (struct dom_sid
) { 0 };
357 NTSTATUS
_wbint_AllocateUid(struct pipes_struct
*p
, struct wbint_AllocateUid
*r
)
362 status
= idmap_allocate_uid(&xid
);
363 if (!NT_STATUS_IS_OK(status
)) {
366 *r
->out
.uid
= xid
.id
;
370 NTSTATUS
_wbint_AllocateGid(struct pipes_struct
*p
, struct wbint_AllocateGid
*r
)
375 status
= idmap_allocate_gid(&xid
);
376 if (!NT_STATUS_IS_OK(status
)) {
379 *r
->out
.gid
= xid
.id
;
383 NTSTATUS
_wbint_GetNssInfo(struct pipes_struct
*p
, struct wbint_GetNssInfo
*r
)
385 struct idmap_domain
*domain
;
388 domain
= idmap_find_domain(r
->in
.info
->domain_name
);
389 if ((domain
== NULL
) || (domain
->query_user
== NULL
)) {
390 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
393 status
= domain
->query_user(domain
, r
->in
.info
);
397 NTSTATUS
_wbint_LookupUserAliases(struct pipes_struct
*p
,
398 struct wbint_LookupUserAliases
*r
)
400 struct winbindd_domain
*domain
= wb_child_domain();
403 if (domain
== NULL
) {
404 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
407 status
= wb_cache_lookup_useraliases(domain
, p
->mem_ctx
,
408 r
->in
.sids
->num_sids
,
410 &r
->out
.rids
->num_rids
,
412 reset_cm_connection_on_error(domain
, NULL
, status
);
416 NTSTATUS
_wbint_LookupUserGroups(struct pipes_struct
*p
,
417 struct wbint_LookupUserGroups
*r
)
419 struct winbindd_domain
*domain
= wb_child_domain();
422 if (domain
== NULL
) {
423 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
426 status
= wb_cache_lookup_usergroups(domain
, p
->mem_ctx
, r
->in
.sid
,
427 &r
->out
.sids
->num_sids
,
429 reset_cm_connection_on_error(domain
, NULL
, status
);
433 NTSTATUS
_wbint_QuerySequenceNumber(struct pipes_struct
*p
,
434 struct wbint_QuerySequenceNumber
*r
)
436 struct winbindd_domain
*domain
= wb_child_domain();
439 if (domain
== NULL
) {
440 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
443 status
= wb_cache_sequence_number(domain
, r
->out
.sequence
);
444 reset_cm_connection_on_error(domain
, NULL
, status
);
448 NTSTATUS
_wbint_LookupGroupMembers(struct pipes_struct
*p
,
449 struct wbint_LookupGroupMembers
*r
)
451 struct winbindd_domain
*domain
= wb_child_domain();
452 uint32_t i
, num_names
;
453 struct dom_sid
*sid_mem
;
455 uint32_t *name_types
;
458 if (domain
== NULL
) {
459 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
462 status
= wb_cache_lookup_groupmem(domain
, p
->mem_ctx
, r
->in
.sid
,
463 r
->in
.type
, &num_names
, &sid_mem
,
464 &names
, &name_types
);
465 reset_cm_connection_on_error(domain
, NULL
, status
);
466 if (!NT_STATUS_IS_OK(status
)) {
470 r
->out
.members
->num_principals
= num_names
;
471 r
->out
.members
->principals
= talloc_array(
472 r
->out
.members
, struct wbint_Principal
, num_names
);
473 if (r
->out
.members
->principals
== NULL
) {
474 return NT_STATUS_NO_MEMORY
;
477 for (i
=0; i
<num_names
; i
++) {
478 struct wbint_Principal
*m
= &r
->out
.members
->principals
[i
];
479 sid_copy(&m
->sid
, &sid_mem
[i
]);
480 m
->name
= talloc_move(r
->out
.members
->principals
, &names
[i
]);
481 m
->type
= (enum lsa_SidType
)name_types
[i
];
487 NTSTATUS
_wbint_LookupAliasMembers(struct pipes_struct
*p
,
488 struct wbint_LookupAliasMembers
*r
)
490 struct winbindd_domain
*domain
= wb_child_domain();
493 if (domain
== NULL
) {
494 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
496 status
= wb_cache_lookup_aliasmem(domain
,
500 &r
->out
.sids
->num_sids
,
502 reset_cm_connection_on_error(domain
, NULL
, status
);
503 if (!NT_STATUS_IS_OK(status
)) {
510 NTSTATUS
_wbint_QueryGroupList(struct pipes_struct
*p
,
511 struct wbint_QueryGroupList
*r
)
513 TALLOC_CTX
*frame
= NULL
;
514 struct winbindd_domain
*domain
= wb_child_domain();
516 uint32_t num_local_groups
= 0;
517 struct wb_acct_info
*local_groups
= NULL
;
518 uint32_t num_dom_groups
= 0;
519 struct wb_acct_info
*dom_groups
= NULL
;
521 uint64_t num_total
= 0;
522 struct wbint_Principal
*result
;
523 NTSTATUS status
= NT_STATUS_UNSUCCESSFUL
;
524 bool include_local_groups
= false;
526 if (domain
== NULL
) {
527 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
530 frame
= talloc_stackframe();
532 switch (lp_server_role()) {
533 case ROLE_ACTIVE_DIRECTORY_DC
:
534 if (domain
->internal
) {
536 * we want to include local groups
537 * for BUILTIN and WORKGROUP
539 include_local_groups
= true;
542 case ROLE_DOMAIN_MEMBER
:
544 * This is needed for GETGRENT to show also e.g. BUILTIN/users.
545 * Otherwise the test_membership_user (smbtorture
546 * local.nss.membership) would fail (getgrouplist() would
547 * reports BUILTIN/users).
549 if (domain
->internal
) {
551 * we want to include local groups
552 * for BUILTIN and LOCALSAM
554 include_local_groups
= true;
559 * We might include local groups in more
560 * setups later, but that requires more work
566 if (include_local_groups
) {
567 status
= wb_cache_enum_local_groups(domain
, frame
,
570 reset_cm_connection_on_error(domain
, NULL
, status
);
571 if (!NT_STATUS_IS_OK(status
)) {
576 status
= wb_cache_enum_dom_groups(domain
, frame
,
579 reset_cm_connection_on_error(domain
, NULL
, status
);
580 if (!NT_STATUS_IS_OK(status
)) {
584 num_total
= num_local_groups
+ num_dom_groups
;
585 if (num_total
> UINT32_MAX
) {
586 status
= NT_STATUS_INTERNAL_ERROR
;
590 result
= talloc_array(frame
, struct wbint_Principal
, num_total
);
591 if (result
== NULL
) {
592 status
= NT_STATUS_NO_MEMORY
;
596 for (i
= 0; i
< num_local_groups
; i
++) {
597 struct wb_acct_info
*lg
= &local_groups
[i
];
598 struct wbint_Principal
*rg
= &result
[ti
++];
600 sid_compose(&rg
->sid
, &domain
->sid
, lg
->rid
);
601 rg
->type
= SID_NAME_ALIAS
;
602 rg
->name
= talloc_strdup(result
, lg
->acct_name
);
603 if (rg
->name
== NULL
) {
604 status
= NT_STATUS_NO_MEMORY
;
608 num_local_groups
= 0;
610 for (i
= 0; i
< num_dom_groups
; i
++) {
611 struct wb_acct_info
*dg
= &dom_groups
[i
];
612 struct wbint_Principal
*rg
= &result
[ti
++];
614 sid_compose(&rg
->sid
, &domain
->sid
, dg
->rid
);
615 rg
->type
= SID_NAME_DOM_GRP
;
616 rg
->name
= talloc_strdup(result
, dg
->acct_name
);
617 if (rg
->name
== NULL
) {
618 status
= NT_STATUS_NO_MEMORY
;
624 r
->out
.groups
->num_principals
= ti
;
625 r
->out
.groups
->principals
= talloc_move(r
->out
.groups
, &result
);
627 status
= NT_STATUS_OK
;
633 NTSTATUS
_wbint_QueryUserRidList(struct pipes_struct
*p
,
634 struct wbint_QueryUserRidList
*r
)
636 struct winbindd_domain
*domain
= wb_child_domain();
639 if (domain
== NULL
) {
640 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
644 * Right now this is overkill. We should add a backend call
645 * just querying the rids.
648 status
= wb_cache_query_user_list(domain
, p
->mem_ctx
,
650 reset_cm_connection_on_error(domain
, NULL
, status
);
652 if (!NT_STATUS_IS_OK(status
)) {
656 r
->out
.rids
->num_rids
= talloc_array_length(r
->out
.rids
->rids
);
661 NTSTATUS
_wbint_DsGetDcName(struct pipes_struct
*p
, struct wbint_DsGetDcName
*r
)
663 struct winbindd_domain
*domain
= wb_child_domain();
664 struct rpc_pipe_client
*netlogon_pipe
;
665 struct netr_DsRGetDCNameInfo
*dc_info
;
668 unsigned int orig_timeout
;
669 struct dcerpc_binding_handle
*b
;
671 bool try_dsrgetdcname
= false;
673 if (domain
== NULL
) {
674 return dsgetdcname(p
->mem_ctx
, global_messaging_context(),
675 r
->in
.domain_name
, r
->in
.domain_guid
,
676 r
->in
.site_name
? r
->in
.site_name
: "",
681 if (domain
->active_directory
) {
682 try_dsrgetdcname
= true;
686 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
688 reset_cm_connection_on_error(domain
, NULL
, status
);
689 if (!NT_STATUS_IS_OK(status
)) {
690 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
694 b
= netlogon_pipe
->binding_handle
;
696 /* This call can take a long time - allow the server to time out.
697 35 seconds should do it. */
699 orig_timeout
= rpccli_set_timeout(netlogon_pipe
, 35000);
701 if (try_dsrgetdcname
) {
702 status
= dcerpc_netr_DsRGetDCName(b
,
703 p
->mem_ctx
, domain
->dcname
,
704 r
->in
.domain_name
, NULL
, r
->in
.domain_guid
,
705 r
->in
.flags
, r
->out
.dc_info
, &werr
);
706 if (NT_STATUS_IS_OK(status
) && W_ERROR_IS_OK(werr
)) {
710 reset_cm_connection_on_error(domain
, NULL
, status
))
715 try_dsrgetdcname
= false;
720 * Fallback to less capable methods
723 dc_info
= talloc_zero(r
->out
.dc_info
, struct netr_DsRGetDCNameInfo
);
724 if (dc_info
== NULL
) {
725 status
= NT_STATUS_NO_MEMORY
;
729 if (r
->in
.flags
& DS_PDC_REQUIRED
) {
730 status
= dcerpc_netr_GetDcName(b
,
731 p
->mem_ctx
, domain
->dcname
,
732 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
734 status
= dcerpc_netr_GetAnyDCName(b
,
735 p
->mem_ctx
, domain
->dcname
,
736 r
->in
.domain_name
, &dc_info
->dc_unc
, &werr
);
739 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
743 if (!NT_STATUS_IS_OK(status
)) {
744 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
748 if (!W_ERROR_IS_OK(werr
)) {
749 DEBUG(10, ("dcerpc_netr_Get[Any]DCName failed: %s\n",
751 status
= werror_to_ntstatus(werr
);
755 *r
->out
.dc_info
= dc_info
;
756 status
= NT_STATUS_OK
;
759 /* And restore our original timeout. */
760 rpccli_set_timeout(netlogon_pipe
, orig_timeout
);
765 NTSTATUS
_wbint_LookupRids(struct pipes_struct
*p
, struct wbint_LookupRids
*r
)
767 struct winbindd_domain
*domain
= wb_child_domain();
770 enum lsa_SidType
*types
;
771 struct wbint_Principal
*result
;
775 if (domain
== NULL
) {
776 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
779 status
= wb_cache_rids_to_names(domain
, talloc_tos(), r
->in
.domain_sid
,
780 r
->in
.rids
->rids
, r
->in
.rids
->num_rids
,
781 &domain_name
, &names
, &types
);
782 reset_cm_connection_on_error(domain
, NULL
, status
);
783 if (!NT_STATUS_IS_OK(status
) &&
784 !NT_STATUS_EQUAL(status
, STATUS_SOME_UNMAPPED
)) {
788 *r
->out
.domain_name
= talloc_move(r
->out
.domain_name
, &domain_name
);
790 result
= talloc_array(p
->mem_ctx
, struct wbint_Principal
,
791 r
->in
.rids
->num_rids
);
792 if (result
== NULL
) {
793 return NT_STATUS_NO_MEMORY
;
796 for (i
=0; i
<r
->in
.rids
->num_rids
; i
++) {
797 sid_compose(&result
[i
].sid
, r
->in
.domain_sid
,
798 r
->in
.rids
->rids
[i
]);
799 result
[i
].type
= types
[i
];
800 result
[i
].name
= talloc_move(result
, &names
[i
]);
805 r
->out
.names
->num_principals
= r
->in
.rids
->num_rids
;
806 r
->out
.names
->principals
= result
;
810 NTSTATUS
_wbint_CheckMachineAccount(struct pipes_struct
*p
,
811 struct wbint_CheckMachineAccount
*r
)
813 struct winbindd_domain
*domain
;
817 domain
= wb_child_domain();
818 if (domain
== NULL
) {
819 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
823 invalidate_cm_connection(domain
);
824 domain
->conn
.netlogon_force_reauth
= true;
827 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
828 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
829 status
= cm_connect_netlogon_secure(domain
,
831 &netlogon_creds_ctx
);
834 /* There is a race condition between fetching the trust account
835 password and the periodic machine password change. So it's
836 possible that the trust account password has been changed on us.
837 We are returned NT_STATUS_ACCESS_DENIED if this happens. */
839 #define MAX_RETRIES 3
841 if ((num_retries
< MAX_RETRIES
)
842 && NT_STATUS_EQUAL(status
, NT_STATUS_ACCESS_DENIED
)) {
847 if (!NT_STATUS_IS_OK(status
)) {
848 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
852 /* Pass back result code - zero for success, other values for
853 specific failures. */
855 DEBUG(3,("domain %s secret is %s\n", domain
->name
,
856 NT_STATUS_IS_OK(status
) ? "good" : "bad"));
859 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
860 ("Checking the trust account password for domain %s returned %s\n",
861 domain
->name
, nt_errstr(status
)));
866 NTSTATUS
_wbint_ChangeMachineAccount(struct pipes_struct
*p
,
867 struct wbint_ChangeMachineAccount
*r
)
869 struct messaging_context
*msg_ctx
= global_messaging_context();
870 struct winbindd_domain
*domain
;
872 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
873 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
875 domain
= wb_child_domain();
876 if (domain
== NULL
) {
877 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
880 if (r
->in
.dcname
!= NULL
&& r
->in
.dcname
[0] != '\0') {
881 invalidate_cm_connection(domain
);
882 TALLOC_FREE(domain
->dcname
);
884 domain
->dcname
= talloc_strdup(domain
, r
->in
.dcname
);
885 if (domain
->dcname
== NULL
) {
886 status
= NT_STATUS_NO_MEMORY
;
889 domain
->force_dc
= true;
891 DBG_NOTICE("attempt connection to change trust account "
892 "password for %s at %s\n",
893 domain
->name
, domain
->dcname
);
896 status
= cm_connect_netlogon_secure(domain
,
898 &netlogon_creds_ctx
);
899 if (!NT_STATUS_IS_OK(status
)) {
900 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
904 status
= trust_pw_change(netlogon_creds_ctx
,
906 netlogon_pipe
->binding_handle
,
911 /* Pass back result code - zero for success, other values for
912 specific failures. */
914 DEBUG(3,("domain %s secret %s\n", domain
->name
,
915 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
918 DEBUG(NT_STATUS_IS_OK(status
) ? 5 :
919 domain
->force_dc
? 0 : 2,
920 ("Changing the trust account password for domain %s at %s "
921 "(forced: %s) returned %s\n",
922 domain
->name
, domain
->dcname
, domain
->force_dc
? "yes" : "no",
924 domain
->force_dc
= false;
929 NTSTATUS
_wbint_PingDc(struct pipes_struct
*p
, struct wbint_PingDc
*r
)
932 struct winbindd_domain
*domain
;
933 struct rpc_pipe_client
*netlogon_pipe
;
934 union netr_CONTROL_QUERY_INFORMATION info
;
936 fstring logon_server
;
937 struct dcerpc_binding_handle
*b
;
940 domain
= wb_child_domain();
941 if (domain
== NULL
) {
942 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
946 status
= cm_connect_netlogon(domain
, &netlogon_pipe
);
947 reset_cm_connection_on_error(domain
, NULL
, status
);
948 if (!NT_STATUS_IS_OK(status
)) {
949 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
954 b
= netlogon_pipe
->binding_handle
;
956 fstr_sprintf(logon_server
, "\\\\%s", domain
->dcname
);
957 *r
->out
.dcname
= talloc_strdup(p
->mem_ctx
, domain
->dcname
);
958 if (*r
->out
.dcname
== NULL
) {
959 DEBUG(2, ("Could not allocate memory\n"));
960 return NT_STATUS_NO_MEMORY
;
964 * This provokes a WERR_NOT_SUPPORTED error message. This is
965 * documented in the wspp docs. I could not get a successful
966 * call to work, but the main point here is testing that the
967 * netlogon pipe works.
969 status
= dcerpc_netr_LogonControl(b
, p
->mem_ctx
,
970 logon_server
, NETLOGON_CONTROL_QUERY
,
973 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
978 if (!NT_STATUS_IS_OK(status
)) {
979 DEBUG(2, ("dcerpc_netr_LogonControl failed: %s\n",
984 if (!W_ERROR_EQUAL(werr
, WERR_NOT_SUPPORTED
)) {
985 DEBUG(2, ("dcerpc_netr_LogonControl returned %s, expected "
986 "WERR_NOT_SUPPORTED\n",
988 return werror_to_ntstatus(werr
);
991 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
995 NTSTATUS
_winbind_DsrUpdateReadOnlyServerDnsRecords(struct pipes_struct
*p
,
996 struct winbind_DsrUpdateReadOnlyServerDnsRecords
*r
)
998 struct winbindd_domain
*domain
;
1000 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1001 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1002 struct dcerpc_binding_handle
*b
= NULL
;
1005 domain
= wb_child_domain();
1006 if (domain
== NULL
) {
1007 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1011 status
= cm_connect_netlogon_secure(domain
,
1013 &netlogon_creds_ctx
);
1014 if (!NT_STATUS_IS_OK(status
)) {
1015 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
1019 b
= netlogon_pipe
->binding_handle
;
1021 status
= netlogon_creds_cli_DsrUpdateReadOnlyServerDnsRecords(netlogon_creds_ctx
,
1022 netlogon_pipe
->binding_handle
,
1027 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1032 /* Pass back result code - zero for success, other values for
1033 specific failures. */
1035 DEBUG(3,("DNS records for domain %s %s\n", domain
->name
,
1036 NT_STATUS_IS_OK(status
) ? "changed" : "unchanged"));
1039 DEBUG(NT_STATUS_IS_OK(status
) ? 5 : 2,
1040 ("Update of DNS records via RW DC %s returned %s\n",
1041 domain
->name
, nt_errstr(status
)));
1046 NTSTATUS
_winbind_SamLogon(struct pipes_struct
*p
,
1047 struct winbind_SamLogon
*r
)
1049 struct dcesrv_call_state
*dce_call
= p
->dce_call
;
1050 struct dcesrv_connection
*dcesrv_conn
= dce_call
->conn
;
1051 const struct tsocket_address
*local_address
=
1052 dcesrv_connection_get_local_address(dcesrv_conn
);
1053 const struct tsocket_address
*remote_address
=
1054 dcesrv_connection_get_remote_address(dcesrv_conn
);
1055 struct winbindd_domain
*domain
;
1057 struct netr_IdentityInfo
*identity_info
= NULL
;
1058 DATA_BLOB lm_response
, nt_response
;
1059 DATA_BLOB challenge
= data_blob_null
;
1061 uint16_t validation_level
;
1062 union netr_Validation
*validation
= NULL
;
1063 bool interactive
= false;
1066 * Make sure we start with authoritative=true,
1067 * it will only set to false if we don't know the
1070 r
->out
.authoritative
= true;
1072 domain
= wb_child_domain();
1073 if (domain
== NULL
) {
1074 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1077 switch (r
->in
.validation_level
) {
1082 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1085 switch (r
->in
.logon_level
) {
1086 case NetlogonInteractiveInformation
:
1087 case NetlogonServiceInformation
:
1088 case NetlogonInteractiveTransitiveInformation
:
1089 case NetlogonServiceTransitiveInformation
:
1090 if (r
->in
.logon
.password
== NULL
) {
1091 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1095 identity_info
= &r
->in
.logon
.password
->identity_info
;
1097 challenge
= data_blob_null
;
1098 lm_response
= data_blob_talloc(p
->mem_ctx
,
1099 r
->in
.logon
.password
->lmpassword
.hash
,
1100 sizeof(r
->in
.logon
.password
->lmpassword
.hash
));
1101 nt_response
= data_blob_talloc(p
->mem_ctx
,
1102 r
->in
.logon
.password
->ntpassword
.hash
,
1103 sizeof(r
->in
.logon
.password
->ntpassword
.hash
));
1106 case NetlogonNetworkInformation
:
1107 case NetlogonNetworkTransitiveInformation
:
1108 if (r
->in
.logon
.network
== NULL
) {
1109 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1112 interactive
= false;
1113 identity_info
= &r
->in
.logon
.network
->identity_info
;
1115 challenge
= data_blob_talloc(p
->mem_ctx
,
1116 r
->in
.logon
.network
->challenge
,
1118 lm_response
= data_blob_talloc(p
->mem_ctx
,
1119 r
->in
.logon
.network
->lm
.data
,
1120 r
->in
.logon
.network
->lm
.length
);
1121 nt_response
= data_blob_talloc(p
->mem_ctx
,
1122 r
->in
.logon
.network
->nt
.data
,
1123 r
->in
.logon
.network
->nt
.length
);
1126 case NetlogonGenericInformation
:
1127 if (r
->in
.logon
.generic
== NULL
) {
1128 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1131 identity_info
= &r
->in
.logon
.generic
->identity_info
;
1133 * Not implemented here...
1135 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1138 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
1141 status
= winbind_dual_SamLogon(domain
, p
->mem_ctx
,
1143 identity_info
->parameter_control
,
1144 identity_info
->account_name
.string
,
1145 identity_info
->domain_name
.string
,
1146 identity_info
->workstation
.string
,
1147 identity_info
->logon_id
,
1151 lm_response
, nt_response
,
1154 &r
->out
.authoritative
,
1155 true, /* skip_sam */
1159 if (!NT_STATUS_IS_OK(status
)) {
1162 switch (r
->in
.validation_level
) {
1164 status
= map_validation_to_info3(p
->mem_ctx
,
1167 &r
->out
.validation
.sam3
);
1168 TALLOC_FREE(validation
);
1169 if (!NT_STATUS_IS_OK(status
)) {
1172 return NT_STATUS_OK
;
1174 status
= map_validation_to_info6(p
->mem_ctx
,
1177 &r
->out
.validation
.sam6
);
1178 TALLOC_FREE(validation
);
1179 if (!NT_STATUS_IS_OK(status
)) {
1182 return NT_STATUS_OK
;
1185 smb_panic(__location__
);
1186 return NT_STATUS_INTERNAL_ERROR
;
1189 static WERROR
_winbind_LogonControl_REDISCOVER(struct pipes_struct
*p
,
1190 struct winbindd_domain
*domain
,
1191 struct winbind_LogonControl
*r
)
1194 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1195 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1196 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1197 WERROR check_result
= WERR_INTERNAL_ERROR
;
1199 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1200 if (info2
== NULL
) {
1201 return WERR_NOT_ENOUGH_MEMORY
;
1204 if (domain
->internal
) {
1205 check_result
= WERR_OK
;
1210 * For now we just force a reconnect
1212 * TODO: take care of the optional '\dcname'
1214 invalidate_cm_connection(domain
);
1215 domain
->conn
.netlogon_force_reauth
= true;
1216 status
= cm_connect_netlogon_secure(domain
,
1218 &netlogon_creds_ctx
);
1219 reset_cm_connection_on_error(domain
, NULL
, status
);
1220 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1221 status
= NT_STATUS_NO_LOGON_SERVERS
;
1223 if (!NT_STATUS_IS_OK(status
)) {
1224 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1225 __func__
, domain
->name
, domain
->alt_name
,
1226 nt_errstr(status
)));
1228 * Here we return a top level error!
1229 * This is different than TC_QUERY or TC_VERIFY.
1231 return ntstatus_to_werror(status
);
1233 check_result
= WERR_OK
;
1236 info2
->pdc_connection_status
= WERR_OK
;
1237 if (domain
->dcname
!= NULL
) {
1238 info2
->flags
|= NETLOGON_HAS_IP
;
1239 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1240 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1242 if (info2
->trusted_dc_name
== NULL
) {
1243 return WERR_NOT_ENOUGH_MEMORY
;
1246 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1247 if (info2
->trusted_dc_name
== NULL
) {
1248 return WERR_NOT_ENOUGH_MEMORY
;
1251 info2
->tc_connection_status
= check_result
;
1253 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
) ||
1254 !W_ERROR_IS_OK(info2
->tc_connection_status
))
1256 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1257 "pdc_connection[%s] tc_connection[%s]\n",
1258 __func__
, domain
->name
, domain
->alt_name
,
1260 win_errstr(info2
->pdc_connection_status
),
1261 win_errstr(info2
->tc_connection_status
)));
1264 r
->out
.query
->info2
= info2
;
1266 DEBUG(5, ("%s: succeeded.\n", __func__
));
1270 static WERROR
_winbind_LogonControl_TC_QUERY(struct pipes_struct
*p
,
1271 struct winbindd_domain
*domain
,
1272 struct winbind_LogonControl
*r
)
1275 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1276 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1277 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1278 WERROR check_result
= WERR_INTERNAL_ERROR
;
1280 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1281 if (info2
== NULL
) {
1282 return WERR_NOT_ENOUGH_MEMORY
;
1285 if (domain
->internal
) {
1286 check_result
= WERR_OK
;
1290 status
= cm_connect_netlogon_secure(domain
,
1292 &netlogon_creds_ctx
);
1293 reset_cm_connection_on_error(domain
, NULL
, status
);
1294 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1295 status
= NT_STATUS_NO_LOGON_SERVERS
;
1297 if (!NT_STATUS_IS_OK(status
)) {
1298 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1299 nt_errstr(status
)));
1300 check_result
= ntstatus_to_werror(status
);
1303 check_result
= WERR_OK
;
1306 info2
->pdc_connection_status
= WERR_OK
;
1307 if (domain
->dcname
!= NULL
) {
1308 info2
->flags
|= NETLOGON_HAS_IP
;
1309 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1310 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1312 if (info2
->trusted_dc_name
== NULL
) {
1313 return WERR_NOT_ENOUGH_MEMORY
;
1316 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1317 if (info2
->trusted_dc_name
== NULL
) {
1318 return WERR_NOT_ENOUGH_MEMORY
;
1321 info2
->tc_connection_status
= check_result
;
1323 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
) ||
1324 !W_ERROR_IS_OK(info2
->tc_connection_status
))
1326 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1327 "pdc_connection[%s] tc_connection[%s]\n",
1328 __func__
, domain
->name
, domain
->alt_name
,
1330 win_errstr(info2
->pdc_connection_status
),
1331 win_errstr(info2
->tc_connection_status
)));
1334 r
->out
.query
->info2
= info2
;
1336 DEBUG(5, ("%s: succeeded.\n", __func__
));
1340 static WERROR
_winbind_LogonControl_TC_VERIFY(struct pipes_struct
*p
,
1341 struct winbindd_domain
*domain
,
1342 struct winbind_LogonControl
*r
)
1344 TALLOC_CTX
*frame
= talloc_stackframe();
1347 struct lsa_String trusted_domain_name
= {};
1348 struct lsa_StringLarge trusted_domain_name_l
= {};
1349 struct rpc_pipe_client
*local_lsa_pipe
= NULL
;
1350 struct policy_handle local_lsa_policy
= {};
1351 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1352 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1353 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1354 struct cli_credentials
*creds
= NULL
;
1355 struct samr_Password
*cur_nt_hash
= NULL
;
1356 uint32_t trust_attributes
= 0;
1357 struct samr_Password new_owf_password
= {};
1358 bool cmp_new
= false;
1359 struct samr_Password old_owf_password
= {};
1360 bool cmp_old
= false;
1361 const struct lsa_TrustDomainInfoInfoEx
*local_tdo
= NULL
;
1362 bool fetch_fti
= false;
1363 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1364 struct netr_TrustInfo
*trust_info
= NULL
;
1365 struct netr_NETLOGON_INFO_2
*info2
= NULL
;
1366 struct dcerpc_binding_handle
*b
= NULL
;
1367 WERROR check_result
= WERR_INTERNAL_ERROR
;
1368 WERROR verify_result
= WERR_INTERNAL_ERROR
;
1371 trusted_domain_name
.string
= domain
->name
;
1372 trusted_domain_name_l
.string
= domain
->name
;
1374 info2
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_2
);
1375 if (info2
== NULL
) {
1377 return WERR_NOT_ENOUGH_MEMORY
;
1380 if (domain
->internal
) {
1381 check_result
= WERR_OK
;
1385 if (!domain
->primary
) {
1386 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1388 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1390 if (!NT_STATUS_IS_OK(status
)) {
1391 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1392 __location__
, __func__
, nt_errstr(status
)));
1394 return WERR_INTERNAL_ERROR
;
1396 local_lsa
= local_lsa_pipe
->binding_handle
;
1398 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1400 &trusted_domain_name
,
1401 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1403 if (!NT_STATUS_IS_OK(status
)) {
1404 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1405 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1407 return WERR_INTERNAL_ERROR
;
1409 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1410 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1411 __location__
, __func__
, domain
->name
));
1413 return WERR_NO_SUCH_DOMAIN
;
1415 if (!NT_STATUS_IS_OK(result
)) {
1416 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1417 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1419 return WERR_INTERNAL_ERROR
;
1422 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1423 "returned no trusted domain information\n",
1424 __location__
, __func__
));
1426 return WERR_INTERNAL_ERROR
;
1429 local_tdo
= &tdi
->info_ex
;
1430 trust_attributes
= local_tdo
->trust_attributes
;
1433 if (trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1434 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1436 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1438 &trusted_domain_name
,
1439 LSA_FOREST_TRUST_DOMAIN_INFO
,
1441 if (!NT_STATUS_IS_OK(status
)) {
1442 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1443 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1445 return WERR_INTERNAL_ERROR
;
1447 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1448 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1449 __func__
, domain
->name
));
1452 result
= NT_STATUS_OK
;
1454 if (!NT_STATUS_IS_OK(result
)) {
1455 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1456 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1458 return WERR_INTERNAL_ERROR
;
1461 TALLOC_FREE(old_fti
);
1465 status
= cm_connect_netlogon_secure(domain
,
1467 &netlogon_creds_ctx
);
1468 reset_cm_connection_on_error(domain
, NULL
, status
);
1469 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1470 status
= NT_STATUS_NO_LOGON_SERVERS
;
1472 if (!NT_STATUS_IS_OK(status
)) {
1473 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1474 nt_errstr(status
)));
1475 check_result
= ntstatus_to_werror(status
);
1478 check_result
= WERR_OK
;
1479 b
= netlogon_pipe
->binding_handle
;
1481 status
= winbindd_get_trust_credentials(domain
,
1483 true, /* netlogon */
1484 false, /* ipc_fallback */
1486 if (NT_STATUS_IS_OK(status
)) {
1487 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, frame
);
1490 if (cur_nt_hash
== NULL
) {
1491 verify_result
= WERR_NO_TRUST_LSA_SECRET
;
1496 status
= netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx
,
1499 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1500 status
= NT_STATUS_NOT_SUPPORTED
;
1502 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1504 status
= NT_STATUS_OK
;
1506 if (!NT_STATUS_IS_OK(status
)) {
1508 reset_cm_connection_on_error(domain
, b
, status
))
1513 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s)"
1515 domain
->name
, nt_errstr(status
)));
1516 check_result
= ntstatus_to_werror(status
);
1521 if (new_fti
!= NULL
) {
1522 struct lsa_ForestTrustInformation old_fti
= {};
1523 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1524 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1526 status
= dsdb_trust_merge_forest_info(frame
, local_tdo
,
1529 if (!NT_STATUS_IS_OK(status
)) {
1530 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1531 __location__
, __func__
,
1532 domain
->name
, nt_errstr(status
)));
1534 return ntstatus_to_werror(status
);
1537 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1539 &trusted_domain_name_l
,
1540 LSA_FOREST_TRUST_DOMAIN_INFO
,
1542 0, /* check_only=0 => store it! */
1545 if (!NT_STATUS_IS_OK(status
)) {
1546 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1547 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1549 return WERR_INTERNAL_ERROR
;
1551 if (!NT_STATUS_IS_OK(result
)) {
1552 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
1553 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1555 return ntstatus_to_werror(result
);
1559 status
= netlogon_creds_cli_ServerGetTrustInfo(netlogon_creds_ctx
,
1564 if (NT_STATUS_EQUAL(status
, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE
)) {
1565 status
= NT_STATUS_NOT_SUPPORTED
;
1567 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_SUPPORTED
)) {
1568 DEBUG(5, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1569 nt_errstr(status
)));
1570 verify_result
= WERR_OK
;
1573 if (!NT_STATUS_IS_OK(status
)) {
1574 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1578 DEBUG(2, ("netlogon_creds_cli_ServerGetTrustInfo failed: %s\n",
1579 nt_errstr(status
)));
1581 if (!dcerpc_binding_handle_is_connected(b
)) {
1582 check_result
= ntstatus_to_werror(status
);
1585 verify_result
= ntstatus_to_werror(status
);
1590 if (trust_info
!= NULL
&& trust_info
->count
>= 1) {
1591 uint32_t diff
= trust_info
->data
[0] ^ trust_attributes
;
1593 if (diff
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
) {
1594 verify_result
= WERR_DOMAIN_TRUST_INCONSISTENT
;
1599 cmp_new
= mem_equal_const_time(new_owf_password
.hash
,
1601 sizeof(cur_nt_hash
->hash
));
1602 cmp_old
= mem_equal_const_time(old_owf_password
.hash
,
1604 sizeof(cur_nt_hash
->hash
));
1605 if (!cmp_new
&& !cmp_old
) {
1606 DEBUG(1,("%s:Error: credentials for domain[%s/%s] doesn't match "
1607 "any password known to dcname[%s]\n",
1608 __func__
, domain
->name
, domain
->alt_name
,
1610 verify_result
= WERR_WRONG_PASSWORD
;
1615 DEBUG(2,("%s:Warning: credentials for domain[%s/%s] only match "
1616 "against the old password known to dcname[%s]\n",
1617 __func__
, domain
->name
, domain
->alt_name
,
1621 verify_result
= WERR_OK
;
1625 verify_result
= check_result
;
1627 info2
->flags
|= NETLOGON_VERIFY_STATUS_RETURNED
;
1628 info2
->pdc_connection_status
= verify_result
;
1629 if (domain
->dcname
!= NULL
) {
1630 info2
->flags
|= NETLOGON_HAS_IP
;
1631 info2
->flags
|= NETLOGON_HAS_TIMESERV
;
1632 info2
->trusted_dc_name
= talloc_asprintf(info2
, "\\\\%s",
1634 if (info2
->trusted_dc_name
== NULL
) {
1636 return WERR_NOT_ENOUGH_MEMORY
;
1639 info2
->trusted_dc_name
= talloc_strdup(info2
, "");
1640 if (info2
->trusted_dc_name
== NULL
) {
1642 return WERR_NOT_ENOUGH_MEMORY
;
1645 info2
->tc_connection_status
= check_result
;
1647 if (!W_ERROR_IS_OK(info2
->pdc_connection_status
) ||
1648 !W_ERROR_IS_OK(info2
->tc_connection_status
))
1650 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1651 "pdc_connection[%s] tc_connection[%s]\n",
1652 __func__
, domain
->name
, domain
->alt_name
,
1654 win_errstr(info2
->pdc_connection_status
),
1655 win_errstr(info2
->tc_connection_status
)));
1658 r
->out
.query
->info2
= info2
;
1660 DEBUG(5, ("%s: succeeded.\n", __func__
));
1665 static WERROR
_winbind_LogonControl_CHANGE_PASSWORD(struct pipes_struct
*p
,
1666 struct winbindd_domain
*domain
,
1667 struct winbind_LogonControl
*r
)
1669 struct messaging_context
*msg_ctx
= global_messaging_context();
1671 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1672 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1673 struct cli_credentials
*creds
= NULL
;
1674 struct samr_Password
*cur_nt_hash
= NULL
;
1675 struct netr_NETLOGON_INFO_1
*info1
= NULL
;
1676 struct dcerpc_binding_handle
*b
;
1677 WERROR change_result
= WERR_OK
;
1680 info1
= talloc_zero(p
->mem_ctx
, struct netr_NETLOGON_INFO_1
);
1681 if (info1
== NULL
) {
1682 return WERR_NOT_ENOUGH_MEMORY
;
1685 if (domain
->internal
) {
1686 return WERR_NOT_SUPPORTED
;
1689 status
= pdb_get_trust_credentials(domain
->name
,
1693 if (NT_STATUS_IS_OK(status
)) {
1694 cur_nt_hash
= cli_credentials_get_nt_hash(creds
, p
->mem_ctx
);
1699 status
= cm_connect_netlogon_secure(domain
,
1701 &netlogon_creds_ctx
);
1702 reset_cm_connection_on_error(domain
, NULL
, status
);
1703 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1704 status
= NT_STATUS_NO_LOGON_SERVERS
;
1706 if (!NT_STATUS_IS_OK(status
)) {
1707 DEBUG(2, ("%s: domain[%s/%s] cm_connect_netlogon() returned %s\n",
1708 __func__
, domain
->name
, domain
->alt_name
,
1709 nt_errstr(status
)));
1711 * Here we return a top level error!
1712 * This is different than TC_QUERY or TC_VERIFY.
1714 return ntstatus_to_werror(status
);
1716 b
= netlogon_pipe
->binding_handle
;
1718 if (cur_nt_hash
== NULL
) {
1719 change_result
= WERR_NO_TRUST_LSA_SECRET
;
1722 TALLOC_FREE(cur_nt_hash
);
1724 status
= trust_pw_change(netlogon_creds_ctx
,
1725 msg_ctx
, b
, domain
->name
,
1728 if (!NT_STATUS_IS_OK(status
)) {
1729 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1734 DEBUG(1, ("trust_pw_change(%s): %s\n",
1735 domain
->name
, nt_errstr(status
)));
1737 change_result
= ntstatus_to_werror(status
);
1741 change_result
= WERR_OK
;
1744 info1
->pdc_connection_status
= change_result
;
1746 if (!W_ERROR_IS_OK(info1
->pdc_connection_status
)) {
1747 DEBUG(2, ("%s: domain[%s/%s] dcname[%s] "
1748 "pdc_connection[%s]\n",
1749 __func__
, domain
->name
, domain
->alt_name
,
1751 win_errstr(info1
->pdc_connection_status
)));
1754 r
->out
.query
->info1
= info1
;
1756 DEBUG(5, ("%s: succeeded.\n", __func__
));
1760 WERROR
_winbind_LogonControl(struct pipes_struct
*p
,
1761 struct winbind_LogonControl
*r
)
1763 struct winbindd_domain
*domain
;
1765 domain
= wb_child_domain();
1766 if (domain
== NULL
) {
1767 return WERR_NO_SUCH_DOMAIN
;
1770 switch (r
->in
.function_code
) {
1771 case NETLOGON_CONTROL_REDISCOVER
:
1772 if (r
->in
.level
!= 2) {
1773 return WERR_INVALID_PARAMETER
;
1775 return _winbind_LogonControl_REDISCOVER(p
, domain
, r
);
1776 case NETLOGON_CONTROL_TC_QUERY
:
1777 if (r
->in
.level
!= 2) {
1778 return WERR_INVALID_PARAMETER
;
1780 return _winbind_LogonControl_TC_QUERY(p
, domain
, r
);
1781 case NETLOGON_CONTROL_TC_VERIFY
:
1782 if (r
->in
.level
!= 2) {
1783 return WERR_INVALID_PARAMETER
;
1785 return _winbind_LogonControl_TC_VERIFY(p
, domain
, r
);
1786 case NETLOGON_CONTROL_CHANGE_PASSWORD
:
1787 if (r
->in
.level
!= 1) {
1788 return WERR_INVALID_PARAMETER
;
1790 return _winbind_LogonControl_CHANGE_PASSWORD(p
, domain
, r
);
1795 DEBUG(4, ("%s: function_code[0x%x] not supported\n",
1796 __func__
, r
->in
.function_code
));
1797 return WERR_NOT_SUPPORTED
;
1800 WERROR
_winbind_GetForestTrustInformation(struct pipes_struct
*p
,
1801 struct winbind_GetForestTrustInformation
*r
)
1803 TALLOC_CTX
*frame
= talloc_stackframe();
1804 NTSTATUS status
, result
;
1805 struct winbindd_domain
*domain
;
1806 struct rpc_pipe_client
*netlogon_pipe
= NULL
;
1807 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
1808 struct dcerpc_binding_handle
*b
;
1810 struct lsa_String trusted_domain_name
= {};
1811 struct lsa_StringLarge trusted_domain_name_l
= {};
1812 union lsa_TrustedDomainInfo
*tdi
= NULL
;
1813 const struct lsa_TrustDomainInfoInfoEx
*tdo
= NULL
;
1814 struct lsa_ForestTrustInformation _old_fti
= {};
1815 struct lsa_ForestTrustInformation
*old_fti
= NULL
;
1816 struct lsa_ForestTrustInformation
*new_fti
= NULL
;
1817 struct lsa_ForestTrustInformation
*merged_fti
= NULL
;
1818 struct lsa_ForestTrustCollisionInfo
*collision_info
= NULL
;
1819 bool update_fti
= false;
1820 struct rpc_pipe_client
*local_lsa_pipe
;
1821 struct policy_handle local_lsa_policy
;
1822 struct dcerpc_binding_handle
*local_lsa
= NULL
;
1824 domain
= wb_child_domain();
1825 if (domain
== NULL
) {
1827 return WERR_NO_SUCH_DOMAIN
;
1831 * checking for domain->internal and domain->primary
1832 * makes sure we only do some work when running as DC.
1835 if (domain
->internal
) {
1837 return WERR_NO_SUCH_DOMAIN
;
1840 if (domain
->primary
) {
1842 return WERR_NO_SUCH_DOMAIN
;
1845 trusted_domain_name
.string
= domain
->name
;
1846 trusted_domain_name_l
.string
= domain
->name
;
1848 status
= open_internal_lsa_conn(frame
, &local_lsa_pipe
,
1850 if (!NT_STATUS_IS_OK(status
)) {
1851 DEBUG(0,("%s:%s: open_internal_lsa_conn() failed - %s\n",
1852 __location__
, __func__
, nt_errstr(status
)));
1854 return WERR_INTERNAL_ERROR
;
1856 local_lsa
= local_lsa_pipe
->binding_handle
;
1858 status
= dcerpc_lsa_QueryTrustedDomainInfoByName(local_lsa
, frame
,
1860 &trusted_domain_name
,
1861 LSA_TRUSTED_DOMAIN_INFO_INFO_EX
,
1863 if (!NT_STATUS_IS_OK(status
)) {
1864 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) failed - %s\n",
1865 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1867 return WERR_INTERNAL_ERROR
;
1869 if (NT_STATUS_EQUAL(result
, NT_STATUS_OBJECT_NAME_NOT_FOUND
)) {
1870 DEBUG(1,("%s:%s: domain[%s] not found via LSA, might be removed already.\n",
1871 __location__
, __func__
, domain
->name
));
1873 return WERR_NO_SUCH_DOMAIN
;
1875 if (!NT_STATUS_IS_OK(result
)) {
1876 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName(%s) returned %s\n",
1877 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1879 return WERR_INTERNAL_ERROR
;
1882 DEBUG(0,("%s:%s: local_lsa.QueryTrustedDomainInfoByName() "
1883 "returned no trusted domain information\n",
1884 __location__
, __func__
));
1886 return WERR_INTERNAL_ERROR
;
1889 tdo
= &tdi
->info_ex
;
1891 if (!(tdo
->trust_attributes
& LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE
)) {
1892 DEBUG(2,("%s: tdo[%s/%s] is no forest trust attributes[0x%08X]\n",
1893 __func__
, tdo
->netbios_name
.string
,
1894 tdo
->domain_name
.string
,
1895 (unsigned)tdo
->trust_attributes
));
1897 return WERR_NO_SUCH_DOMAIN
;
1900 if (r
->in
.flags
& ~DS_GFTI_UPDATE_TDO
) {
1902 return WERR_INVALID_FLAGS
;
1906 status
= cm_connect_netlogon_secure(domain
,
1908 &netlogon_creds_ctx
);
1909 reset_cm_connection_on_error(domain
, NULL
, status
);
1910 if (NT_STATUS_EQUAL(status
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1911 status
= NT_STATUS_NO_LOGON_SERVERS
;
1913 if (!NT_STATUS_IS_OK(status
)) {
1914 DEBUG(3, ("could not open handle to NETLOGON pipe: %s\n",
1915 nt_errstr(status
)));
1917 return ntstatus_to_werror(status
);
1919 b
= netlogon_pipe
->binding_handle
;
1921 status
= netlogon_creds_cli_GetForestTrustInformation(netlogon_creds_ctx
,
1924 if (!NT_STATUS_IS_OK(status
)) {
1925 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
1929 DEBUG(2, ("netlogon_creds_cli_GetForestTrustInformation(%s) failed: %s\n",
1930 domain
->name
, nt_errstr(status
)));
1932 return ntstatus_to_werror(status
);
1935 *r
->out
.forest_trust_info
= new_fti
;
1937 if (r
->in
.flags
& DS_GFTI_UPDATE_TDO
) {
1941 status
= dcerpc_lsa_lsaRQueryForestTrustInformation(local_lsa
, frame
,
1943 &trusted_domain_name
,
1944 LSA_FOREST_TRUST_DOMAIN_INFO
,
1946 if (!NT_STATUS_IS_OK(status
)) {
1947 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) failed %s\n",
1948 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1950 return WERR_INTERNAL_ERROR
;
1952 if (NT_STATUS_EQUAL(result
, NT_STATUS_NOT_FOUND
)) {
1953 DEBUG(2,("%s: no forest trust information available for domain[%s] yet.\n",
1954 __func__
, domain
->name
));
1956 old_fti
= &_old_fti
;
1957 result
= NT_STATUS_OK
;
1959 if (!NT_STATUS_IS_OK(result
)) {
1960 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation(%s) returned %s\n",
1961 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
1963 return WERR_INTERNAL_ERROR
;
1966 if (old_fti
== NULL
) {
1967 DEBUG(0,("%s:%s: local_lsa.lsaRQueryForestTrustInformation() "
1968 "returned success without returning forest trust information\n",
1969 __location__
, __func__
));
1971 return WERR_INTERNAL_ERROR
;
1978 status
= dsdb_trust_merge_forest_info(frame
, tdo
, old_fti
, new_fti
,
1980 if (!NT_STATUS_IS_OK(status
)) {
1981 DEBUG(0,("%s:%s: dsdb_trust_merge_forest_info(%s) failed %s\n",
1982 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1984 return ntstatus_to_werror(status
);
1987 status
= dcerpc_lsa_lsaRSetForestTrustInformation(local_lsa
, frame
,
1989 &trusted_domain_name_l
,
1990 LSA_FOREST_TRUST_DOMAIN_INFO
,
1992 0, /* check_only=0 => store it! */
1995 if (!NT_STATUS_IS_OK(status
)) {
1996 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) failed %s\n",
1997 __location__
, __func__
, domain
->name
, nt_errstr(status
)));
1999 return WERR_INTERNAL_ERROR
;
2001 if (!NT_STATUS_IS_OK(result
)) {
2002 DEBUG(0,("%s:%s: local_lsa.lsaRSetForestTrustInformation(%s) returned %s\n",
2003 __location__
, __func__
, domain
->name
, nt_errstr(result
)));
2005 return ntstatus_to_werror(result
);
2009 DEBUG(5, ("_winbind_GetForestTrustInformation succeeded\n"));
2014 NTSTATUS
_winbind_SendToSam(struct pipes_struct
*p
, struct winbind_SendToSam
*r
)
2016 struct winbindd_domain
*domain
;
2018 struct rpc_pipe_client
*netlogon_pipe
;
2019 struct netlogon_creds_cli_context
*netlogon_creds_ctx
= NULL
;
2020 struct dcerpc_binding_handle
*b
= NULL
;
2023 DEBUG(5, ("_winbind_SendToSam received\n"));
2024 domain
= wb_child_domain();
2025 if (domain
== NULL
) {
2026 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2030 status
= cm_connect_netlogon_secure(domain
,
2032 &netlogon_creds_ctx
);
2033 reset_cm_connection_on_error(domain
, NULL
, status
);
2034 if (!NT_STATUS_IS_OK(status
)) {
2035 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
2039 b
= netlogon_pipe
->binding_handle
;
2041 status
= netlogon_creds_cli_SendToSam(netlogon_creds_ctx
,
2044 if (!retry
&& reset_cm_connection_on_error(domain
, b
, status
)) {
2052 NTSTATUS
_wbint_ListTrustedDomains(struct pipes_struct
*p
,
2053 struct wbint_ListTrustedDomains
*r
)
2055 struct winbindd_domain
*domain
= wb_child_domain();
2058 struct netr_DomainTrustList trusts
;
2060 struct netr_DomainTrust
*array
= NULL
;
2063 if (domain
== NULL
) {
2064 return NT_STATUS_REQUEST_NOT_ACCEPTED
;
2067 /* Cut client_pid to 32bit */
2068 client_pid
= r
->in
.client_pid
;
2069 if ((uint64_t)client_pid
!= r
->in
.client_pid
) {
2070 DBG_DEBUG("pid out of range\n");
2071 return NT_STATUS_INVALID_PARAMETER
;
2074 DBG_NOTICE("[%s %"PRIu32
"]: list trusted domains\n",
2075 r
->in
.client_name
, client_pid
);
2077 result
= wb_cache_trusted_domains(domain
, p
->mem_ctx
, &trusts
);
2078 if (!NT_STATUS_IS_OK(result
)) {
2079 DBG_NOTICE("wb_cache_trusted_domains returned %s\n",
2084 for (i
=0; i
<trusts
.count
; i
++) {
2085 struct netr_DomainTrust
*st
= &trusts
.array
[i
];
2086 struct netr_DomainTrust
*dt
= NULL
;
2088 if (st
->sid
== NULL
) {
2091 if (dom_sid_equal(st
->sid
, &global_sid_NULL
)) {
2095 array
= talloc_realloc(r
->out
.domains
, array
,
2096 struct netr_DomainTrust
,
2098 if (array
== NULL
) {
2099 return NT_STATUS_NO_MEMORY
;
2104 *dt
= (struct netr_DomainTrust
) {
2105 .trust_flags
= st
->trust_flags
,
2106 .trust_type
= st
->trust_type
,
2107 .trust_attributes
= st
->trust_attributes
,
2108 .netbios_name
= talloc_move(array
, &st
->netbios_name
),
2109 .dns_name
= talloc_move(array
, &st
->dns_name
),
2112 dt
->sid
= dom_sid_dup(array
, st
->sid
);
2113 if (dt
->sid
== NULL
) {
2114 return NT_STATUS_NO_MEMORY
;
2120 r
->out
.domains
->array
= array
;
2121 r
->out
.domains
->count
= count
;
2122 return NT_STATUS_OK
;
2125 #include "librpc/gen_ndr/ndr_winbind_scompat.c"