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 const struct winbindd_child_dispatch_table idmap_dispatch_table
[] = {
74 .struct_cmd
= WINBINDD_DUAL_NDRCMD
,
75 .struct_fn
= winbindd_dual_ndrcmd
,
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());
91 * This is only an optimization, so we're free to
94 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
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
;
106 status
= wb_parent_idmap_setup_recv(subreq
, &cfg
);
108 if (!NT_STATUS_IS_OK(status
)) {
110 * This is only an optimization, so we're free to
113 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
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
;
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
=
132 struct wb_parent_idmap_setup_state
);
134 if (req_state
== TEVENT_REQ_DONE
) {
139 if (state
->cfg
== NULL
) {
143 state
->cfg
->num_doms
= 0;
144 TALLOC_FREE(state
->cfg
->doms
);
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
,
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
);
166 *state
= (struct wb_parent_idmap_setup_state
) {
168 .cfg
= &static_parent_idmap_config
,
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
,
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
,
196 struct wb_parent_idmap_setup_state
*state
=
198 struct wb_parent_idmap_setup_state
);
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
);
208 DBG_ERR("tevent_queue_wait_recv() failed\n");
209 tevent_req_nterror(req
, NT_STATUS_INTERNAL_ERROR
);
213 if (state
->cfg
->num_doms
!= 0) {
215 * If we're not the first one we're done.
217 tevent_req_done(req
);
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
233 state
->cfg
->doms
= talloc_zero_array(NULL
,
234 struct wb_parent_idmap_config_dom
,
236 if (tevent_req_nomem(state
->cfg
->doms
, req
)) {
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
)) {
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
)) {
253 wb_parent_idmap_setup_lookupname_next(req
);
256 static bool wb_parent_idmap_setup_scan_config(const char *domname
,
259 struct tevent_req
*req
=
260 talloc_get_type_abort(private_data
,
262 struct wb_parent_idmap_setup_state
*state
=
264 struct wb_parent_idmap_setup_state
);
265 struct wb_parent_idmap_config_dom
*map
= NULL
;
268 unsigned low_id
, high_id
;
271 range
= idmap_config_const_string(domname
, "range", NULL
);
273 DBG_DEBUG("No range for domain %s found\n", domname
);
277 ret
= sscanf(range
, "%u - %u", &low_id
, &high_id
);
279 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
284 if (low_id
> high_id
) {
285 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
286 low_id
, high_id
, domname
);
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
];
298 struct wb_parent_idmap_config_dom
*tmp
;
301 name
= talloc_strdup(state
, domname
);
303 DBG_ERR("talloc failed\n");
307 tmp
= talloc_realloc(
308 NULL
, state
->cfg
->doms
, struct wb_parent_idmap_config_dom
,
309 state
->cfg
->num_doms
+1);
311 DBG_ERR("talloc failed\n");
314 state
->cfg
->doms
= tmp
;
316 map
= &state
->cfg
->doms
[state
->cfg
->num_doms
];
317 state
->cfg
->num_doms
+= 1;
319 map
->name
= talloc_move(state
->cfg
->doms
, &name
);
322 map
->low_id
= low_id
;
323 map
->high_id
= high_id
;
328 static void wb_parent_idmap_setup_lookupname_next(struct tevent_req
*req
)
330 struct wb_parent_idmap_setup_state
*state
=
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
;
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
);
349 if (strequal(dom
->name
, "*")) {
354 subreq
= wb_lookupname_send(state
,
360 if (tevent_req_nomem(subreq
, req
)) {
363 tevent_req_set_callback(subreq
,
364 wb_parent_idmap_setup_lookupname_done
,
368 static void wb_parent_idmap_setup_lookupname_done(struct tevent_req
*subreq
)
370 struct tevent_req
*req
=
371 tevent_req_callback_data(subreq
,
373 struct wb_parent_idmap_setup_state
*state
=
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
;
381 status
= wb_lookupname_recv(subreq
, &dom
->sid
, &type
);
383 if (!NT_STATUS_IS_OK(status
)) {
384 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
389 wb_parent_idmap_setup_lookupname_next(req
);
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
),
401 ZERO_STRUCT(dom
->sid
);
405 wb_parent_idmap_setup_lookupname_next(req
);
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
;
418 if (tevent_req_is_nterror(req
, &status
)) {
419 tevent_req_received(req
);
424 * Note state->cfg is already set to NULL by
425 * wb_parent_idmap_setup_cleanup()
428 tevent_req_received(req
);