python/samba/tests: add test cases for s3/registry init funcs
[Samba.git] / source3 / winbindd / winbindd_idmap.c
blob79775a03c8b7d5c52f64bd994821df410bf1b6db
1 /*
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/>.
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"
30 #undef DBGC_CLASS
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) {
50 return true;
53 return false;
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 const struct winbindd_child_dispatch_table idmap_dispatch_table[] = {
73 .name = "NDRCMD",
74 .struct_cmd = WINBINDD_DUAL_NDRCMD,
75 .struct_fn = winbindd_dual_ndrcmd,
76 },{
77 .name = NULL,
81 static void init_idmap_child_done(struct tevent_req *subreq);
83 void init_idmap_child(void)
85 struct tevent_req *subreq = NULL;
87 subreq = wb_parent_idmap_setup_send(global_event_context(),
88 global_event_context());
89 if (subreq == NULL) {
91 * This is only an optimization, so we're free to
92 * to ignore errors
94 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
95 return;
97 tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
98 DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
101 static void init_idmap_child_done(struct tevent_req *subreq)
103 const struct wb_parent_idmap_config *cfg = NULL;
104 NTSTATUS status;
106 status = wb_parent_idmap_setup_recv(subreq, &cfg);
107 TALLOC_FREE(subreq);
108 if (!NT_STATUS_IS_OK(status)) {
110 * This is only an optimization, so we're free to
111 * to ignore errors
113 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
114 nt_errstr(status));
115 return;
118 DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
121 struct wb_parent_idmap_setup_state {
122 struct tevent_context *ev;
123 struct wb_parent_idmap_config *cfg;
124 size_t dom_idx;
127 static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
128 enum tevent_req_state req_state)
130 struct wb_parent_idmap_setup_state *state =
131 tevent_req_data(req,
132 struct wb_parent_idmap_setup_state);
134 if (req_state == TEVENT_REQ_DONE) {
135 state->cfg = NULL;
136 return;
139 if (state->cfg == NULL) {
140 return;
143 state->cfg->num_doms = 0;
144 TALLOC_FREE(state->cfg->doms);
145 state->cfg = NULL;
148 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
149 static bool wb_parent_idmap_setup_scan_config(const char *domname,
150 void *private_data);
151 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
152 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
154 struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
155 struct tevent_context *ev)
157 struct tevent_req *req = NULL;
158 struct wb_parent_idmap_setup_state *state = NULL;
159 struct tevent_req *subreq = NULL;
161 req = tevent_req_create(mem_ctx, &state,
162 struct wb_parent_idmap_setup_state);
163 if (req == NULL) {
164 return NULL;
166 *state = (struct wb_parent_idmap_setup_state) {
167 .ev = ev,
168 .cfg = &static_parent_idmap_config,
169 .dom_idx = 0,
172 if (state->cfg->queue == NULL) {
173 state->cfg->queue = tevent_queue_create(NULL,
174 "wb_parent_idmap_config_queue");
175 if (tevent_req_nomem(state->cfg->queue, req)) {
176 return tevent_req_post(req, ev);
180 subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
181 if (tevent_req_nomem(subreq, req)) {
182 return tevent_req_post(req, ev);
184 tevent_req_set_callback(subreq,
185 wb_parent_idmap_setup_queue_wait_done,
186 req);
188 return req;
191 static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
193 struct tevent_req *req =
194 tevent_req_callback_data(subreq,
195 struct tevent_req);
196 struct wb_parent_idmap_setup_state *state =
197 tevent_req_data(req,
198 struct wb_parent_idmap_setup_state);
199 bool ok;
202 * Note we don't call TALLOC_FREE(subreq) here in order to block the
203 * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
204 * will destroy it implicitly.
206 ok = tevent_queue_wait_recv(subreq);
207 if (!ok) {
208 DBG_ERR("tevent_queue_wait_recv() failed\n");
209 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
210 return;
213 if (state->cfg->num_doms != 0) {
215 * If we're not the first one we're done.
217 tevent_req_done(req);
218 return;
222 * From this point we start changing state->cfg,
223 * which is &static_parent_idmap_config,
224 * so we better setup a cleanup function
225 * to undo the changes on failure.
227 tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
230 * Put the passdb idmap domain first. We always need to try
231 * there first.
233 state->cfg->doms = talloc_zero_array(NULL,
234 struct wb_parent_idmap_config_dom,
236 if (tevent_req_nomem(state->cfg->doms, req)) {
237 return;
239 state->cfg->doms[0].low_id = 0;
240 state->cfg->doms[0].high_id = UINT_MAX;
241 state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
242 get_global_sam_name());
243 if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
244 return;
246 state->cfg->num_doms += 1;
248 lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
249 if (!tevent_req_is_in_progress(req)) {
250 return;
253 wb_parent_idmap_setup_lookupname_next(req);
256 static bool wb_parent_idmap_setup_scan_config(const char *domname,
257 void *private_data)
259 struct tevent_req *req =
260 talloc_get_type_abort(private_data,
261 struct tevent_req);
262 struct wb_parent_idmap_setup_state *state =
263 tevent_req_data(req,
264 struct wb_parent_idmap_setup_state);
265 struct wb_parent_idmap_config_dom *map = NULL;
266 size_t i;
267 const char *range;
268 unsigned low_id, high_id;
269 int ret;
271 range = idmap_config_const_string(domname, "range", NULL);
272 if (range == NULL) {
273 DBG_DEBUG("No range for domain %s found\n", domname);
274 return false;
277 ret = sscanf(range, "%u - %u", &low_id, &high_id);
278 if (ret != 2) {
279 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
280 range, domname);
281 return false;
284 if (low_id > high_id) {
285 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
286 low_id, high_id, domname);
287 return false;
290 for (i=0; i<state->cfg->num_doms; i++) {
291 if (strequal(domname, state->cfg->doms[i].name)) {
292 map = &state->cfg->doms[i];
293 break;
297 if (map == NULL) {
298 struct wb_parent_idmap_config_dom *tmp;
299 char *name;
301 name = talloc_strdup(state, domname);
302 if (name == NULL) {
303 DBG_ERR("talloc failed\n");
304 return false;
307 tmp = talloc_realloc(
308 NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
309 state->cfg->num_doms+1);
310 if (tmp == NULL) {
311 DBG_ERR("talloc failed\n");
312 return false;
314 state->cfg->doms = tmp;
316 map = &state->cfg->doms[state->cfg->num_doms];
317 state->cfg->num_doms += 1;
318 ZERO_STRUCTP(map);
319 map->name = talloc_move(state->cfg->doms, &name);
322 map->low_id = low_id;
323 map->high_id = high_id;
325 return false;
328 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
330 struct wb_parent_idmap_setup_state *state =
331 tevent_req_data(req,
332 struct wb_parent_idmap_setup_state);
333 struct wb_parent_idmap_config_dom *dom =
334 &state->cfg->doms[state->dom_idx];
335 struct tevent_req *subreq = NULL;
337 next_domain:
338 if (state->dom_idx == state->cfg->num_doms) {
340 * We're done, so start the idmap child
342 setup_child(NULL, &static_idmap_child,
343 idmap_dispatch_table,
344 "log.winbindd", "idmap");
345 tevent_req_done(req);
346 return;
349 if (strequal(dom->name, "*")) {
350 state->dom_idx++;
351 goto next_domain;
354 subreq = wb_lookupname_send(state,
355 state->ev,
356 dom->name,
357 dom->name,
359 LOOKUP_NAME_NO_NSS);
360 if (tevent_req_nomem(subreq, req)) {
361 return;
363 tevent_req_set_callback(subreq,
364 wb_parent_idmap_setup_lookupname_done,
365 req);
368 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
370 struct tevent_req *req =
371 tevent_req_callback_data(subreq,
372 struct tevent_req);
373 struct wb_parent_idmap_setup_state *state =
374 tevent_req_data(req,
375 struct wb_parent_idmap_setup_state);
376 struct wb_parent_idmap_config_dom *dom =
377 &state->cfg->doms[state->dom_idx];
378 enum lsa_SidType type;
379 NTSTATUS status;
381 status = wb_lookupname_recv(subreq, &dom->sid, &type);
382 TALLOC_FREE(subreq);
383 if (!NT_STATUS_IS_OK(status)) {
384 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
385 dom->name,
386 nt_errstr(status));
388 state->dom_idx++;
389 wb_parent_idmap_setup_lookupname_next(req);
390 return;
393 if (type != SID_NAME_DOMAIN) {
394 struct dom_sid_buf buf;
396 DBG_ERR("SID %s for idmap domain name '%s' "
397 "not a domain SID\n",
398 dom_sid_str_buf(&dom->sid, &buf),
399 dom->name);
401 ZERO_STRUCT(dom->sid);
404 state->dom_idx++;
405 wb_parent_idmap_setup_lookupname_next(req);
407 return;
410 NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
411 const struct wb_parent_idmap_config **_cfg)
413 const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
414 NTSTATUS status;
416 *_cfg = NULL;
418 if (tevent_req_is_nterror(req, &status)) {
419 tevent_req_received(req);
420 return status;
424 * Note state->cfg is already set to NULL by
425 * wb_parent_idmap_setup_cleanup()
427 *_cfg = cfg;
428 tevent_req_received(req);
429 return NT_STATUS_OK;