2 Unix SMB/CIFS implementation.
4 Copyright (C) Volker Lendecke 2011
5 Copyright (C) Michael Adam 2012
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "../libcli/security/security.h"
24 #include "idmap_cache.h"
25 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
29 struct wb_sids2xids_state
{
30 struct tevent_context
*ev
;
35 struct id_map
*cached
;
37 struct dom_sid
*non_cached
;
38 uint32_t num_non_cached
;
41 * Domain array to use for the idmap call. The output from
42 * lookupsids cannot be used directly since for migrated
43 * objects the returned domain SID can be different than the
44 * original one. The new domain SID cannot be combined with
45 * the RID from the previous domain.
47 * The proper way would be asking for the correct RID in the
48 * new domain, but this approach avoids id mappings for
51 struct lsa_RefDomainList idmap_doms
;
54 struct wbint_TransIDArray
*dom_ids
;
55 struct lsa_RefDomainList idmap_dom
;
58 struct wbint_TransIDArray ids
;
62 static bool wb_sids2xids_in_cache(struct dom_sid
*sid
, struct id_map
*map
);
63 static void wb_sids2xids_lookupsids_done(struct tevent_req
*subreq
);
64 static void wb_sids2xids_done(struct tevent_req
*subreq
);
65 static void wb_sids2xids_gotdc(struct tevent_req
*subreq
);
67 struct tevent_req
*wb_sids2xids_send(TALLOC_CTX
*mem_ctx
,
68 struct tevent_context
*ev
,
69 const struct dom_sid
*sids
,
70 const uint32_t num_sids
)
72 struct tevent_req
*req
, *subreq
;
73 struct wb_sids2xids_state
*state
;
76 req
= tevent_req_create(mem_ctx
, &state
,
77 struct wb_sids2xids_state
);
84 state
->num_sids
= num_sids
;
86 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_sids
);
87 if (tevent_req_nomem(state
->sids
, req
)) {
88 return tevent_req_post(req
, ev
);
91 for (i
= 0; i
< num_sids
; i
++) {
92 sid_copy(&state
->sids
[i
], &sids
[i
]);
95 state
->cached
= talloc_zero_array(state
, struct id_map
, num_sids
);
96 if (tevent_req_nomem(state
->cached
, req
)) {
97 return tevent_req_post(req
, ev
);
100 state
->non_cached
= talloc_array(state
, struct dom_sid
, num_sids
);
101 if (tevent_req_nomem(state
->non_cached
, req
)) {
102 return tevent_req_post(req
, ev
);
106 * Extract those sids that can not be resolved from cache
107 * into a separate list to be handed to id mapping, keeping
110 for (i
=0; i
<state
->num_sids
; i
++) {
111 struct dom_sid_buf buf
;
113 DEBUG(10, ("SID %d: %s\n", (int)i
,
114 dom_sid_str_buf(&state
->sids
[i
], &buf
)));
116 if (wb_sids2xids_in_cache(&state
->sids
[i
], &state
->cached
[i
])) {
119 sid_copy(&state
->non_cached
[state
->num_non_cached
],
121 state
->num_non_cached
+= 1;
124 if (state
->num_non_cached
== 0) {
125 tevent_req_done(req
);
126 return tevent_req_post(req
, ev
);
129 subreq
= wb_lookupsids_send(state
, ev
, state
->non_cached
,
130 state
->num_non_cached
);
131 if (tevent_req_nomem(subreq
, req
)) {
132 return tevent_req_post(req
, ev
);
134 tevent_req_set_callback(subreq
, wb_sids2xids_lookupsids_done
, req
);
138 static bool wb_sids2xids_in_cache(struct dom_sid
*sid
, struct id_map
*map
)
143 if (!winbindd_use_idmap_cache()) {
146 if (idmap_cache_find_sid2unixid(sid
, &id
, &expired
)) {
147 if (expired
&& is_domain_online(find_our_domain())) {
152 map
->status
= ID_MAPPED
;
158 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
);
159 static struct wbint_TransIDArray
*wb_sids2xids_extract_for_domain_index(
160 TALLOC_CTX
*mem_ctx
, const struct wbint_TransIDArray
*src
,
161 uint32_t domain_index
);
163 static void wb_sids2xids_lookupsids_done(struct tevent_req
*subreq
)
165 struct tevent_req
*req
= tevent_req_callback_data(
166 subreq
, struct tevent_req
);
167 struct wb_sids2xids_state
*state
= tevent_req_data(
168 req
, struct wb_sids2xids_state
);
169 struct lsa_RefDomainList
*domains
= NULL
;
170 struct lsa_TransNameArray
*names
= NULL
;
171 struct dcerpc_binding_handle
*child_binding_handle
= NULL
;
175 status
= wb_lookupsids_recv(subreq
, state
, &domains
, &names
);
177 if (tevent_req_nterror(req
, status
)) {
181 state
->ids
.num_ids
= state
->num_non_cached
;
182 state
->ids
.ids
= talloc_array(state
, struct wbint_TransID
,
183 state
->num_non_cached
);
184 if (tevent_req_nomem(state
->ids
.ids
, req
)) {
188 for (i
=0; i
<state
->num_non_cached
; i
++) {
189 const struct dom_sid
*sid
= &state
->non_cached
[i
];
190 struct dom_sid dom_sid
;
191 struct lsa_TranslatedName
*n
= &names
->names
[i
];
192 struct wbint_TransID
*t
= &state
->ids
.ids
[i
];
194 const char *domain_name
= NULL
;
196 if (n
->sid_index
!= UINT32_MAX
) {
197 const struct lsa_DomainInfo
*info
;
200 info
= &domains
->domains
[n
->sid_index
];
201 match
= dom_sid_in_domain(info
->sid
, sid
);
203 domain_name
= info
->name
.string
;
206 if (domain_name
== NULL
) {
207 struct winbindd_domain
*wb_domain
= NULL
;
210 * This is needed to handle Samba DCs
211 * which always return sid_index == UINT32_MAX for
214 wb_domain
= find_domain_from_sid_noinit(sid
);
215 if (wb_domain
!= NULL
) {
216 domain_name
= wb_domain
->name
;
219 if (domain_name
== NULL
) {
223 sid_copy(&dom_sid
, sid
);
224 sid_split_rid(&dom_sid
, &t
->rid
);
225 t
->type
= lsa_SidType_to_id_type(n
->sid_type
);
226 domain_index
= init_lsa_ref_domain_list(
227 state
, &state
->idmap_doms
, domain_name
, &dom_sid
);
228 if (domain_index
== -1) {
232 t
->domain_index
= domain_index
;
234 t
->xid
.id
= UINT32_MAX
;
235 t
->xid
.type
= t
->type
;
239 TALLOC_FREE(domains
);
241 child_binding_handle
= idmap_child_handle();
243 state
->dom_ids
= wb_sids2xids_extract_for_domain_index(
244 state
, &state
->ids
, state
->dom_index
);
245 if (tevent_req_nomem(state
->dom_ids
, req
)) {
249 state
->idmap_dom
= (struct lsa_RefDomainList
) {
251 .domains
= &state
->idmap_doms
.domains
[state
->dom_index
],
255 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
256 state
, state
->ev
, child_binding_handle
, &state
->idmap_dom
,
258 if (tevent_req_nomem(subreq
, req
)) {
261 tevent_req_set_callback(subreq
, wb_sids2xids_done
, req
);
264 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
)
269 case SID_NAME_COMPUTER
:
273 case SID_NAME_DOM_GRP
:
275 case SID_NAME_WKN_GRP
:
279 type
= ID_TYPE_NOT_SPECIFIED
;
286 static void wb_sids2xids_done(struct tevent_req
*subreq
)
288 struct tevent_req
*req
= tevent_req_callback_data(
289 subreq
, struct tevent_req
);
290 struct wb_sids2xids_state
*state
= tevent_req_data(
291 req
, struct wb_sids2xids_state
);
292 NTSTATUS status
, result
;
293 struct winbindd_child
*child
;
295 struct wbint_TransIDArray
*src
, *dst
;
298 status
= dcerpc_wbint_Sids2UnixIDs_recv(subreq
, state
, &result
);
301 if (tevent_req_nterror(req
, status
)) {
305 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
306 !state
->tried_dclookup
) {
308 struct lsa_DomainInfo
*d
;
310 d
= &state
->idmap_doms
.domains
[state
->dom_index
];
312 subreq
= wb_dsgetdcname_send(
313 state
, state
->ev
, d
->name
.string
, NULL
, NULL
,
315 if (tevent_req_nomem(subreq
, req
)) {
318 tevent_req_set_callback(subreq
, wb_sids2xids_gotdc
, req
);
322 src
= state
->dom_ids
;
326 if (any_nt_status_not_ok(status
, result
, &status
)) {
327 DBG_DEBUG("status=%s, result=%s\n", nt_errstr(status
),
331 * All we can do here is to report "not mapped"
333 for (i
=0; i
<src
->num_ids
; i
++) {
334 src
->ids
[i
].xid
.type
= ID_TYPE_NOT_SPECIFIED
;
338 for (i
=0; i
<dst
->num_ids
; i
++) {
339 if (dst
->ids
[i
].domain_index
== state
->dom_index
) {
340 dst
->ids
[i
].type
= src
->ids
[src_idx
].type
;
341 dst
->ids
[i
].xid
= src
->ids
[src_idx
].xid
;
346 TALLOC_FREE(state
->dom_ids
);
348 state
->dom_index
+= 1;
349 state
->tried_dclookup
= false;
351 if (state
->dom_index
== state
->idmap_doms
.count
) {
352 tevent_req_done(req
);
356 child
= idmap_child();
358 state
->dom_ids
= wb_sids2xids_extract_for_domain_index(
359 state
, &state
->ids
, state
->dom_index
);
360 if (tevent_req_nomem(state
->dom_ids
, req
)) {
364 state
->idmap_dom
= (struct lsa_RefDomainList
) {
366 .domains
= &state
->idmap_doms
.domains
[state
->dom_index
],
370 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
371 state
, state
->ev
, child
->binding_handle
, &state
->idmap_dom
,
373 if (tevent_req_nomem(subreq
, req
)) {
376 tevent_req_set_callback(subreq
, wb_sids2xids_done
, req
);
379 static void wb_sids2xids_gotdc(struct tevent_req
*subreq
)
381 struct tevent_req
*req
= tevent_req_callback_data(
382 subreq
, struct tevent_req
);
383 struct wb_sids2xids_state
*state
= tevent_req_data(
384 req
, struct wb_sids2xids_state
);
385 struct winbindd_child
*child
= idmap_child();
386 struct netr_DsRGetDCNameInfo
*dcinfo
;
389 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
391 if (tevent_req_nterror(req
, status
)) {
395 state
->tried_dclookup
= true;
398 struct lsa_DomainInfo
*d
=
399 &state
->idmap_doms
.domains
[state
->dom_index
];
400 const char *dom_name
= d
->name
.string
;
402 status
= wb_dsgetdcname_gencache_set(dom_name
, dcinfo
);
403 if (tevent_req_nterror(req
, status
)) {
408 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
409 state
, state
->ev
, child
->binding_handle
, &state
->idmap_dom
,
411 if (tevent_req_nomem(subreq
, req
)) {
414 tevent_req_set_callback(subreq
, wb_sids2xids_done
, req
);
417 NTSTATUS
wb_sids2xids_recv(struct tevent_req
*req
,
418 struct unixid xids
[], uint32_t num_xids
)
420 struct wb_sids2xids_state
*state
= tevent_req_data(
421 req
, struct wb_sids2xids_state
);
423 uint32_t i
, num_non_cached
;
425 if (tevent_req_is_nterror(req
, &status
)) {
426 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
430 if (num_xids
!= state
->num_sids
) {
431 DEBUG(1, ("%s: Have %u xids, caller wants %u\n", __func__
,
432 (unsigned)state
->num_sids
, num_xids
));
433 return NT_STATUS_INTERNAL_ERROR
;
438 for (i
=0; i
<state
->num_sids
; i
++) {
443 if (state
->cached
[i
].sid
!= NULL
) {
444 xid
= state
->cached
[i
].xid
;
446 xid
= state
->ids
.ids
[num_non_cached
].xid
;
448 idmap_cache_set_sid2unixid(
449 &state
->non_cached
[num_non_cached
],
461 static struct wbint_TransIDArray
*wb_sids2xids_extract_for_domain_index(
462 TALLOC_CTX
*mem_ctx
, const struct wbint_TransIDArray
*src
,
463 uint32_t domain_index
)
465 struct wbint_TransIDArray
*ret
;
468 ret
= talloc_zero(mem_ctx
, struct wbint_TransIDArray
);
472 ret
->ids
= talloc_array(ret
, struct wbint_TransID
, src
->num_ids
);
473 if (ret
->ids
== NULL
) {
478 for (i
=0; i
<src
->num_ids
; i
++) {
479 if (src
->ids
[i
].domain_index
== domain_index
) {
480 ret
->ids
[ret
->num_ids
] = src
->ids
[i
];
481 ret
->ids
[ret
->num_ids
].domain_index
= 0;