source: vendor/current/source3/winbindd/wb_sids2xids.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 7.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 async sids2xids
4 Copyright (C) Volker Lendecke 2011
5 Copyright (C) Michael Adam 2012
6
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.
11
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.
16
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/>.
19*/
20
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"
27
28struct wb_sids2xids_state {
29 struct tevent_context *ev;
30
31 struct dom_sid *sids;
32 uint32_t num_sids;
33
34 struct id_map *cached;
35
36 struct dom_sid *non_cached;
37 uint32_t num_non_cached;
38
39 /*
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.
45 *
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.
49 */
50 struct lsa_RefDomainList *idmap_doms;
51
52 struct wbint_TransIDArray ids;
53};
54
55
56static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map);
57static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq);
58static void wb_sids2xids_done(struct tevent_req *subreq);
59
60struct 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)
64{
65 struct tevent_req *req, *subreq;
66 struct wb_sids2xids_state *state;
67 uint32_t i;
68
69 req = tevent_req_create(mem_ctx, &state,
70 struct wb_sids2xids_state);
71 if (req == NULL) {
72 return NULL;
73 }
74
75 state->ev = ev;
76
77 state->num_sids = num_sids;
78
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);
82 }
83
84 for (i = 0; i < num_sids; i++) {
85 sid_copy(&state->sids[i], &sids[i]);
86 }
87
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);
91 }
92
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);
96 }
97
98 /*
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.
102 */
103 for (i=0; i<state->num_sids; i++) {
104
105 DEBUG(10, ("SID %d: %s\n", (int)i,
106 sid_string_dbg(&state->sids[i])));
107
108 if (wb_sids2xids_in_cache(&state->sids[i], &state->cached[i])) {
109 continue;
110 }
111 sid_copy(&state->non_cached[state->num_non_cached],
112 &state->sids[i]);
113 state->num_non_cached += 1;
114 }
115
116 if (state->num_non_cached == 0) {
117 tevent_req_done(req);
118 return tevent_req_post(req, ev);
119 }
120
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);
125 }
126 tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
127 return req;
128}
129
130static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
131{
132 struct unixid id;
133 bool expired;
134
135 if (!winbindd_use_idmap_cache()) {
136 return false;
137 }
138 if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
139 if (expired && is_domain_online(find_our_domain())) {
140 return false;
141 }
142 map->sid = sid;
143 map->xid = id;
144 map->status = ID_MAPPED;
145 return true;
146 }
147 return false;
148}
149
150static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type);
151
152static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
153{
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;
163
164 status = wb_lookupsids_recv(subreq, state, &domains, &names);
165 TALLOC_FREE(subreq);
166 if (tevent_req_nterror(req, status)) {
167 return;
168 }
169
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;
175 }
176
177 state->idmap_doms = talloc_zero(state, struct lsa_RefDomainList);
178 if (tevent_req_nomem(state->idmap_doms, req)) {
179 return;
180 }
181
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];
187 int domain_index;
188
189 sid_copy(&dom_sid, &state->non_cached[i]);
190 sid_split_rid(&dom_sid, &t->rid);
191
192 info = &domains->domains[n->sid_index];
193 t->type = lsa_SidType_to_id_type(n->sid_type);
194
195 domain_index = init_lsa_ref_domain_list(
196 state, state->idmap_doms, info->name.string, &dom_sid);
197 if (domain_index == -1) {
198 tevent_req_oom(req);
199 return;
200 }
201 t->domain_index = domain_index;
202
203 t->xid.id = UINT32_MAX;
204 t->xid.type = t->type;
205 }
206
207 TALLOC_FREE(names);
208 TALLOC_FREE(domains);
209
210 child = idmap_child();
211
212 subreq = dcerpc_wbint_Sids2UnixIDs_send(
213 state, state->ev, child->binding_handle, state->idmap_doms,
214 &state->ids);
215 if (tevent_req_nomem(subreq, req)) {
216 return;
217 }
218 tevent_req_set_callback(subreq, wb_sids2xids_done, req);
219}
220
221static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
222{
223 enum id_type type;
224
225 switch(sid_type) {
226 case SID_NAME_COMPUTER:
227 case SID_NAME_USER:
228 type = ID_TYPE_UID;
229 break;
230 case SID_NAME_DOM_GRP:
231 case SID_NAME_ALIAS:
232 case SID_NAME_WKN_GRP:
233 type = ID_TYPE_GID;
234 break;
235 default:
236 type = ID_TYPE_NOT_SPECIFIED;
237 break;
238 }
239
240 return type;
241}
242
243
244static void wb_sids2xids_done(struct tevent_req *subreq)
245{
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;
251
252 status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
253 TALLOC_FREE(subreq);
254 if (any_nt_status_not_ok(status, result, &status)) {
255 tevent_req_nterror(req, status);
256 return;
257 }
258 tevent_req_done(req);
259}
260
261NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
262 struct unixid xids[], uint32_t num_xids)
263{
264 struct wb_sids2xids_state *state = tevent_req_data(
265 req, struct wb_sids2xids_state);
266 NTSTATUS status;
267 uint32_t i, num_non_cached;
268
269 if (tevent_req_is_nterror(req, &status)) {
270 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status)));
271 return status;
272 }
273
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;
278 }
279
280 num_non_cached = 0;
281
282 for (i=0; i<state->num_sids; i++) {
283 struct unixid xid;
284
285 xid.id = UINT32_MAX;
286
287 if (state->cached[i].sid != NULL) {
288 xid = state->cached[i].xid;
289 } else {
290 xid = state->ids.ids[num_non_cached].xid;
291
292 idmap_cache_set_sid2unixid(
293 &state->non_cached[num_non_cached],
294 &xid);
295
296 num_non_cached += 1;
297 }
298
299 xids[i] = xid;
300 }
301
302 return NT_STATUS_OK;
303}
Note: See TracBrowser for help on using the repository browser.