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
) && type
== SID_NAME_UNKNOWN
) {
390 status
= NT_STATUS_NONE_MAPPED
;
392 if (!NT_STATUS_IS_OK(status
)) {
393 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
398 wb_parent_idmap_setup_lookupname_next(req
);
402 if (type
!= SID_NAME_DOMAIN
) {
403 struct dom_sid_buf buf
;
405 DBG_ERR("SID %s for idmap domain name '%s' "
406 "not a domain SID\n",
407 dom_sid_str_buf(&dom
->sid
, &buf
),
410 ZERO_STRUCT(dom
->sid
);
414 wb_parent_idmap_setup_lookupname_next(req
);
419 NTSTATUS
wb_parent_idmap_setup_recv(struct tevent_req
*req
,
420 const struct wb_parent_idmap_config
**_cfg
)
422 const struct wb_parent_idmap_config
*cfg
= &static_parent_idmap_config
;
427 if (tevent_req_is_nterror(req
, &status
)) {
428 tevent_req_received(req
);
433 * Note state->cfg is already set to NULL by
434 * wb_parent_idmap_setup_cleanup()
437 tevent_req_received(req
);