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 = NULL;
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 0 : pid_t idmap_child_pid(void)
57 : {
58 0 : return static_idmap_child->pid;
59 : }
60 :
61 109720 : 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 109720 : SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
68 109720 : return static_idmap_child->binding_handle;
69 : }
70 :
71 : static void init_idmap_child_done(struct tevent_req *subreq);
72 :
73 45 : NTSTATUS init_idmap_child(TALLOC_CTX *mem_ctx)
74 : {
75 45 : struct tevent_req *subreq = NULL;
76 :
77 45 : if (static_idmap_child != NULL) {
78 0 : DBG_ERR("idmap child already allocated\n");
79 0 : return NT_STATUS_INTERNAL_ERROR;
80 : }
81 :
82 45 : static_idmap_child = talloc_zero(mem_ctx, struct winbindd_child);
83 45 : if (static_idmap_child == NULL) {
84 0 : return NT_STATUS_NO_MEMORY;
85 : }
86 :
87 45 : subreq = wb_parent_idmap_setup_send(static_idmap_child,
88 : global_event_context());
89 45 : if (subreq == NULL) {
90 : /*
91 : * This is only an optimization, so we're free to
92 : * to ignore errors
93 : */
94 0 : DBG_ERR("wb_parent_idmap_setup_send() failed\n");
95 0 : return NT_STATUS_NO_MEMORY;
96 : }
97 45 : tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
98 45 : DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
99 45 : return NT_STATUS_OK;
100 : }
101 :
102 45 : static void init_idmap_child_done(struct tevent_req *subreq)
103 : {
104 45 : const struct wb_parent_idmap_config *cfg = NULL;
105 0 : NTSTATUS status;
106 :
107 45 : status = wb_parent_idmap_setup_recv(subreq, &cfg);
108 45 : TALLOC_FREE(subreq);
109 45 : if (!NT_STATUS_IS_OK(status)) {
110 : /*
111 : * This is only an optimization, so we're free to
112 : * to ignore errors
113 : */
114 0 : DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
115 : nt_errstr(status));
116 0 : return;
117 : }
118 :
119 45 : DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
120 : }
121 :
122 : struct wb_parent_idmap_setup_state {
123 : struct tevent_context *ev;
124 : struct wb_parent_idmap_config *cfg;
125 : size_t dom_idx;
126 : };
127 :
128 90 : static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
129 : enum tevent_req_state req_state)
130 : {
131 0 : struct wb_parent_idmap_setup_state *state =
132 90 : tevent_req_data(req,
133 : struct wb_parent_idmap_setup_state);
134 :
135 90 : if (req_state == TEVENT_REQ_DONE) {
136 45 : state->cfg = NULL;
137 45 : return;
138 : }
139 :
140 45 : if (state->cfg == NULL) {
141 45 : return;
142 : }
143 :
144 0 : state->cfg->num_doms = 0;
145 0 : state->cfg->initialized = false;
146 0 : TALLOC_FREE(state->cfg->doms);
147 0 : state->cfg = NULL;
148 : }
149 :
150 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
151 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
152 : void *private_data);
153 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
154 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
155 :
156 116807 : struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
157 : struct tevent_context *ev)
158 : {
159 116807 : struct tevent_req *req = NULL;
160 116807 : struct wb_parent_idmap_setup_state *state = NULL;
161 116807 : struct tevent_req *subreq = NULL;
162 :
163 116807 : req = tevent_req_create(mem_ctx, &state,
164 : struct wb_parent_idmap_setup_state);
165 116807 : if (req == NULL) {
166 0 : return NULL;
167 : }
168 116807 : *state = (struct wb_parent_idmap_setup_state) {
169 : .ev = ev,
170 : .cfg = &static_parent_idmap_config,
171 : .dom_idx = 0,
172 : };
173 :
174 116807 : if (state->cfg->initialized) {
175 116747 : tevent_req_done(req);
176 116747 : return tevent_req_post(req, ev);
177 : }
178 :
179 60 : if (state->cfg->queue == NULL) {
180 45 : state->cfg->queue = tevent_queue_create(NULL,
181 : "wb_parent_idmap_config_queue");
182 45 : if (tevent_req_nomem(state->cfg->queue, req)) {
183 0 : return tevent_req_post(req, ev);
184 : }
185 : }
186 :
187 60 : subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
188 60 : if (tevent_req_nomem(subreq, req)) {
189 0 : return tevent_req_post(req, ev);
190 : }
191 60 : tevent_req_set_callback(subreq,
192 : wb_parent_idmap_setup_queue_wait_done,
193 : req);
194 :
195 60 : return req;
196 : }
197 :
198 60 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
199 : {
200 0 : struct tevent_req *req =
201 60 : tevent_req_callback_data(subreq,
202 : struct tevent_req);
203 0 : struct wb_parent_idmap_setup_state *state =
204 60 : tevent_req_data(req,
205 : struct wb_parent_idmap_setup_state);
206 0 : bool ok;
207 :
208 : /*
209 : * Note we don't call TALLOC_FREE(subreq) here in order to block the
210 : * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
211 : * will destroy it implicitly.
212 : */
213 60 : ok = tevent_queue_wait_recv(subreq);
214 60 : if (!ok) {
215 0 : DBG_ERR("tevent_queue_wait_recv() failed\n");
216 0 : tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
217 0 : return;
218 : }
219 :
220 60 : if (state->cfg->num_doms != 0) {
221 : /*
222 : * If we're not the first one we're done.
223 : */
224 15 : tevent_req_done(req);
225 15 : return;
226 : }
227 :
228 : /*
229 : * From this point we start changing state->cfg,
230 : * which is &static_parent_idmap_config,
231 : * so we better setup a cleanup function
232 : * to undo the changes on failure.
233 : */
234 45 : tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
235 :
236 : /*
237 : * Put the passdb idmap domain first. We always need to try
238 : * there first.
239 : */
240 45 : state->cfg->doms = talloc_zero_array(NULL,
241 : struct wb_parent_idmap_config_dom,
242 : 1);
243 45 : if (tevent_req_nomem(state->cfg->doms, req)) {
244 0 : return;
245 : }
246 45 : state->cfg->doms[0].low_id = 0;
247 45 : state->cfg->doms[0].high_id = UINT_MAX;
248 45 : state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
249 : get_global_sam_name());
250 45 : if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
251 0 : return;
252 : }
253 45 : state->cfg->num_doms += 1;
254 :
255 45 : lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
256 45 : if (!tevent_req_is_in_progress(req)) {
257 0 : return;
258 : }
259 :
260 45 : wb_parent_idmap_setup_lookupname_next(req);
261 : }
262 :
263 55 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
264 : void *private_data)
265 : {
266 0 : struct tevent_req *req =
267 55 : talloc_get_type_abort(private_data,
268 : struct tevent_req);
269 0 : struct wb_parent_idmap_setup_state *state =
270 55 : tevent_req_data(req,
271 : struct wb_parent_idmap_setup_state);
272 55 : struct wb_parent_idmap_config_dom *map = NULL;
273 0 : size_t i;
274 0 : const char *range;
275 0 : unsigned low_id, high_id;
276 0 : int ret;
277 :
278 55 : range = idmap_config_const_string(domname, "range", NULL);
279 55 : if (range == NULL) {
280 0 : DBG_DEBUG("No range for domain %s found\n", domname);
281 0 : return false;
282 : }
283 :
284 55 : ret = sscanf(range, "%u - %u", &low_id, &high_id);
285 55 : if (ret != 2) {
286 0 : DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
287 : range, domname);
288 0 : return false;
289 : }
290 :
291 55 : if (low_id > high_id) {
292 0 : DBG_DEBUG("Invalid range %u - %u for domain %s\n",
293 : low_id, high_id, domname);
294 0 : return false;
295 : }
296 :
297 122 : for (i=0; i<state->cfg->num_doms; i++) {
298 67 : if (strequal(domname, state->cfg->doms[i].name)) {
299 0 : map = &state->cfg->doms[i];
300 0 : break;
301 : }
302 : }
303 :
304 55 : if (map == NULL) {
305 0 : struct wb_parent_idmap_config_dom *tmp;
306 0 : char *name;
307 :
308 55 : name = talloc_strdup(state, domname);
309 55 : if (name == NULL) {
310 0 : DBG_ERR("talloc failed\n");
311 0 : return false;
312 : }
313 :
314 55 : tmp = talloc_realloc(
315 : NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
316 : state->cfg->num_doms+1);
317 55 : if (tmp == NULL) {
318 0 : DBG_ERR("talloc failed\n");
319 0 : return false;
320 : }
321 55 : state->cfg->doms = tmp;
322 :
323 55 : map = &state->cfg->doms[state->cfg->num_doms];
324 55 : state->cfg->num_doms += 1;
325 55 : ZERO_STRUCTP(map);
326 55 : map->name = talloc_move(state->cfg->doms, &name);
327 : }
328 :
329 55 : map->low_id = low_id;
330 55 : map->high_id = high_id;
331 :
332 55 : return false;
333 : }
334 :
335 100 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
336 : {
337 0 : struct wb_parent_idmap_setup_state *state =
338 100 : tevent_req_data(req,
339 : struct wb_parent_idmap_setup_state);
340 100 : struct wb_parent_idmap_config_dom *dom =
341 100 : &state->cfg->doms[state->dom_idx];
342 100 : struct tevent_req *subreq = NULL;
343 :
344 145 : next_domain:
345 145 : if (state->dom_idx == state->cfg->num_doms) {
346 : /*
347 : * We're done, so start the idmap child
348 : */
349 45 : setup_child(NULL, static_idmap_child, "log.winbindd", "idmap");
350 45 : static_parent_idmap_config.initialized = true;
351 45 : tevent_req_done(req);
352 45 : return;
353 : }
354 :
355 100 : if (strequal(dom->name, "*")) {
356 45 : state->dom_idx++;
357 45 : goto next_domain;
358 : }
359 :
360 55 : subreq = wb_lookupname_send(state,
361 : state->ev,
362 : dom->name,
363 : dom->name,
364 : "",
365 : LOOKUP_NAME_NO_NSS);
366 55 : if (tevent_req_nomem(subreq, req)) {
367 0 : return;
368 : }
369 55 : tevent_req_set_callback(subreq,
370 : wb_parent_idmap_setup_lookupname_done,
371 : req);
372 : }
373 :
374 55 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
375 : {
376 0 : struct tevent_req *req =
377 55 : tevent_req_callback_data(subreq,
378 : struct tevent_req);
379 0 : struct wb_parent_idmap_setup_state *state =
380 55 : tevent_req_data(req,
381 : struct wb_parent_idmap_setup_state);
382 55 : struct wb_parent_idmap_config_dom *dom =
383 55 : &state->cfg->doms[state->dom_idx];
384 0 : enum lsa_SidType type;
385 0 : NTSTATUS status;
386 :
387 55 : status = wb_lookupname_recv(subreq, &dom->sid, &type);
388 55 : TALLOC_FREE(subreq);
389 55 : if (!NT_STATUS_IS_OK(status)) {
390 0 : DBG_ERR("Lookup domain name '%s' failed '%s'\n",
391 : dom->name,
392 : nt_errstr(status));
393 :
394 0 : state->dom_idx++;
395 0 : wb_parent_idmap_setup_lookupname_next(req);
396 0 : return;
397 : }
398 :
399 55 : if (type != SID_NAME_DOMAIN) {
400 0 : struct dom_sid_buf buf;
401 :
402 0 : DBG_ERR("SID %s for idmap domain name '%s' "
403 : "not a domain SID\n",
404 : dom_sid_str_buf(&dom->sid, &buf),
405 : dom->name);
406 :
407 0 : ZERO_STRUCT(dom->sid);
408 : }
409 :
410 55 : state->dom_idx++;
411 55 : wb_parent_idmap_setup_lookupname_next(req);
412 :
413 55 : return;
414 : }
415 :
416 116807 : NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
417 : const struct wb_parent_idmap_config **_cfg)
418 : {
419 116807 : const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
420 0 : NTSTATUS status;
421 :
422 116807 : *_cfg = NULL;
423 :
424 116807 : if (tevent_req_is_nterror(req, &status)) {
425 0 : tevent_req_received(req);
426 0 : return status;
427 : }
428 :
429 : /*
430 : * Note state->cfg is already set to NULL by
431 : * wb_parent_idmap_setup_cleanup()
432 : */
433 116807 : *_cfg = cfg;
434 116807 : tevent_req_received(req);
435 116807 : return NT_STATUS_OK;
436 : }
|