Line data Source code
1 : /*
2 : * Unix SMB/CIFS implementation.
3 : * async xids2sids
4 : * Copyright (C) Volker Lendecke 2015
5 : *
6 : * This program is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "winbindd.h"
22 : #include "../libcli/security/security.h"
23 : #include "idmap_cache.h"
24 : #include "librpc/gen_ndr/ndr_winbind_c.h"
25 : #include "librpc/gen_ndr/ndr_netlogon.h"
26 : #include "passdb/lookup_sid.h"
27 :
28 : struct wb_xids2sids_dom_state {
29 : struct tevent_context *ev;
30 : struct unixid *all_xids;
31 : const bool *cached;
32 : size_t num_all_xids;
33 : struct dom_sid *all_sids;
34 : const struct wb_parent_idmap_config_dom *dom_map;
35 : bool tried_dclookup;
36 :
37 : size_t num_dom_xids;
38 : struct unixid *dom_xids;
39 : struct dom_sid *dom_sids;
40 : };
41 :
42 : static void wb_xids2sids_dom_done(struct tevent_req *subreq);
43 : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq);
44 :
45 6304 : static struct tevent_req *wb_xids2sids_dom_send(
46 : TALLOC_CTX *mem_ctx, struct tevent_context *ev,
47 : const struct wb_parent_idmap_config_dom *dom_map,
48 : struct unixid *xids,
49 : const bool *cached,
50 : size_t num_xids,
51 : struct dom_sid *sids)
52 : {
53 : struct tevent_req *req, *subreq;
54 : struct wb_xids2sids_dom_state *state;
55 6304 : struct dcerpc_binding_handle *child_binding_handle = NULL;
56 : size_t i;
57 :
58 6304 : req = tevent_req_create(mem_ctx, &state,
59 : struct wb_xids2sids_dom_state);
60 6304 : if (req == NULL) {
61 0 : return NULL;
62 : }
63 :
64 6304 : D_DEBUG("Searching for %zu xid(s) in domain %s.\n",
65 : num_xids,
66 : dom_map->name);
67 :
68 6304 : state->ev = ev;
69 6304 : state->all_xids = xids;
70 6304 : state->cached = cached;
71 6304 : state->num_all_xids = num_xids;
72 6304 : state->all_sids = sids;
73 6304 : state->dom_map = dom_map;
74 :
75 6304 : state->dom_xids = talloc_array(state, struct unixid, num_xids);
76 6304 : if (tevent_req_nomem(state->dom_xids, req)) {
77 0 : return tevent_req_post(req, ev);
78 : }
79 6304 : state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
80 6304 : if (tevent_req_nomem(state->dom_sids, req)) {
81 0 : return tevent_req_post(req, ev);
82 : }
83 :
84 13973 : for (i=0; i<num_xids; i++) {
85 7669 : struct unixid id = state->all_xids[i];
86 :
87 7669 : if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
88 : /* out of range */
89 683 : D_DEBUG("%zu: XID %"PRIu32" is out of range.\n",
90 : i, id.id);
91 7719 : continue;
92 : }
93 6986 : if (state->cached[i]) {
94 : /* already found in cache */
95 6668 : D_DEBUG("%zu: XID %"PRIu32" is already found in cache.\n",
96 : i, id.id);
97 6668 : continue;
98 : }
99 318 : if (!is_null_sid(&state->all_sids[i])) {
100 : /* already mapped in a previously asked domain */
101 2 : D_DEBUG("%zu: XID %"PRIu32" is already mapped in a previously asked domain.\n",
102 : i, id.id);
103 2 : continue;
104 : }
105 316 : D_DEBUG("%zu: XID %"PRIu32" will be looked up via dcerpc_wbint_UnixIDs2Sids_send().\n",
106 : i, id.id);
107 316 : state->dom_xids[state->num_dom_xids++] = id;
108 : }
109 :
110 6304 : if (state->num_dom_xids == 0) {
111 6124 : tevent_req_done(req);
112 6124 : return tevent_req_post(req, ev);
113 : }
114 :
115 180 : child_binding_handle = idmap_child_handle();
116 400 : subreq = dcerpc_wbint_UnixIDs2Sids_send(
117 70 : state, ev, child_binding_handle, dom_map->name, dom_map->sid,
118 400 : state->num_dom_xids, state->dom_xids, state->dom_sids);
119 180 : if (tevent_req_nomem(subreq, req)) {
120 0 : return tevent_req_post(req, ev);
121 : }
122 180 : tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
123 180 : return req;
124 : }
125 :
126 182 : static void wb_xids2sids_dom_done(struct tevent_req *subreq)
127 : {
128 182 : struct tevent_req *req = tevent_req_callback_data(
129 : subreq, struct tevent_req);
130 182 : struct wb_xids2sids_dom_state *state = tevent_req_data(
131 : req, struct wb_xids2sids_dom_state);
132 182 : const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
133 : NTSTATUS status, result;
134 : size_t i;
135 : size_t dom_sid_idx;
136 :
137 182 : status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
138 182 : TALLOC_FREE(subreq);
139 182 : if (tevent_req_nterror(req, status)) {
140 2 : return;
141 : }
142 :
143 183 : if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
144 2 : !state->tried_dclookup) {
145 :
146 2 : const char *domain_name = find_dns_domain_name(
147 2 : state->dom_map->name);
148 :
149 2 : subreq = wb_dsgetdcname_send(state,
150 : state->ev,
151 : domain_name,
152 : NULL,
153 : NULL,
154 : DS_RETURN_DNS_NAME);
155 2 : if (tevent_req_nomem(subreq, req)) {
156 1 : return;
157 : }
158 2 : tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
159 2 : return;
160 : }
161 :
162 360 : if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
163 180 : tevent_req_nterror(req, result)) {
164 0 : return;
165 : }
166 :
167 180 : dom_sid_idx = 0;
168 :
169 180 : D_DEBUG("Processing response for %zu xid(s).\n", state->num_all_xids);
170 497 : for (i=0; i<state->num_all_xids; i++) {
171 317 : struct unixid *id = &state->all_xids[i];
172 : struct dom_sid_buf buf;
173 :
174 317 : if ((id->id < dom_map->low_id) || (id->id > dom_map->high_id)) {
175 : /* out of range */
176 1 : continue;
177 : }
178 317 : if (state->cached[i]) {
179 : /* already found in cache */
180 1 : continue;
181 : }
182 316 : if (!is_null_sid(&state->all_sids[i])) {
183 : /* already mapped in a previously asked domain */
184 0 : continue;
185 : }
186 :
187 316 : sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
188 316 : *id = state->dom_xids[dom_sid_idx];
189 316 : D_DEBUG("%zu: XID %"PRIu32" mapped to SID %s.\n",
190 : i,
191 : id->id,
192 : dom_sid_str_buf(&state->all_sids[i], &buf));
193 :
194 316 : dom_sid_idx += 1;
195 : }
196 :
197 180 : tevent_req_done(req);
198 : }
199 :
200 2 : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
201 : {
202 2 : struct tevent_req *req = tevent_req_callback_data(
203 : subreq, struct tevent_req);
204 2 : struct wb_xids2sids_dom_state *state = tevent_req_data(
205 : req, struct wb_xids2sids_dom_state);
206 2 : struct dcerpc_binding_handle *child_binding_handle = NULL;
207 : struct netr_DsRGetDCNameInfo *dcinfo;
208 : NTSTATUS status;
209 :
210 2 : status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
211 2 : TALLOC_FREE(subreq);
212 2 : if (tevent_req_nterror(req, status)) {
213 0 : return;
214 : }
215 :
216 2 : state->tried_dclookup = true;
217 :
218 2 : status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
219 2 : if (tevent_req_nterror(req, status)) {
220 0 : return;
221 : }
222 :
223 2 : child_binding_handle = idmap_child_handle();
224 4 : subreq = dcerpc_wbint_UnixIDs2Sids_send(
225 2 : state, state->ev, child_binding_handle, state->dom_map->name,
226 3 : state->dom_map->sid, state->num_dom_xids,
227 : state->dom_xids, state->dom_sids);
228 2 : if (tevent_req_nomem(subreq, req)) {
229 0 : return;
230 : }
231 2 : tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
232 : }
233 :
234 6304 : static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
235 : {
236 6304 : return tevent_req_simple_recv_ntstatus(req);
237 : }
238 :
239 : struct wb_xids2sids_state {
240 : struct tevent_context *ev;
241 : struct unixid *xids;
242 : size_t num_xids;
243 : struct dom_sid *sids;
244 : bool *cached;
245 :
246 : size_t dom_idx;
247 : const struct wb_parent_idmap_config *cfg;
248 : };
249 :
250 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
251 : static void wb_xids2sids_done(struct tevent_req *subreq);
252 :
253 4470 : struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
254 : struct tevent_context *ev,
255 : const struct unixid *xids,
256 : uint32_t num_xids)
257 : {
258 : struct tevent_req *req, *subreq;
259 : struct wb_xids2sids_state *state;
260 :
261 4470 : req = tevent_req_create(mem_ctx, &state,
262 : struct wb_xids2sids_state);
263 4470 : if (req == NULL) {
264 0 : return NULL;
265 : }
266 :
267 4470 : D_INFO("WB command xids2sids start.\nLooking up %"PRIu32" XID(s).\n",
268 : num_xids);
269 :
270 4470 : state->ev = ev;
271 4470 : state->num_xids = num_xids;
272 :
273 4470 : state->xids = talloc_array(state, struct unixid, num_xids);
274 4470 : if (tevent_req_nomem(state->xids, req)) {
275 0 : return tevent_req_post(req, ev);
276 : }
277 4470 : memcpy(state->xids, xids, num_xids * sizeof(struct unixid));
278 :
279 4470 : state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
280 4470 : if (tevent_req_nomem(state->sids, req)) {
281 0 : return tevent_req_post(req, ev);
282 : }
283 :
284 4470 : state->cached = talloc_zero_array(state, bool, num_xids);
285 4470 : if (tevent_req_nomem(state->cached, req)) {
286 0 : return tevent_req_post(req, ev);
287 : }
288 :
289 4470 : if (winbindd_use_idmap_cache()) {
290 : uint32_t i;
291 :
292 10169 : for (i=0; i<num_xids; i++) {
293 5699 : struct dom_sid sid = {0};
294 5699 : bool ok, expired = true;
295 :
296 5699 : ok = idmap_cache_find_xid2sid(
297 5699 : &xids[i], &sid, &expired);
298 5699 : if (ok && !expired) {
299 : struct dom_sid_buf buf;
300 5469 : DBG_DEBUG("Found %cID in cache: %s\n",
301 : xids[i].type == ID_TYPE_UID?'U':'G',
302 : dom_sid_str_buf(&sid, &buf));
303 :
304 5469 : sid_copy(&state->sids[i], &sid);
305 5469 : state->cached[i] = true;
306 : }
307 : }
308 : }
309 :
310 4470 : subreq = wb_parent_idmap_setup_send(state, state->ev);
311 4470 : if (tevent_req_nomem(subreq, req)) {
312 0 : return tevent_req_post(req, ev);
313 : }
314 4470 : tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
315 4470 : return req;
316 : }
317 :
318 4470 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
319 : {
320 4470 : struct tevent_req *req = tevent_req_callback_data(
321 : subreq, struct tevent_req);
322 4470 : struct wb_xids2sids_state *state = tevent_req_data(
323 : req, struct wb_xids2sids_state);
324 : NTSTATUS status;
325 :
326 4470 : status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
327 4470 : TALLOC_FREE(subreq);
328 4470 : if (tevent_req_nterror(req, status)) {
329 0 : return;
330 : }
331 4470 : SMB_ASSERT(state->cfg->num_doms > 0);
332 :
333 12012 : subreq = wb_xids2sids_dom_send(
334 : state, state->ev,
335 4470 : &state->cfg->doms[state->dom_idx],
336 4470 : state->xids, state->cached, state->num_xids, state->sids);
337 4470 : if (tevent_req_nomem(subreq, req)) {
338 0 : return;
339 : }
340 4470 : tevent_req_set_callback(subreq, wb_xids2sids_done, req);
341 4470 : return;
342 : }
343 :
344 6304 : static void wb_xids2sids_done(struct tevent_req *subreq)
345 : {
346 6304 : struct tevent_req *req = tevent_req_callback_data(
347 : subreq, struct tevent_req);
348 6304 : struct wb_xids2sids_state *state = tevent_req_data(
349 : req, struct wb_xids2sids_state);
350 : size_t i;
351 : NTSTATUS status;
352 :
353 6304 : status = wb_xids2sids_dom_recv(subreq);
354 6304 : TALLOC_FREE(subreq);
355 6304 : if (tevent_req_nterror(req, status)) {
356 0 : return;
357 : }
358 :
359 6304 : state->dom_idx += 1;
360 6304 : if (state->dom_idx < state->cfg->num_doms) {
361 1834 : const struct wb_parent_idmap_config_dom *dom_map =
362 1834 : &state->cfg->doms[state->dom_idx];
363 :
364 2776 : subreq = wb_xids2sids_dom_send(state,
365 : state->ev,
366 : dom_map,
367 : state->xids,
368 1834 : state->cached,
369 : state->num_xids,
370 : state->sids);
371 1834 : if (tevent_req_nomem(subreq, req)) {
372 0 : return;
373 : }
374 1834 : tevent_req_set_callback(subreq, wb_xids2sids_done, req);
375 1834 : return;
376 : }
377 :
378 :
379 10169 : for (i = 0; i < state->num_xids; i++) {
380 : /*
381 : * Prime the cache after an xid2sid call. It's important that we
382 : * use the xid value returned from the backend for the xid value
383 : * passed to idmap_cache_set_sid2unixid(), not the input to
384 : * wb_xids2sids_send: the input carries what was asked for,
385 : * e.g. a ID_TYPE_UID. The result from the backend something the
386 : * idmap child possibly changed to ID_TYPE_BOTH.
387 : *
388 : * And of course If the value was from the cache don't update
389 : * the cache.
390 : */
391 :
392 5699 : if (state->cached[i]) {
393 5469 : continue;
394 : }
395 :
396 230 : idmap_cache_set_sid2unixid(&state->sids[i], &state->xids[i]);
397 : }
398 :
399 4470 : tevent_req_done(req);
400 4470 : return;
401 : }
402 :
403 4470 : NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
404 : struct dom_sid **sids)
405 : {
406 4470 : struct wb_xids2sids_state *state = tevent_req_data(
407 : req, struct wb_xids2sids_state);
408 : NTSTATUS status;
409 : size_t i;
410 :
411 4470 : D_INFO("WB command xids2sids end.\n");
412 4470 : if (tevent_req_is_nterror(req, &status)) {
413 0 : D_WARNING("wb_sids_to_xids failed: %s\n", nt_errstr(status));
414 0 : return status;
415 : }
416 :
417 4470 : *sids = talloc_move(mem_ctx, &state->sids);
418 4470 : if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
419 0 : for (i = 0; i < state->num_xids; i++) {
420 : struct dom_sid_buf buf;
421 0 : D_INFO("%zu: XID %"PRIu32" mapped to SID %s\n",
422 : i,
423 : state->xids[i].id,
424 : dom_sid_str_buf(&((*sids)[i]), &buf));
425 : }
426 : }
427 4470 : return NT_STATUS_OK;
428 : }
|