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