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"
28 struct wb_sids2xids_state
{
29 struct tevent_context
*ev
;
34 struct id_map
*cached
;
36 struct dom_sid
*non_cached
;
37 uint32_t num_non_cached
;
40 * Domain array to use for the idmap call. The output from
41 * lookupsids cannot be used directly since for migrated
42 * objects the returned domain SID can be different that the
43 * original one. The new domain SID cannot be combined with
44 * the RID from the previous domain.
46 * The proper way would be asking for the correct RID in the
47 * new domain, but this approach avoids id mappings for
50 struct lsa_RefDomainList
*idmap_doms
;
52 struct wbint_TransIDArray ids
;
56 static bool wb_sids2xids_in_cache(struct dom_sid
*sid
, struct id_map
*map
);
57 static void wb_sids2xids_lookupsids_done(struct tevent_req
*subreq
);
58 static void wb_sids2xids_done(struct tevent_req
*subreq
);
60 struct tevent_req
*wb_sids2xids_send(TALLOC_CTX
*mem_ctx
,
61 struct tevent_context
*ev
,
62 const struct dom_sid
*sids
,
63 const uint32_t num_sids
)
65 struct tevent_req
*req
, *subreq
;
66 struct wb_sids2xids_state
*state
;
69 req
= tevent_req_create(mem_ctx
, &state
,
70 struct wb_sids2xids_state
);
77 state
->num_sids
= num_sids
;
79 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_sids
);
80 if (tevent_req_nomem(state
->sids
, req
)) {
81 return tevent_req_post(req
, ev
);
84 for (i
= 0; i
< num_sids
; i
++) {
85 sid_copy(&state
->sids
[i
], &sids
[i
]);
88 state
->cached
= talloc_zero_array(state
, struct id_map
, num_sids
);
89 if (tevent_req_nomem(state
->cached
, req
)) {
90 return tevent_req_post(req
, ev
);
93 state
->non_cached
= talloc_array(state
, struct dom_sid
, num_sids
);
94 if (tevent_req_nomem(state
->non_cached
, req
)) {
95 return tevent_req_post(req
, ev
);
99 * Extract those sids that can not be resolved from cache
100 * into a separate list to be handed to id mapping, keeping
103 for (i
=0; i
<state
->num_sids
; i
++) {
105 DEBUG(10, ("SID %d: %s\n", (int)i
,
106 sid_string_dbg(&state
->sids
[i
])));
108 if (wb_sids2xids_in_cache(&state
->sids
[i
], &state
->cached
[i
])) {
111 sid_copy(&state
->non_cached
[state
->num_non_cached
],
113 state
->num_non_cached
+= 1;
116 if (state
->num_non_cached
== 0) {
117 tevent_req_done(req
);
118 return tevent_req_post(req
, ev
);
121 subreq
= wb_lookupsids_send(state
, ev
, state
->non_cached
,
122 state
->num_non_cached
);
123 if (tevent_req_nomem(subreq
, req
)) {
124 return tevent_req_post(req
, ev
);
126 tevent_req_set_callback(subreq
, wb_sids2xids_lookupsids_done
, req
);
130 static bool wb_sids2xids_in_cache(struct dom_sid
*sid
, struct id_map
*map
)
135 if (!winbindd_use_idmap_cache()) {
138 if (idmap_cache_find_sid2unixid(sid
, &id
, &expired
)) {
139 if (expired
&& is_domain_online(find_our_domain())) {
144 map
->status
= ID_MAPPED
;
150 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
);
152 static void wb_sids2xids_lookupsids_done(struct tevent_req
*subreq
)
154 struct tevent_req
*req
= tevent_req_callback_data(
155 subreq
, struct tevent_req
);
156 struct wb_sids2xids_state
*state
= tevent_req_data(
157 req
, struct wb_sids2xids_state
);
158 struct lsa_RefDomainList
*domains
= NULL
;
159 struct lsa_TransNameArray
*names
= NULL
;
160 struct winbindd_child
*child
;
164 status
= wb_lookupsids_recv(subreq
, state
, &domains
, &names
);
166 if (tevent_req_nterror(req
, status
)) {
170 state
->ids
.num_ids
= state
->num_non_cached
;
171 state
->ids
.ids
= talloc_array(state
, struct wbint_TransID
,
172 state
->num_non_cached
);
173 if (tevent_req_nomem(state
->ids
.ids
, req
)) {
177 state
->idmap_doms
= talloc_zero(state
, struct lsa_RefDomainList
);
178 if (tevent_req_nomem(state
->idmap_doms
, req
)) {
182 for (i
=0; i
<state
->num_non_cached
; i
++) {
183 struct dom_sid dom_sid
;
184 struct lsa_DomainInfo
*info
;
185 struct lsa_TranslatedName
*n
= &names
->names
[i
];
186 struct wbint_TransID
*t
= &state
->ids
.ids
[i
];
189 sid_copy(&dom_sid
, &state
->non_cached
[i
]);
190 sid_split_rid(&dom_sid
, &t
->rid
);
192 info
= &domains
->domains
[n
->sid_index
];
193 t
->type
= lsa_SidType_to_id_type(n
->sid_type
);
195 domain_index
= init_lsa_ref_domain_list(
196 state
, state
->idmap_doms
, info
->name
.string
, &dom_sid
);
197 if (domain_index
== -1) {
201 t
->domain_index
= domain_index
;
203 t
->xid
.id
= UINT32_MAX
;
204 t
->xid
.type
= t
->type
;
208 TALLOC_FREE(domains
);
210 child
= idmap_child();
212 subreq
= dcerpc_wbint_Sids2UnixIDs_send(
213 state
, state
->ev
, child
->binding_handle
, state
->idmap_doms
,
215 if (tevent_req_nomem(subreq
, req
)) {
218 tevent_req_set_callback(subreq
, wb_sids2xids_done
, req
);
221 static enum id_type
lsa_SidType_to_id_type(const enum lsa_SidType sid_type
)
226 case SID_NAME_COMPUTER
:
230 case SID_NAME_DOM_GRP
:
232 case SID_NAME_WKN_GRP
:
236 type
= ID_TYPE_NOT_SPECIFIED
;
244 static void wb_sids2xids_done(struct tevent_req
*subreq
)
246 struct tevent_req
*req
= tevent_req_callback_data(
247 subreq
, struct tevent_req
);
248 struct wb_sids2xids_state
*state
= tevent_req_data(
249 req
, struct wb_sids2xids_state
);
250 NTSTATUS status
, result
;
252 status
= dcerpc_wbint_Sids2UnixIDs_recv(subreq
, state
, &result
);
254 if (any_nt_status_not_ok(status
, result
, &status
)) {
255 tevent_req_nterror(req
, status
);
258 tevent_req_done(req
);
261 NTSTATUS
wb_sids2xids_recv(struct tevent_req
*req
,
262 struct unixid xids
[], uint32_t num_xids
)
264 struct wb_sids2xids_state
*state
= tevent_req_data(
265 req
, struct wb_sids2xids_state
);
267 uint32_t i
, num_non_cached
;
269 if (tevent_req_is_nterror(req
, &status
)) {
270 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
274 if (num_xids
!= state
->num_sids
) {
275 DEBUG(1, ("%s: Have %u xids, caller wants %u\n", __func__
,
276 (unsigned)state
->num_sids
, num_xids
));
277 return NT_STATUS_INTERNAL_ERROR
;
282 for (i
=0; i
<state
->num_sids
; i
++) {
287 if (state
->cached
[i
].sid
!= NULL
) {
288 xid
= state
->cached
[i
].xid
;
290 xid
= state
->ids
.ids
[num_non_cached
].xid
;
292 idmap_cache_set_sid2unixid(
293 &state
->non_cached
[num_non_cached
],