2 Unix SMB/CIFS implementation.
4 Async helpers for blocking functions
6 Copyright (C) Volker Lendecke 2005
7 Copyright (C) Gerald Carter 2006
8 Copyright (C) Simo Sorce 2007
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.
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.
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/>.
26 #include "../libcli/security/security.h"
27 #include "passdb/lookup_sid.h"
28 #include "lib/global_contexts.h"
31 #define DBGC_CLASS DBGC_WINBIND
33 static struct winbindd_child static_idmap_child;
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.
40 static struct wb_parent_idmap_config static_parent_idmap_config;
42 struct winbindd_child *idmap_child(void)
44 return &static_idmap_child;
47 bool is_idmap_child(const struct winbindd_child *child)
49 if (child == &static_idmap_child) {
56 pid_t idmap_child_pid(void)
58 return static_idmap_child.pid;
61 struct dcerpc_binding_handle *idmap_child_handle(void)
64 * The caller needs to use wb_parent_idmap_setup_send/recv
65 * before talking to the idmap child!
67 SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
68 return static_idmap_child.binding_handle;
71 static void init_idmap_child_done(struct tevent_req *subreq);
73 void init_idmap_child(void)
75 struct tevent_req *subreq = NULL;
77 subreq = wb_parent_idmap_setup_send(global_event_context(),
78 global_event_context());
81 * This is only an optimization, so we're free to
84 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
87 tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
88 DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
91 static void init_idmap_child_done(struct tevent_req *subreq)
93 const struct wb_parent_idmap_config *cfg = NULL;
96 status = wb_parent_idmap_setup_recv(subreq, &cfg);
98 if (!NT_STATUS_IS_OK(status)) {
100 * This is only an optimization, so we're free to
103 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
108 DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
111 struct wb_parent_idmap_setup_state {
112 struct tevent_context *ev;
113 struct wb_parent_idmap_config *cfg;
117 static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
118 enum tevent_req_state req_state)
120 struct wb_parent_idmap_setup_state *state =
122 struct wb_parent_idmap_setup_state);
124 if (req_state == TEVENT_REQ_DONE) {
129 if (state->cfg == NULL) {
133 state->cfg->num_doms = 0;
134 state->cfg->initialized = false;
135 TALLOC_FREE(state->cfg->doms);
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,
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);
145 struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
146 struct tevent_context *ev)
148 struct tevent_req *req = NULL;
149 struct wb_parent_idmap_setup_state *state = NULL;
150 struct tevent_req *subreq = NULL;
152 req = tevent_req_create(mem_ctx, &state,
153 struct wb_parent_idmap_setup_state);
157 *state = (struct wb_parent_idmap_setup_state) {
159 .cfg = &static_parent_idmap_config,
163 if (state->cfg->initialized) {
164 tevent_req_done(req);
165 return tevent_req_post(req, ev);
168 if (state->cfg->queue == NULL) {
169 state->cfg->queue = tevent_queue_create(NULL,
170 "wb_parent_idmap_config_queue");
171 if (tevent_req_nomem(state->cfg->queue, req)) {
172 return tevent_req_post(req, ev);
176 subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
177 if (tevent_req_nomem(subreq, req)) {
178 return tevent_req_post(req, ev);
180 tevent_req_set_callback(subreq,
181 wb_parent_idmap_setup_queue_wait_done,
187 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
189 struct tevent_req *req =
190 tevent_req_callback_data(subreq,
192 struct wb_parent_idmap_setup_state *state =
194 struct wb_parent_idmap_setup_state);
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.
202 ok = tevent_queue_wait_recv(subreq);
204 DBG_ERR("tevent_queue_wait_recv() failed\n");
205 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
209 if (state->cfg->num_doms != 0) {
211 * If we're not the first one we're done.
213 tevent_req_done(req);
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.
223 tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
226 * Put the passdb idmap domain first. We always need to try
229 state->cfg->doms = talloc_zero_array(NULL,
230 struct wb_parent_idmap_config_dom,
232 if (tevent_req_nomem(state->cfg->doms, req)) {
235 state->cfg->doms[0].low_id = 0;
236 state->cfg->doms[0].high_id = UINT_MAX;
237 state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
238 get_global_sam_name());
239 if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
242 state->cfg->num_doms += 1;
244 lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
245 if (!tevent_req_is_in_progress(req)) {
249 wb_parent_idmap_setup_lookupname_next(req);
252 static bool wb_parent_idmap_setup_scan_config(const char *domname,
255 struct tevent_req *req =
256 talloc_get_type_abort(private_data,
258 struct wb_parent_idmap_setup_state *state =
260 struct wb_parent_idmap_setup_state);
261 struct wb_parent_idmap_config_dom *map = NULL;
264 unsigned low_id, high_id;
267 range = idmap_config_const_string(domname, "range", NULL);
269 DBG_DEBUG("No range for domain %s found\n", domname);
273 ret = sscanf(range, "%u - %u", &low_id, &high_id);
275 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
280 if (low_id > high_id) {
281 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
282 low_id, high_id, domname);
286 for (i=0; i<state->cfg->num_doms; i++) {
287 if (strequal(domname, state->cfg->doms[i].name)) {
288 map = &state->cfg->doms[i];
294 struct wb_parent_idmap_config_dom *tmp;
297 name = talloc_strdup(state, domname);
299 DBG_ERR("talloc failed\n");
303 tmp = talloc_realloc(
304 NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
305 state->cfg->num_doms+1);
307 DBG_ERR("talloc failed\n");
310 state->cfg->doms = tmp;
312 map = &state->cfg->doms[state->cfg->num_doms];
313 state->cfg->num_doms += 1;
315 map->name = talloc_move(state->cfg->doms, &name);
318 map->low_id = low_id;
319 map->high_id = high_id;
324 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
326 struct wb_parent_idmap_setup_state *state =
328 struct wb_parent_idmap_setup_state);
329 struct wb_parent_idmap_config_dom *dom =
330 &state->cfg->doms[state->dom_idx];
331 struct tevent_req *subreq = NULL;
334 if (state->dom_idx == state->cfg->num_doms) {
336 * We're done, so start the idmap child
338 setup_child(NULL, &static_idmap_child, "log.winbindd", "idmap");
339 static_parent_idmap_config.initialized = true;
340 tevent_req_done(req);
344 if (strequal(dom->name, "*")) {
349 subreq = wb_lookupname_send(state,
355 if (tevent_req_nomem(subreq, req)) {
358 tevent_req_set_callback(subreq,
359 wb_parent_idmap_setup_lookupname_done,
363 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
365 struct tevent_req *req =
366 tevent_req_callback_data(subreq,
368 struct wb_parent_idmap_setup_state *state =
370 struct wb_parent_idmap_setup_state);
371 struct wb_parent_idmap_config_dom *dom =
372 &state->cfg->doms[state->dom_idx];
373 enum lsa_SidType type;
376 status = wb_lookupname_recv(subreq, &dom->sid, &type);
378 if (!NT_STATUS_IS_OK(status)) {
379 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
384 wb_parent_idmap_setup_lookupname_next(req);
388 if (type != SID_NAME_DOMAIN) {
389 struct dom_sid_buf buf;
391 DBG_ERR("SID %s for idmap domain name '%s' "
392 "not a domain SID\n",
393 dom_sid_str_buf(&dom->sid, &buf),
396 ZERO_STRUCT(dom->sid);
400 wb_parent_idmap_setup_lookupname_next(req);
405 NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
406 const struct wb_parent_idmap_config **_cfg)
408 const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
413 if (tevent_req_is_nterror(req, &status)) {
414 tevent_req_received(req);
419 * Note state->cfg is already set to NULL by
420 * wb_parent_idmap_setup_cleanup()
423 tevent_req_received(req);