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 = NULL;
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 NTSTATUS init_idmap_child(TALLOC_CTX *mem_ctx)
75 struct tevent_req *subreq = NULL;
77 if (static_idmap_child != NULL) {
78 DBG_ERR("idmap child already allocated\n");
79 return NT_STATUS_INTERNAL_ERROR;
82 static_idmap_child = talloc_zero(mem_ctx, struct winbindd_child);
83 if (static_idmap_child == NULL) {
84 return NT_STATUS_NO_MEMORY;
87 subreq = wb_parent_idmap_setup_send(static_idmap_child,
88 global_event_context());
91 * This is only an optimization, so we're free to
94 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
95 return NT_STATUS_NO_MEMORY;
97 tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
98 DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
102 static void init_idmap_child_done(struct tevent_req *subreq)
104 const struct wb_parent_idmap_config *cfg = NULL;
107 status = wb_parent_idmap_setup_recv(subreq, &cfg);
109 if (!NT_STATUS_IS_OK(status)) {
111 * This is only an optimization, so we're free to
114 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
119 DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
122 struct wb_parent_idmap_setup_state {
123 struct tevent_context *ev;
124 struct wb_parent_idmap_config *cfg;
128 static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
129 enum tevent_req_state req_state)
131 struct wb_parent_idmap_setup_state *state =
133 struct wb_parent_idmap_setup_state);
135 if (req_state == TEVENT_REQ_DONE) {
140 if (state->cfg == NULL) {
144 state->cfg->num_doms = 0;
145 state->cfg->initialized = false;
146 TALLOC_FREE(state->cfg->doms);
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,
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);
156 struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
157 struct tevent_context *ev)
159 struct tevent_req *req = NULL;
160 struct wb_parent_idmap_setup_state *state = NULL;
161 struct tevent_req *subreq = NULL;
163 req = tevent_req_create(mem_ctx, &state,
164 struct wb_parent_idmap_setup_state);
168 *state = (struct wb_parent_idmap_setup_state) {
170 .cfg = &static_parent_idmap_config,
174 if (state->cfg->initialized) {
175 tevent_req_done(req);
176 return tevent_req_post(req, ev);
179 if (state->cfg->queue == NULL) {
180 state->cfg->queue = tevent_queue_create(NULL,
181 "wb_parent_idmap_config_queue");
182 if (tevent_req_nomem(state->cfg->queue, req)) {
183 return tevent_req_post(req, ev);
187 subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
188 if (tevent_req_nomem(subreq, req)) {
189 return tevent_req_post(req, ev);
191 tevent_req_set_callback(subreq,
192 wb_parent_idmap_setup_queue_wait_done,
198 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
200 struct tevent_req *req =
201 tevent_req_callback_data(subreq,
203 struct wb_parent_idmap_setup_state *state =
205 struct wb_parent_idmap_setup_state);
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.
213 ok = tevent_queue_wait_recv(subreq);
215 DBG_ERR("tevent_queue_wait_recv() failed\n");
216 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
220 if (state->cfg->num_doms != 0) {
222 * If we're not the first one we're done.
224 tevent_req_done(req);
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.
234 tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
237 * Put the passdb idmap domain first. We always need to try
240 state->cfg->doms = talloc_zero_array(NULL,
241 struct wb_parent_idmap_config_dom,
243 if (tevent_req_nomem(state->cfg->doms, req)) {
246 state->cfg->doms[0].low_id = 0;
247 state->cfg->doms[0].high_id = UINT_MAX;
248 state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
249 get_global_sam_name());
250 if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
253 state->cfg->num_doms += 1;
255 lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
256 if (!tevent_req_is_in_progress(req)) {
260 wb_parent_idmap_setup_lookupname_next(req);
263 static bool wb_parent_idmap_setup_scan_config(const char *domname,
266 struct tevent_req *req =
267 talloc_get_type_abort(private_data,
269 struct wb_parent_idmap_setup_state *state =
271 struct wb_parent_idmap_setup_state);
272 struct wb_parent_idmap_config_dom *map = NULL;
275 unsigned low_id, high_id;
278 range = idmap_config_const_string(domname, "range", NULL);
280 DBG_DEBUG("No range for domain %s found\n", domname);
284 ret = sscanf(range, "%u - %u", &low_id, &high_id);
286 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
291 if (low_id > high_id) {
292 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
293 low_id, high_id, domname);
297 for (i=0; i<state->cfg->num_doms; i++) {
298 if (strequal(domname, state->cfg->doms[i].name)) {
299 map = &state->cfg->doms[i];
305 struct wb_parent_idmap_config_dom *tmp;
308 name = talloc_strdup(state, domname);
310 DBG_ERR("talloc failed\n");
314 tmp = talloc_realloc(
315 NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
316 state->cfg->num_doms+1);
318 DBG_ERR("talloc failed\n");
321 state->cfg->doms = tmp;
323 map = &state->cfg->doms[state->cfg->num_doms];
324 state->cfg->num_doms += 1;
326 map->name = talloc_move(state->cfg->doms, &name);
329 map->low_id = low_id;
330 map->high_id = high_id;
335 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
337 struct wb_parent_idmap_setup_state *state =
339 struct wb_parent_idmap_setup_state);
340 struct wb_parent_idmap_config_dom *dom =
341 &state->cfg->doms[state->dom_idx];
342 struct tevent_req *subreq = NULL;
345 if (state->dom_idx == state->cfg->num_doms) {
347 * We're done, so start the idmap child
349 setup_child(NULL, static_idmap_child, "log.winbindd", "idmap");
350 static_parent_idmap_config.initialized = true;
351 tevent_req_done(req);
355 if (strequal(dom->name, "*")) {
360 subreq = wb_lookupname_send(state,
366 if (tevent_req_nomem(subreq, req)) {
369 tevent_req_set_callback(subreq,
370 wb_parent_idmap_setup_lookupname_done,
374 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
376 struct tevent_req *req =
377 tevent_req_callback_data(subreq,
379 struct wb_parent_idmap_setup_state *state =
381 struct wb_parent_idmap_setup_state);
382 struct wb_parent_idmap_config_dom *dom =
383 &state->cfg->doms[state->dom_idx];
384 enum lsa_SidType type;
387 status = wb_lookupname_recv(subreq, &dom->sid, &type);
389 if (!NT_STATUS_IS_OK(status)) {
390 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
395 wb_parent_idmap_setup_lookupname_next(req);
399 if (type != SID_NAME_DOMAIN) {
400 struct dom_sid_buf buf;
402 DBG_ERR("SID %s for idmap domain name '%s' "
403 "not a domain SID\n",
404 dom_sid_str_buf(&dom->sid, &buf),
407 ZERO_STRUCT(dom->sid);
411 wb_parent_idmap_setup_lookupname_next(req);
416 NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
417 const struct wb_parent_idmap_config **_cfg)
419 const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
424 if (tevent_req_is_nterror(req, &status)) {
425 tevent_req_received(req);
430 * Note state->cfg is already set to NULL by
431 * wb_parent_idmap_setup_cleanup()
434 tevent_req_received(req);