winbind: Slightly simplify wb_sids2xids
[Samba.git] / source3 / winbindd / wb_sids2xids.c
blob76149743f055532728d622b49887ca65a4ecd263
1 /*
2 Unix SMB/CIFS implementation.
3 async sids2xids
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/>.
21 #include "includes.h"
22 #include "winbindd.h"
23 #include "../libcli/security/security.h"
24 #include "idmap_cache.h"
25 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 #include "lsa.h"
28 struct wb_sids2xids_state {
29 struct tevent_context *ev;
31 struct dom_sid *sids;
32 uint32_t num_sids;
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
48 * invalid SIDs.
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;
67 uint32_t i;
69 req = tevent_req_create(mem_ctx, &state,
70 struct wb_sids2xids_state);
71 if (req == NULL) {
72 return NULL;
75 state->ev = ev;
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
101 * the same index.
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])) {
109 continue;
111 sid_copy(&state->non_cached[state->num_non_cached],
112 &state->sids[i]);
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);
127 return req;
130 static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
132 struct unixid id;
133 bool expired;
135 if (!winbindd_use_idmap_cache()) {
136 return false;
138 if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
139 if (expired && is_domain_online(find_our_domain())) {
140 return false;
142 map->sid = sid;
143 map->xid = id;
144 map->status = ID_MAPPED;
145 return true;
147 return false;
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;
161 NTSTATUS status;
162 int i;
164 status = wb_lookupsids_recv(subreq, state, &domains, &names);
165 TALLOC_FREE(subreq);
166 if (tevent_req_nterror(req, status)) {
167 return;
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)) {
174 return;
177 state->idmap_doms = talloc_zero(state, struct lsa_RefDomainList);
178 if (tevent_req_nomem(state->idmap_doms, req)) {
179 return;
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];
188 sid_copy(&dom_sid, &state->non_cached[i]);
189 sid_split_rid(&dom_sid, &t->rid);
191 info = &domains->domains[n->sid_index];
192 t->type = lsa_SidType_to_id_type(n->sid_type);
193 t->domain_index = init_lsa_ref_domain_list(state,
194 state->idmap_doms,
195 info->name.string,
196 &dom_sid);
197 t->xid.id = UINT32_MAX;
198 t->xid.type = t->type;
201 TALLOC_FREE(names);
202 TALLOC_FREE(domains);
204 child = idmap_child();
206 subreq = dcerpc_wbint_Sids2UnixIDs_send(
207 state, state->ev, child->binding_handle, state->idmap_doms,
208 &state->ids);
209 if (tevent_req_nomem(subreq, req)) {
210 return;
212 tevent_req_set_callback(subreq, wb_sids2xids_done, req);
215 static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
217 enum id_type type;
219 switch(sid_type) {
220 case SID_NAME_COMPUTER:
221 case SID_NAME_USER:
222 type = ID_TYPE_UID;
223 break;
224 case SID_NAME_DOM_GRP:
225 case SID_NAME_ALIAS:
226 case SID_NAME_WKN_GRP:
227 type = ID_TYPE_GID;
228 break;
229 default:
230 type = ID_TYPE_NOT_SPECIFIED;
231 break;
234 return type;
238 static void wb_sids2xids_done(struct tevent_req *subreq)
240 struct tevent_req *req = tevent_req_callback_data(
241 subreq, struct tevent_req);
242 struct wb_sids2xids_state *state = tevent_req_data(
243 req, struct wb_sids2xids_state);
244 NTSTATUS status, result;
246 status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
247 TALLOC_FREE(subreq);
248 if (any_nt_status_not_ok(status, result, &status)) {
249 tevent_req_nterror(req, status);
250 return;
252 tevent_req_done(req);
255 NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
256 struct unixid *xids)
258 struct wb_sids2xids_state *state = tevent_req_data(
259 req, struct wb_sids2xids_state);
260 NTSTATUS status;
261 uint32_t i, num_non_cached;
263 if (tevent_req_is_nterror(req, &status)) {
264 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status)));
265 return status;
268 num_non_cached = 0;
270 for (i=0; i<state->num_sids; i++) {
271 struct unixid xid;
273 xid.id = UINT32_MAX;
275 if (state->cached[i].sid != NULL) {
276 xid = state->cached[i].xid;
277 } else {
278 xid = state->ids.ids[num_non_cached].xid;
280 idmap_cache_set_sid2unixid(
281 &state->non_cached[num_non_cached],
282 &xid);
284 num_non_cached += 1;
287 xids[i] = xid;
290 return NT_STATUS_OK;