Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Async helpers for blocking functions
5 :
6 : Copyright (C) Volker Lendecke 2005
7 : Copyright (C) Gerald Carter 2006
8 : Copyright (C) Simo Sorce 2007
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "winbindd.h"
26 : #include "../libcli/security/security.h"
27 : #include "passdb/lookup_sid.h"
28 : #include "lib/global_contexts.h"
29 :
30 : #undef DBGC_CLASS
31 : #define DBGC_CLASS DBGC_WINBIND
32 :
33 : static struct winbindd_child static_idmap_child;
34 :
35 : /*
36 : * Map idmap ranges to domain names, taken from smb.conf. This is
37 : * stored in the parent winbind and used to assemble xids2sids/sids2xids calls
38 : * into per-idmap-domain chunks.
39 : */
40 : static struct wb_parent_idmap_config static_parent_idmap_config;
41 :
42 109 : struct winbindd_child *idmap_child(void)
43 : {
44 109 : return &static_idmap_child;
45 : }
46 :
47 0 : bool is_idmap_child(const struct winbindd_child *child)
48 : {
49 0 : if (child == &static_idmap_child) {
50 0 : return true;
51 : }
52 :
53 0 : return false;
54 : }
55 :
56 2 : pid_t idmap_child_pid(void)
57 : {
58 2 : return static_idmap_child.pid;
59 : }
60 :
61 95872 : struct dcerpc_binding_handle *idmap_child_handle(void)
62 : {
63 : /*
64 : * The caller needs to use wb_parent_idmap_setup_send/recv
65 : * before talking to the idmap child!
66 : */
67 95872 : SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
68 95872 : return static_idmap_child.binding_handle;
69 : }
70 :
71 : static void init_idmap_child_done(struct tevent_req *subreq);
72 :
73 41 : void init_idmap_child(void)
74 : {
75 41 : struct tevent_req *subreq = NULL;
76 :
77 41 : subreq = wb_parent_idmap_setup_send(global_event_context(),
78 : global_event_context());
79 41 : if (subreq == NULL) {
80 : /*
81 : * This is only an optimization, so we're free to
82 : * to ignore errors
83 : */
84 0 : DBG_ERR("wb_parent_idmap_setup_send() failed\n");
85 0 : return;
86 : }
87 41 : tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
88 41 : DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
89 : }
90 :
91 41 : static void init_idmap_child_done(struct tevent_req *subreq)
92 : {
93 41 : const struct wb_parent_idmap_config *cfg = NULL;
94 0 : NTSTATUS status;
95 :
96 41 : status = wb_parent_idmap_setup_recv(subreq, &cfg);
97 41 : TALLOC_FREE(subreq);
98 41 : if (!NT_STATUS_IS_OK(status)) {
99 : /*
100 : * This is only an optimization, so we're free to
101 : * to ignore errors
102 : */
103 0 : DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
104 : nt_errstr(status));
105 0 : return;
106 : }
107 :
108 41 : DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
109 : }
110 :
111 : struct wb_parent_idmap_setup_state {
112 : struct tevent_context *ev;
113 : struct wb_parent_idmap_config *cfg;
114 : size_t dom_idx;
115 : };
116 :
117 82 : static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
118 : enum tevent_req_state req_state)
119 : {
120 0 : struct wb_parent_idmap_setup_state *state =
121 82 : tevent_req_data(req,
122 : struct wb_parent_idmap_setup_state);
123 :
124 82 : if (req_state == TEVENT_REQ_DONE) {
125 41 : state->cfg = NULL;
126 41 : return;
127 : }
128 :
129 41 : if (state->cfg == NULL) {
130 41 : return;
131 : }
132 :
133 0 : state->cfg->num_doms = 0;
134 0 : state->cfg->initialized = false;
135 0 : TALLOC_FREE(state->cfg->doms);
136 0 : state->cfg = NULL;
137 : }
138 :
139 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
140 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
141 : void *private_data);
142 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
143 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
144 :
145 101543 : struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
146 : struct tevent_context *ev)
147 : {
148 101543 : struct tevent_req *req = NULL;
149 101543 : struct wb_parent_idmap_setup_state *state = NULL;
150 101543 : struct tevent_req *subreq = NULL;
151 :
152 101543 : req = tevent_req_create(mem_ctx, &state,
153 : struct wb_parent_idmap_setup_state);
154 101543 : if (req == NULL) {
155 0 : return NULL;
156 : }
157 101543 : *state = (struct wb_parent_idmap_setup_state) {
158 : .ev = ev,
159 : .cfg = &static_parent_idmap_config,
160 : .dom_idx = 0,
161 : };
162 :
163 101543 : if (state->cfg->initialized) {
164 101487 : tevent_req_done(req);
165 101487 : return tevent_req_post(req, ev);
166 : }
167 :
168 56 : if (state->cfg->queue == NULL) {
169 41 : state->cfg->queue = tevent_queue_create(NULL,
170 : "wb_parent_idmap_config_queue");
171 41 : if (tevent_req_nomem(state->cfg->queue, req)) {
172 0 : return tevent_req_post(req, ev);
173 : }
174 : }
175 :
176 56 : subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
177 56 : if (tevent_req_nomem(subreq, req)) {
178 0 : return tevent_req_post(req, ev);
179 : }
180 56 : tevent_req_set_callback(subreq,
181 : wb_parent_idmap_setup_queue_wait_done,
182 : req);
183 :
184 56 : return req;
185 : }
186 :
187 56 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
188 : {
189 0 : struct tevent_req *req =
190 56 : tevent_req_callback_data(subreq,
191 : struct tevent_req);
192 0 : struct wb_parent_idmap_setup_state *state =
193 56 : tevent_req_data(req,
194 : struct wb_parent_idmap_setup_state);
195 0 : bool ok;
196 :
197 : /*
198 : * Note we don't call TALLOC_FREE(subreq) here in order to block the
199 : * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
200 : * will destroy it implicitly.
201 : */
202 56 : ok = tevent_queue_wait_recv(subreq);
203 56 : if (!ok) {
204 0 : DBG_ERR("tevent_queue_wait_recv() failed\n");
205 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
206 0 : return;
207 : }
208 :
209 56 : if (state->cfg->num_doms != 0) {
210 : /*
211 : * If we're not the first one we're done.
212 : */
213 15 : tevent_req_done(req);
214 15 : return;
215 : }
216 :
217 : /*
218 : * From this point we start changing state->cfg,
219 : * which is &static_parent_idmap_config,
220 : * so we better setup a cleanup function
221 : * to undo the changes on failure.
222 : */
223 41 : tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
224 :
225 : /*
226 : * Put the passdb idmap domain first. We always need to try
227 : * there first.
228 : */
229 41 : state->cfg->doms = talloc_zero_array(NULL,
230 : struct wb_parent_idmap_config_dom,
231 : 1);
232 41 : if (tevent_req_nomem(state->cfg->doms, req)) {
233 0 : return;
234 : }
235 41 : state->cfg->doms[0].low_id = 0;
236 41 : state->cfg->doms[0].high_id = UINT_MAX;
237 41 : state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
238 : get_global_sam_name());
239 41 : if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
240 0 : return;
241 : }
242 41 : state->cfg->num_doms += 1;
243 :
244 41 : lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
245 41 : if (!tevent_req_is_in_progress(req)) {
246 0 : return;
247 : }
248 :
249 41 : wb_parent_idmap_setup_lookupname_next(req);
250 : }
251 :
252 51 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
253 : void *private_data)
254 : {
255 0 : struct tevent_req *req =
256 51 : talloc_get_type_abort(private_data,
257 : struct tevent_req);
258 0 : struct wb_parent_idmap_setup_state *state =
259 51 : tevent_req_data(req,
260 : struct wb_parent_idmap_setup_state);
261 51 : struct wb_parent_idmap_config_dom *map = NULL;
262 0 : size_t i;
263 0 : const char *range;
264 0 : unsigned low_id, high_id;
265 0 : int ret;
266 :
267 51 : range = idmap_config_const_string(domname, "range", NULL);
268 51 : if (range == NULL) {
269 0 : DBG_DEBUG("No range for domain %s found\n", domname);
270 0 : return false;
271 : }
272 :
273 51 : ret = sscanf(range, "%u - %u", &low_id, &high_id);
274 51 : if (ret != 2) {
275 0 : DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
276 : range, domname);
277 0 : return false;
278 : }
279 :
280 51 : if (low_id > high_id) {
281 0 : DBG_DEBUG("Invalid range %u - %u for domain %s\n",
282 : low_id, high_id, domname);
283 0 : return false;
284 : }
285 :
286 114 : for (i=0; i<state->cfg->num_doms; i++) {
287 63 : if (strequal(domname, state->cfg->doms[i].name)) {
288 0 : map = &state->cfg->doms[i];
289 0 : break;
290 : }
291 : }
292 :
293 51 : if (map == NULL) {
294 0 : struct wb_parent_idmap_config_dom *tmp;
295 0 : char *name;
296 :
297 51 : name = talloc_strdup(state, domname);
298 51 : if (name == NULL) {
299 0 : DBG_ERR("talloc failed\n");
300 0 : return false;
301 : }
302 :
303 51 : tmp = talloc_realloc(
304 : NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
305 : state->cfg->num_doms+1);
306 51 : if (tmp == NULL) {
307 0 : DBG_ERR("talloc failed\n");
308 0 : return false;
309 : }
310 51 : state->cfg->doms = tmp;
311 :
312 51 : map = &state->cfg->doms[state->cfg->num_doms];
313 51 : state->cfg->num_doms += 1;
314 51 : ZERO_STRUCTP(map);
315 51 : map->name = talloc_move(state->cfg->doms, &name);
316 : }
317 :
318 51 : map->low_id = low_id;
319 51 : map->high_id = high_id;
320 :
321 51 : return false;
322 : }
323 :
324 92 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
325 : {
326 0 : struct wb_parent_idmap_setup_state *state =
327 92 : tevent_req_data(req,
328 : struct wb_parent_idmap_setup_state);
329 92 : struct wb_parent_idmap_config_dom *dom =
330 92 : &state->cfg->doms[state->dom_idx];
331 92 : struct tevent_req *subreq = NULL;
332 :
333 133 : next_domain:
334 133 : if (state->dom_idx == state->cfg->num_doms) {
335 : /*
336 : * We're done, so start the idmap child
337 : */
338 41 : setup_child(NULL, &static_idmap_child, "log.winbindd", "idmap");
339 41 : static_parent_idmap_config.initialized = true;
340 41 : tevent_req_done(req);
341 41 : return;
342 : }
343 :
344 92 : if (strequal(dom->name, "*")) {
345 41 : state->dom_idx++;
346 41 : goto next_domain;
347 : }
348 :
349 51 : subreq = wb_lookupname_send(state,
350 : state->ev,
351 : dom->name,
352 : dom->name,
353 : "",
354 : LOOKUP_NAME_NO_NSS);
355 51 : if (tevent_req_nomem(subreq, req)) {
356 0 : return;
357 : }
358 51 : tevent_req_set_callback(subreq,
359 : wb_parent_idmap_setup_lookupname_done,
360 : req);
361 : }
362 :
363 51 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
364 : {
365 0 : struct tevent_req *req =
366 51 : tevent_req_callback_data(subreq,
367 : struct tevent_req);
368 0 : struct wb_parent_idmap_setup_state *state =
369 51 : tevent_req_data(req,
370 : struct wb_parent_idmap_setup_state);
371 51 : struct wb_parent_idmap_config_dom *dom =
372 51 : &state->cfg->doms[state->dom_idx];
373 0 : enum lsa_SidType type;
374 0 : NTSTATUS status;
375 :
376 51 : status = wb_lookupname_recv(subreq, &dom->sid, &type);
377 51 : TALLOC_FREE(subreq);
378 51 : if (!NT_STATUS_IS_OK(status)) {
379 0 : DBG_ERR("Lookup domain name '%s' failed '%s'\n",
380 : dom->name,
381 : nt_errstr(status));
382 :
383 0 : state->dom_idx++;
384 0 : wb_parent_idmap_setup_lookupname_next(req);
385 0 : return;
386 : }
387 :
388 51 : if (type != SID_NAME_DOMAIN) {
389 0 : struct dom_sid_buf buf;
390 :
391 0 : DBG_ERR("SID %s for idmap domain name '%s' "
392 : "not a domain SID\n",
393 : dom_sid_str_buf(&dom->sid, &buf),
394 : dom->name);
395 :
396 0 : ZERO_STRUCT(dom->sid);
397 : }
398 :
399 51 : state->dom_idx++;
400 51 : wb_parent_idmap_setup_lookupname_next(req);
401 :
402 51 : return;
403 : }
404 :
405 101543 : NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
406 : const struct wb_parent_idmap_config **_cfg)
407 : {
408 101543 : const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
409 0 : NTSTATUS status;
410 :
411 101543 : *_cfg = NULL;
412 :
413 101543 : if (tevent_req_is_nterror(req, &status)) {
414 0 : tevent_req_received(req);
415 0 : return status;
416 : }
417 :
418 : /*
419 : * Note state->cfg is already set to NULL by
420 : * wb_parent_idmap_setup_cleanup()
421 : */
422 101543 : *_cfg = cfg;
423 101543 : tevent_req_received(req);
424 101543 : return NT_STATUS_OK;
425 : }
|