2 * Unix SMB/CIFS implementation.
4 * Copyright (C) Volker Lendecke 2015
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "../libcli/security/security.h"
23 #include "idmap_cache.h"
24 #include "librpc/gen_ndr/ndr_winbind_c.h"
25 #include "librpc/gen_ndr/ndr_netlogon.h"
27 struct wb_xids2sids_dom_map
{
34 * Map idmap ranges to domain names, taken from smb.conf. This is
35 * stored in the parent winbind and used to assemble xid2sid calls
36 * into per-idmap-domain chunks.
38 static struct wb_xids2sids_dom_map
*dom_maps
;
40 static bool wb_xids2sids_add_dom(const char *domname
,
43 struct wb_xids2sids_dom_map
*map
= NULL
;
44 size_t num_maps
= talloc_array_length(dom_maps
);
48 unsigned low_id
, high_id
;
51 config_option
= talloc_asprintf(
52 talloc_tos(), "idmap config %s", domname
);
53 if (config_option
== NULL
) {
56 range
= lp_parm_const_string(-1, config_option
, "range", NULL
);
57 TALLOC_FREE(config_option
);
60 DBG_DEBUG("No range for domain %s found\n", domname
);
64 ret
= sscanf(range
, "%u - %u", &low_id
, &high_id
);
66 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
71 if (low_id
> high_id
) {
72 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
73 low_id
, high_id
, domname
);
77 for (i
=0; i
<num_maps
; i
++) {
78 if (strequal(domname
, dom_maps
[i
].name
)) {
85 struct wb_xids2sids_dom_map
*tmp
;
88 name
= talloc_strdup(talloc_tos(), domname
);
90 DBG_DEBUG("talloc failed\n");
95 NULL
, dom_maps
, struct wb_xids2sids_dom_map
,
103 map
= &dom_maps
[num_maps
];
104 map
->name
= talloc_move(dom_maps
, &name
);
107 map
->low_id
= low_id
;
108 map
->high_id
= high_id
;
113 static void wb_xids2sids_init_dom_maps(void)
115 if (dom_maps
!= NULL
) {
120 * Put the passdb idmap domain first. We always need to try
124 dom_maps
= talloc_array(NULL
, struct wb_xids2sids_dom_map
, 1);
125 if (dom_maps
== NULL
) {
128 dom_maps
[0].low_id
= 0;
129 dom_maps
[0].high_id
= UINT_MAX
;
130 dom_maps
[0].name
= talloc_strdup(dom_maps
, get_global_sam_name());
131 if (dom_maps
[0].name
== NULL
) {
132 TALLOC_FREE(dom_maps
);
136 lp_scan_idmap_domains(wb_xids2sids_add_dom
, NULL
);
139 struct wb_xids2sids_dom_state
{
140 struct tevent_context
*ev
;
141 struct unixid
*all_xids
;
143 struct dom_sid
*all_sids
;
144 struct wb_xids2sids_dom_map
*dom_map
;
148 struct unixid
*dom_xids
;
149 struct dom_sid
*dom_sids
;
152 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
);
153 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
);
155 static struct tevent_req
*wb_xids2sids_dom_send(
156 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
157 struct wb_xids2sids_dom_map
*dom_map
,
158 struct unixid
*xids
, size_t num_xids
, struct dom_sid
*sids
)
160 struct tevent_req
*req
, *subreq
;
161 struct wb_xids2sids_dom_state
*state
;
162 struct winbindd_child
*child
;
165 req
= tevent_req_create(mem_ctx
, &state
,
166 struct wb_xids2sids_dom_state
);
171 state
->all_xids
= xids
;
172 state
->num_all_xids
= num_xids
;
173 state
->all_sids
= sids
;
174 state
->dom_map
= dom_map
;
176 state
->dom_xids
= talloc_array(state
, struct unixid
, num_xids
);
177 if (tevent_req_nomem(state
->dom_xids
, req
)) {
178 return tevent_req_post(req
, ev
);
180 state
->dom_sids
= talloc_array(state
, struct dom_sid
, num_xids
);
181 if (tevent_req_nomem(state
->dom_sids
, req
)) {
182 return tevent_req_post(req
, ev
);
185 for (i
=0; i
<num_xids
; i
++) {
186 struct unixid id
= state
->all_xids
[i
];
188 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
192 if (!is_null_sid(&state
->all_sids
[i
])) {
197 state
->dom_xids
[state
->num_dom_xids
++] = id
;
200 if (state
->num_dom_xids
== 0) {
201 tevent_req_done(req
);
202 return tevent_req_post(req
, ev
);
205 child
= idmap_child();
206 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
207 state
, ev
, child
->binding_handle
, dom_map
->name
,
208 state
->num_dom_xids
, state
->dom_xids
, state
->dom_sids
);
209 if (tevent_req_nomem(subreq
, req
)) {
210 return tevent_req_post(req
, ev
);
212 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
216 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
)
218 struct tevent_req
*req
= tevent_req_callback_data(
219 subreq
, struct tevent_req
);
220 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
221 req
, struct wb_xids2sids_dom_state
);
222 struct wb_xids2sids_dom_map
*dom_map
= state
->dom_map
;
223 NTSTATUS status
, result
;
227 status
= dcerpc_wbint_UnixIDs2Sids_recv(subreq
, state
, &result
);
229 if (tevent_req_nterror(req
, status
)) {
233 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
234 !state
->tried_dclookup
) {
236 subreq
= wb_dsgetdcname_send(
237 state
, state
->ev
, state
->dom_map
->name
, NULL
, NULL
,
239 if (tevent_req_nomem(subreq
, req
)) {
242 tevent_req_set_callback(subreq
, wb_xids2sids_dom_gotdc
, req
);
246 if (!NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
) &&
247 tevent_req_nterror(req
, result
)) {
253 for (i
=0; i
<state
->num_all_xids
; i
++) {
254 struct unixid id
= state
->all_xids
[i
];
256 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
260 if (!is_null_sid(&state
->all_sids
[i
])) {
265 sid_copy(&state
->all_sids
[i
], &state
->dom_sids
[dom_sid_idx
++]);
268 tevent_req_done(req
);
271 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
)
273 struct tevent_req
*req
= tevent_req_callback_data(
274 subreq
, struct tevent_req
);
275 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
276 req
, struct wb_xids2sids_dom_state
);
277 struct winbindd_child
*child
= idmap_child();
278 struct netr_DsRGetDCNameInfo
*dcinfo
;
281 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
283 if (tevent_req_nterror(req
, status
)) {
287 state
->tried_dclookup
= true;
289 status
= wb_dsgetdcname_gencache_set(state
->dom_map
->name
, dcinfo
);
290 if (tevent_req_nterror(req
, status
)) {
294 child
= idmap_child();
295 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
296 state
, state
->ev
, child
->binding_handle
, state
->dom_map
->name
,
297 state
->num_dom_xids
, state
->dom_xids
, state
->dom_sids
);
298 if (tevent_req_nomem(subreq
, req
)) {
301 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
304 static NTSTATUS
wb_xids2sids_dom_recv(struct tevent_req
*req
)
306 return tevent_req_simple_recv_ntstatus(req
);
309 struct wb_xids2sids_state
{
310 struct tevent_context
*ev
;
313 struct dom_sid
*sids
;
318 static void wb_xids2sids_done(struct tevent_req
*subreq
);
320 struct tevent_req
*wb_xids2sids_send(TALLOC_CTX
*mem_ctx
,
321 struct tevent_context
*ev
,
325 struct tevent_req
*req
, *subreq
;
326 struct wb_xids2sids_state
*state
;
329 req
= tevent_req_create(mem_ctx
, &state
,
330 struct wb_xids2sids_state
);
336 state
->num_xids
= num_xids
;
338 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_xids
);
339 if (tevent_req_nomem(state
->sids
, req
)) {
340 return tevent_req_post(req
, ev
);
343 wb_xids2sids_init_dom_maps();
344 num_domains
= talloc_array_length(dom_maps
);
346 if (num_domains
== 0) {
347 tevent_req_done(req
);
348 return tevent_req_post(req
, ev
);
351 subreq
= wb_xids2sids_dom_send(
352 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
353 state
->xids
, state
->num_xids
, state
->sids
);
354 if (tevent_req_nomem(subreq
, req
)) {
355 return tevent_req_post(req
, ev
);
357 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
361 static void wb_xids2sids_done(struct tevent_req
*subreq
)
363 struct tevent_req
*req
= tevent_req_callback_data(
364 subreq
, struct tevent_req
);
365 struct wb_xids2sids_state
*state
= tevent_req_data(
366 req
, struct wb_xids2sids_state
);
367 size_t num_domains
= talloc_array_length(dom_maps
);
370 status
= wb_xids2sids_dom_recv(subreq
);
372 if (tevent_req_nterror(req
, status
)) {
378 if (state
->dom_idx
>= num_domains
) {
379 tevent_req_done(req
);
383 subreq
= wb_xids2sids_dom_send(
384 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
385 state
->xids
, state
->num_xids
, state
->sids
);
386 if (tevent_req_nomem(subreq
, req
)) {
389 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
392 NTSTATUS
wb_xids2sids_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
393 struct dom_sid
**sids
)
395 struct wb_xids2sids_state
*state
= tevent_req_data(
396 req
, struct wb_xids2sids_state
);
399 if (tevent_req_is_nterror(req
, &status
)) {
400 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
404 *sids
= talloc_move(mem_ctx
, &state
->sids
);