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 18056 : 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 0 : struct tevent_req *req, *subreq;
54 0 : struct wb_xids2sids_dom_state *state;
55 18056 : struct dcerpc_binding_handle *child_binding_handle = NULL;
56 0 : size_t i;
57 :
58 18056 : req = tevent_req_create(mem_ctx, &state,
59 : struct wb_xids2sids_dom_state);
60 18056 : if (req == NULL) {
61 0 : return NULL;
62 : }
63 :
64 18056 : D_DEBUG("Searching for %zu xid(s) in domain %s.\n",
65 : num_xids,
66 : dom_map->name);
67 :
68 18056 : state->ev = ev;
69 18056 : state->all_xids = xids;
70 18056 : state->cached = cached;
71 18056 : state->num_all_xids = num_xids;
72 18056 : state->all_sids = sids;
73 18056 : state->dom_map = dom_map;
74 :
75 18056 : state->dom_xids = talloc_array(state, struct unixid, num_xids);
76 18056 : if (tevent_req_nomem(state->dom_xids, req)) {
77 0 : return tevent_req_post(req, ev);
78 : }
79 18056 : state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
80 18056 : if (tevent_req_nomem(state->dom_sids, req)) {
81 0 : return tevent_req_post(req, ev);
82 : }
83 :
84 36316 : for (i=0; i<num_xids; i++) {
85 18260 : struct unixid id = state->all_xids[i];
86 :
87 18260 : if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
88 : /* out of range */
89 3408 : D_DEBUG("%zu: XID %"PRIu32" is out of range.\n",
90 : i, id.id);
91 17638 : continue;
92 : }
93 14852 : if (state->cached[i]) {
94 : /* already found in cache */
95 14222 : D_DEBUG("%zu: XID %"PRIu32" is already found in cache.\n",
96 : i, id.id);
97 14222 : continue;
98 : }
99 630 : if (!is_null_sid(&state->all_sids[i])) {
100 : /* already mapped in a previously asked domain */
101 8 : D_DEBUG("%zu: XID %"PRIu32" is already mapped in a previously asked domain.\n",
102 : i, id.id);
103 8 : continue;
104 : }
105 622 : D_DEBUG("%zu: XID %"PRIu32" will be looked up via dcerpc_wbint_UnixIDs2Sids_send().\n",
106 : i, id.id);
107 622 : state->dom_xids[state->num_dom_xids++] = id;
108 : }
109 :
110 18056 : if (state->num_dom_xids == 0) {
111 17570 : tevent_req_done(req);
112 17570 : return tevent_req_post(req, ev);
113 : }
114 :
115 486 : child_binding_handle = idmap_child_handle();
116 486 : subreq = dcerpc_wbint_UnixIDs2Sids_send(
117 486 : state, ev, child_binding_handle, dom_map->name, dom_map->sid,
118 486 : state->num_dom_xids, state->dom_xids, state->dom_sids);
119 486 : if (tevent_req_nomem(subreq, req)) {
120 0 : return tevent_req_post(req, ev);
121 : }
122 486 : tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
123 486 : return req;
124 : }
125 :
126 488 : static void wb_xids2sids_dom_done(struct tevent_req *subreq)
127 : {
128 488 : struct tevent_req *req = tevent_req_callback_data(
129 : subreq, struct tevent_req);
130 488 : struct wb_xids2sids_dom_state *state = tevent_req_data(
131 : req, struct wb_xids2sids_dom_state);
132 488 : const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
133 0 : NTSTATUS status, result;
134 0 : size_t i;
135 0 : size_t dom_sid_idx;
136 :
137 488 : status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
138 488 : TALLOC_FREE(subreq);
139 488 : if (tevent_req_nterror(req, status)) {
140 2 : return;
141 : }
142 :
143 488 : if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
144 2 : !state->tried_dclookup) {
145 :
146 2 : subreq = wb_dsgetdcname_send(
147 2 : state, state->ev, state->dom_map->name, NULL, NULL,
148 : DS_RETURN_DNS_NAME);
149 2 : if (tevent_req_nomem(subreq, req)) {
150 2 : return;
151 : }
152 2 : tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
153 2 : return;
154 : }
155 :
156 972 : if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
157 486 : tevent_req_nterror(req, result)) {
158 0 : return;
159 : }
160 :
161 486 : dom_sid_idx = 0;
162 :
163 486 : D_DEBUG("Processing response for %zu xid(s).\n", state->num_all_xids);
164 1108 : for (i=0; i<state->num_all_xids; i++) {
165 622 : struct unixid *id = &state->all_xids[i];
166 0 : struct dom_sid_buf buf;
167 :
168 622 : if ((id->id < dom_map->low_id) || (id->id > dom_map->high_id)) {
169 : /* out of range */
170 0 : continue;
171 : }
172 622 : if (state->cached[i]) {
173 : /* already found in cache */
174 0 : continue;
175 : }
176 622 : if (!is_null_sid(&state->all_sids[i])) {
177 : /* already mapped in a previously asked domain */
178 0 : continue;
179 : }
180 :
181 622 : sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
182 622 : *id = state->dom_xids[dom_sid_idx];
183 622 : D_DEBUG("%zu: XID %"PRIu32" mapped to SID %s.\n",
184 : i,
185 : id->id,
186 : dom_sid_str_buf(&state->all_sids[i], &buf));
187 :
188 622 : dom_sid_idx += 1;
189 : }
190 :
191 486 : tevent_req_done(req);
192 : }
193 :
194 2 : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
195 : {
196 2 : struct tevent_req *req = tevent_req_callback_data(
197 : subreq, struct tevent_req);
198 2 : struct wb_xids2sids_dom_state *state = tevent_req_data(
199 : req, struct wb_xids2sids_dom_state);
200 2 : struct dcerpc_binding_handle *child_binding_handle = NULL;
201 0 : struct netr_DsRGetDCNameInfo *dcinfo;
202 0 : NTSTATUS status;
203 :
204 2 : status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
205 2 : TALLOC_FREE(subreq);
206 2 : if (tevent_req_nterror(req, status)) {
207 0 : return;
208 : }
209 :
210 2 : state->tried_dclookup = true;
211 :
212 2 : status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
213 2 : if (tevent_req_nterror(req, status)) {
214 0 : return;
215 : }
216 :
217 2 : child_binding_handle = idmap_child_handle();
218 2 : subreq = dcerpc_wbint_UnixIDs2Sids_send(
219 2 : state, state->ev, child_binding_handle, state->dom_map->name,
220 2 : state->dom_map->sid, state->num_dom_xids,
221 : state->dom_xids, state->dom_sids);
222 2 : if (tevent_req_nomem(subreq, req)) {
223 0 : return;
224 : }
225 2 : tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
226 : }
227 :
228 18056 : static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
229 : {
230 18056 : return tevent_req_simple_recv_ntstatus(req);
231 : }
232 :
233 : struct wb_xids2sids_state {
234 : struct tevent_context *ev;
235 : struct unixid *xids;
236 : size_t num_xids;
237 : struct dom_sid *sids;
238 : bool *cached;
239 :
240 : size_t dom_idx;
241 : const struct wb_parent_idmap_config *cfg;
242 : };
243 :
244 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
245 : static void wb_xids2sids_done(struct tevent_req *subreq);
246 :
247 8831 : struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
248 : struct tevent_context *ev,
249 : const struct unixid *xids,
250 : uint32_t num_xids)
251 : {
252 0 : struct tevent_req *req, *subreq;
253 0 : struct wb_xids2sids_state *state;
254 :
255 8831 : req = tevent_req_create(mem_ctx, &state,
256 : struct wb_xids2sids_state);
257 8831 : if (req == NULL) {
258 0 : return NULL;
259 : }
260 :
261 8831 : D_INFO("WB command xids2sids start.\nLooking up %"PRIu32" XID(s).\n",
262 : num_xids);
263 :
264 8831 : state->ev = ev;
265 8831 : state->num_xids = num_xids;
266 :
267 8831 : state->xids = talloc_array(state, struct unixid, num_xids);
268 8831 : if (tevent_req_nomem(state->xids, req)) {
269 0 : return tevent_req_post(req, ev);
270 : }
271 8831 : memcpy(state->xids, xids, num_xids * sizeof(struct unixid));
272 :
273 8831 : state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
274 8831 : if (tevent_req_nomem(state->sids, req)) {
275 0 : return tevent_req_post(req, ev);
276 : }
277 :
278 8831 : state->cached = talloc_zero_array(state, bool, num_xids);
279 8831 : if (tevent_req_nomem(state->cached, req)) {
280 0 : return tevent_req_post(req, ev);
281 : }
282 :
283 8831 : if (winbindd_use_idmap_cache()) {
284 : uint32_t i;
285 :
286 17730 : for (i=0; i<num_xids; i++) {
287 8899 : struct dom_sid sid = {0};
288 8899 : bool ok, expired = true;
289 :
290 8899 : ok = idmap_cache_find_xid2sid(
291 8899 : &xids[i], &sid, &expired);
292 8899 : if (ok && !expired) {
293 0 : struct dom_sid_buf buf;
294 8387 : DBG_DEBUG("Found %cID in cache: %s\n",
295 : xids[i].type == ID_TYPE_UID?'U':'G',
296 : dom_sid_str_buf(&sid, &buf));
297 :
298 8387 : sid_copy(&state->sids[i], &sid);
299 8387 : state->cached[i] = true;
300 : }
301 : }
302 : }
303 :
304 8831 : subreq = wb_parent_idmap_setup_send(state, state->ev);
305 8831 : if (tevent_req_nomem(subreq, req)) {
306 0 : return tevent_req_post(req, ev);
307 : }
308 8831 : tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
309 8831 : return req;
310 : }
311 :
312 8831 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
313 : {
314 8831 : struct tevent_req *req = tevent_req_callback_data(
315 : subreq, struct tevent_req);
316 8831 : struct wb_xids2sids_state *state = tevent_req_data(
317 : req, struct wb_xids2sids_state);
318 0 : NTSTATUS status;
319 :
320 8831 : status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
321 8831 : TALLOC_FREE(subreq);
322 8831 : if (tevent_req_nterror(req, status)) {
323 0 : return;
324 : }
325 8831 : SMB_ASSERT(state->cfg->num_doms > 0);
326 :
327 8831 : subreq = wb_xids2sids_dom_send(
328 : state, state->ev,
329 8831 : &state->cfg->doms[state->dom_idx],
330 8831 : state->xids, state->cached, state->num_xids, state->sids);
331 8831 : if (tevent_req_nomem(subreq, req)) {
332 0 : return;
333 : }
334 8831 : tevent_req_set_callback(subreq, wb_xids2sids_done, req);
335 8831 : return;
336 : }
337 :
338 18056 : static void wb_xids2sids_done(struct tevent_req *subreq)
339 : {
340 18056 : struct tevent_req *req = tevent_req_callback_data(
341 : subreq, struct tevent_req);
342 18056 : struct wb_xids2sids_state *state = tevent_req_data(
343 : req, struct wb_xids2sids_state);
344 0 : size_t i;
345 0 : NTSTATUS status;
346 :
347 18056 : status = wb_xids2sids_dom_recv(subreq);
348 18056 : TALLOC_FREE(subreq);
349 18056 : if (tevent_req_nterror(req, status)) {
350 0 : return;
351 : }
352 :
353 18056 : state->dom_idx += 1;
354 18056 : if (state->dom_idx < state->cfg->num_doms) {
355 9225 : const struct wb_parent_idmap_config_dom *dom_map =
356 9225 : &state->cfg->doms[state->dom_idx];
357 :
358 9225 : subreq = wb_xids2sids_dom_send(state,
359 : state->ev,
360 : dom_map,
361 : state->xids,
362 9225 : state->cached,
363 : state->num_xids,
364 : state->sids);
365 9225 : if (tevent_req_nomem(subreq, req)) {
366 0 : return;
367 : }
368 9225 : tevent_req_set_callback(subreq, wb_xids2sids_done, req);
369 9225 : return;
370 : }
371 :
372 :
373 17730 : for (i = 0; i < state->num_xids; i++) {
374 : /*
375 : * Prime the cache after an xid2sid call. It's important that we
376 : * use the xid value returned from the backend for the xid value
377 : * passed to idmap_cache_set_sid2unixid(), not the input to
378 : * wb_xids2sids_send: the input carries what was asked for,
379 : * e.g. a ID_TYPE_UID. The result from the backend something the
380 : * idmap child possibly changed to ID_TYPE_BOTH.
381 : *
382 : * And of course If the value was from the cache don't update
383 : * the cache.
384 : */
385 :
386 8899 : if (state->cached[i]) {
387 8387 : continue;
388 : }
389 :
390 512 : idmap_cache_set_sid2unixid(&state->sids[i], &state->xids[i]);
391 : }
392 :
393 8831 : tevent_req_done(req);
394 8831 : return;
395 : }
396 :
397 8831 : NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
398 : struct dom_sid **sids)
399 : {
400 8831 : struct wb_xids2sids_state *state = tevent_req_data(
401 : req, struct wb_xids2sids_state);
402 0 : NTSTATUS status;
403 0 : size_t i;
404 :
405 8831 : D_INFO("WB command xids2sids end.\n");
406 8831 : if (tevent_req_is_nterror(req, &status)) {
407 0 : D_WARNING("wb_sids_to_xids failed: %s\n", nt_errstr(status));
408 0 : return status;
409 : }
410 :
411 8831 : *sids = talloc_move(mem_ctx, &state->sids);
412 8831 : if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
413 0 : for (i = 0; i < state->num_xids; i++) {
414 0 : struct dom_sid_buf buf;
415 0 : D_INFO("%zu: XID %"PRIu32" mapped to SID %s\n",
416 : i,
417 : state->xids[i].id,
418 : dom_sid_str_buf(&((*sids)[i]), &buf));
419 : }
420 : }
421 8831 : return NT_STATUS_OK;
422 : }
|