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"
26 #include "passdb/lookup_sid.h"
28 struct wb_xids2sids_dom_map
{
36 * Map idmap ranges to domain names, taken from smb.conf. This is
37 * stored in the parent winbind and used to assemble xid2sid calls
38 * into per-idmap-domain chunks.
40 static struct wb_xids2sids_dom_map
*dom_maps
;
42 static bool wb_xids2sids_add_dom(const char *domname
,
45 struct wb_xids2sids_dom_map
*map
= NULL
;
46 size_t num_maps
= talloc_array_length(dom_maps
);
49 unsigned low_id
, high_id
;
52 range
= idmap_config_const_string(domname
, "range", NULL
);
54 DBG_DEBUG("No range for domain %s found\n", domname
);
58 ret
= sscanf(range
, "%u - %u", &low_id
, &high_id
);
60 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
65 if (low_id
> high_id
) {
66 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
67 low_id
, high_id
, domname
);
71 for (i
=0; i
<num_maps
; i
++) {
72 if (strequal(domname
, dom_maps
[i
].name
)) {
79 struct wb_xids2sids_dom_map
*tmp
;
82 name
= talloc_strdup(talloc_tos(), domname
);
84 DBG_DEBUG("talloc failed\n");
89 NULL
, dom_maps
, struct wb_xids2sids_dom_map
,
97 map
= &dom_maps
[num_maps
];
99 map
->name
= talloc_move(dom_maps
, &name
);
102 map
->low_id
= low_id
;
103 map
->high_id
= high_id
;
108 struct wb_xids2sids_init_dom_maps_state
{
109 struct tevent_context
*ev
;
110 struct tevent_req
*req
;
114 static void wb_xids2sids_init_dom_maps_lookupname_next(
115 struct wb_xids2sids_init_dom_maps_state
*state
);
117 static void wb_xids2sids_init_dom_maps_lookupname_done(
118 struct tevent_req
*subreq
);
120 static struct tevent_req
*wb_xids2sids_init_dom_maps_send(
121 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
)
123 struct tevent_req
*req
= NULL
;
124 struct wb_xids2sids_init_dom_maps_state
*state
= NULL
;
126 req
= tevent_req_create(mem_ctx
, &state
,
127 struct wb_xids2sids_init_dom_maps_state
);
131 *state
= (struct wb_xids2sids_init_dom_maps_state
) {
137 if (dom_maps
!= NULL
) {
138 tevent_req_done(req
);
139 return tevent_req_post(req
, ev
);
142 * Put the passdb idmap domain first. We always need to try
146 dom_maps
= talloc_zero_array(NULL
, struct wb_xids2sids_dom_map
, 1);
147 if (tevent_req_nomem(dom_maps
, req
)) {
148 return tevent_req_post(req
, ev
);
150 dom_maps
[0].low_id
= 0;
151 dom_maps
[0].high_id
= UINT_MAX
;
152 dom_maps
[0].name
= talloc_strdup(dom_maps
, get_global_sam_name());
153 if (tevent_req_nomem(dom_maps
[0].name
, req
)) {
154 TALLOC_FREE(dom_maps
);
155 return tevent_req_post(req
, ev
);
158 lp_scan_idmap_domains(wb_xids2sids_add_dom
, NULL
);
160 wb_xids2sids_init_dom_maps_lookupname_next(state
);
161 if (!tevent_req_is_in_progress(req
)) {
162 tevent_req_post(req
, ev
);
167 static void wb_xids2sids_init_dom_maps_lookupname_next(
168 struct wb_xids2sids_init_dom_maps_state
*state
)
170 struct tevent_req
*subreq
= NULL
;
172 if (state
->dom_idx
== talloc_array_length(dom_maps
)) {
173 tevent_req_done(state
->req
);
177 if (strequal(dom_maps
[state
->dom_idx
].name
, "*")) {
179 if (state
->dom_idx
== talloc_array_length(dom_maps
)) {
180 tevent_req_done(state
->req
);
185 subreq
= wb_lookupname_send(state
,
187 dom_maps
[state
->dom_idx
].name
,
188 dom_maps
[state
->dom_idx
].name
,
191 if (tevent_req_nomem(subreq
, state
->req
)) {
194 tevent_req_set_callback(subreq
,
195 wb_xids2sids_init_dom_maps_lookupname_done
,
199 static void wb_xids2sids_init_dom_maps_lookupname_done(
200 struct tevent_req
*subreq
)
202 struct tevent_req
*req
= tevent_req_callback_data(
203 subreq
, struct tevent_req
);
204 struct wb_xids2sids_init_dom_maps_state
*state
= tevent_req_data(
205 req
, struct wb_xids2sids_init_dom_maps_state
);
206 enum lsa_SidType type
;
209 status
= wb_lookupname_recv(subreq
,
210 &dom_maps
[state
->dom_idx
].sid
,
213 if (!NT_STATUS_IS_OK(status
)) {
214 DBG_WARNING("Lookup domain name '%s' failed '%s'\n",
215 dom_maps
[state
->dom_idx
].name
,
219 wb_xids2sids_init_dom_maps_lookupname_next(state
);
223 if (type
!= SID_NAME_DOMAIN
) {
224 DBG_WARNING("SID %s for idmap domain name '%s' "
225 "not a domain SID\n",
226 sid_string_dbg(&dom_maps
[state
->dom_idx
].sid
),
227 dom_maps
[state
->dom_idx
].name
);
229 ZERO_STRUCT(dom_maps
[state
->dom_idx
].sid
);
233 wb_xids2sids_init_dom_maps_lookupname_next(state
);
238 static NTSTATUS
wb_xids2sids_init_dom_maps_recv(struct tevent_req
*req
)
240 return tevent_req_simple_recv_ntstatus(req
);
243 struct wb_xids2sids_dom_state
{
244 struct tevent_context
*ev
;
245 struct unixid
*all_xids
;
247 struct dom_sid
*all_sids
;
248 struct wb_xids2sids_dom_map
*dom_map
;
252 struct unixid
*dom_xids
;
253 struct dom_sid
*dom_sids
;
256 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
);
257 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
);
259 static struct tevent_req
*wb_xids2sids_dom_send(
260 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
261 struct wb_xids2sids_dom_map
*dom_map
,
262 struct unixid
*xids
, size_t num_xids
, struct dom_sid
*sids
)
264 struct tevent_req
*req
, *subreq
;
265 struct wb_xids2sids_dom_state
*state
;
266 struct winbindd_child
*child
;
269 req
= tevent_req_create(mem_ctx
, &state
,
270 struct wb_xids2sids_dom_state
);
275 state
->all_xids
= xids
;
276 state
->num_all_xids
= num_xids
;
277 state
->all_sids
= sids
;
278 state
->dom_map
= dom_map
;
280 state
->dom_xids
= talloc_array(state
, struct unixid
, num_xids
);
281 if (tevent_req_nomem(state
->dom_xids
, req
)) {
282 return tevent_req_post(req
, ev
);
284 state
->dom_sids
= talloc_array(state
, struct dom_sid
, num_xids
);
285 if (tevent_req_nomem(state
->dom_sids
, req
)) {
286 return tevent_req_post(req
, ev
);
289 for (i
=0; i
<num_xids
; i
++) {
290 struct unixid id
= state
->all_xids
[i
];
292 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
296 if (!is_null_sid(&state
->all_sids
[i
])) {
300 state
->dom_xids
[state
->num_dom_xids
++] = id
;
303 if (state
->num_dom_xids
== 0) {
304 tevent_req_done(req
);
305 return tevent_req_post(req
, ev
);
308 child
= idmap_child();
309 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
310 state
, ev
, child
->binding_handle
, dom_map
->name
, dom_map
->sid
,
311 state
->num_dom_xids
, state
->dom_xids
, state
->dom_sids
);
312 if (tevent_req_nomem(subreq
, req
)) {
313 return tevent_req_post(req
, ev
);
315 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
319 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
)
321 struct tevent_req
*req
= tevent_req_callback_data(
322 subreq
, struct tevent_req
);
323 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
324 req
, struct wb_xids2sids_dom_state
);
325 struct wb_xids2sids_dom_map
*dom_map
= state
->dom_map
;
326 NTSTATUS status
, result
;
330 status
= dcerpc_wbint_UnixIDs2Sids_recv(subreq
, state
, &result
);
332 if (tevent_req_nterror(req
, status
)) {
336 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
337 !state
->tried_dclookup
) {
339 subreq
= wb_dsgetdcname_send(
340 state
, state
->ev
, state
->dom_map
->name
, NULL
, NULL
,
342 if (tevent_req_nomem(subreq
, req
)) {
345 tevent_req_set_callback(subreq
, wb_xids2sids_dom_gotdc
, req
);
349 if (!NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
) &&
350 tevent_req_nterror(req
, result
)) {
356 for (i
=0; i
<state
->num_all_xids
; i
++) {
357 struct unixid id
= state
->all_xids
[i
];
359 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
363 if (!is_null_sid(&state
->all_sids
[i
])) {
368 sid_copy(&state
->all_sids
[i
], &state
->dom_sids
[dom_sid_idx
]);
371 * Prime the cache after an xid2sid call. It's
372 * important that we use state->dom_xids for the xid
373 * value, not state->all_xids: state->all_xids carries
374 * what we asked for, e.g. a
375 * ID_TYPE_UID. state->dom_xids holds something the
376 * idmap child possibly changed to ID_TYPE_BOTH.
378 idmap_cache_set_sid2unixid(
379 &state
->all_sids
[i
], &state
->dom_xids
[dom_sid_idx
]);
384 tevent_req_done(req
);
387 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
)
389 struct tevent_req
*req
= tevent_req_callback_data(
390 subreq
, struct tevent_req
);
391 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
392 req
, struct wb_xids2sids_dom_state
);
393 struct winbindd_child
*child
= idmap_child();
394 struct netr_DsRGetDCNameInfo
*dcinfo
;
397 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
399 if (tevent_req_nterror(req
, status
)) {
403 state
->tried_dclookup
= true;
405 status
= wb_dsgetdcname_gencache_set(state
->dom_map
->name
, dcinfo
);
406 if (tevent_req_nterror(req
, status
)) {
410 child
= idmap_child();
411 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
412 state
, state
->ev
, child
->binding_handle
, state
->dom_map
->name
,
413 state
->dom_map
->sid
, state
->num_dom_xids
,
414 state
->dom_xids
, state
->dom_sids
);
415 if (tevent_req_nomem(subreq
, req
)) {
418 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
421 static NTSTATUS
wb_xids2sids_dom_recv(struct tevent_req
*req
)
423 return tevent_req_simple_recv_ntstatus(req
);
426 struct wb_xids2sids_state
{
427 struct tevent_context
*ev
;
430 struct dom_sid
*sids
;
435 static void wb_xids2sids_done(struct tevent_req
*subreq
);
436 static void wb_xids2sids_init_dom_maps_done(struct tevent_req
*subreq
);
438 struct tevent_req
*wb_xids2sids_send(TALLOC_CTX
*mem_ctx
,
439 struct tevent_context
*ev
,
443 struct tevent_req
*req
, *subreq
;
444 struct wb_xids2sids_state
*state
;
446 req
= tevent_req_create(mem_ctx
, &state
,
447 struct wb_xids2sids_state
);
453 state
->num_xids
= num_xids
;
455 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_xids
);
456 if (tevent_req_nomem(state
->sids
, req
)) {
457 return tevent_req_post(req
, ev
);
460 if (winbindd_use_idmap_cache()) {
463 for (i
=0; i
<num_xids
; i
++) {
467 switch (xids
[i
].type
) {
469 ok
= idmap_cache_find_uid2sid(
470 xids
[i
].id
, &sid
, &expired
);
473 ok
= idmap_cache_find_gid2sid(
474 xids
[i
].id
, &sid
, &expired
);
480 if (ok
&& !expired
) {
481 sid_copy(&state
->sids
[i
], &sid
);
486 subreq
= wb_xids2sids_init_dom_maps_send(
488 if (tevent_req_nomem(subreq
, req
)) {
489 return tevent_req_post(req
, ev
);
491 tevent_req_set_callback(subreq
, wb_xids2sids_init_dom_maps_done
, req
);
495 static void wb_xids2sids_init_dom_maps_done(struct tevent_req
*subreq
)
497 struct tevent_req
*req
= tevent_req_callback_data(
498 subreq
, struct tevent_req
);
499 struct wb_xids2sids_state
*state
= tevent_req_data(
500 req
, struct wb_xids2sids_state
);
504 status
= wb_xids2sids_init_dom_maps_recv(subreq
);
506 if (tevent_req_nterror(req
, status
)) {
510 num_domains
= talloc_array_length(dom_maps
);
511 if (num_domains
== 0) {
512 tevent_req_done(req
);
516 subreq
= wb_xids2sids_dom_send(
517 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
518 state
->xids
, state
->num_xids
, state
->sids
);
519 if (tevent_req_nomem(subreq
, req
)) {
522 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
526 static void wb_xids2sids_done(struct tevent_req
*subreq
)
528 struct tevent_req
*req
= tevent_req_callback_data(
529 subreq
, struct tevent_req
);
530 struct wb_xids2sids_state
*state
= tevent_req_data(
531 req
, struct wb_xids2sids_state
);
532 size_t num_domains
= talloc_array_length(dom_maps
);
535 status
= wb_xids2sids_dom_recv(subreq
);
537 if (tevent_req_nterror(req
, status
)) {
543 if (state
->dom_idx
>= num_domains
) {
544 tevent_req_done(req
);
548 subreq
= wb_xids2sids_dom_send(
549 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
550 state
->xids
, state
->num_xids
, state
->sids
);
551 if (tevent_req_nomem(subreq
, req
)) {
554 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
557 NTSTATUS
wb_xids2sids_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
558 struct dom_sid
**sids
)
560 struct wb_xids2sids_state
*state
= tevent_req_data(
561 req
, struct wb_xids2sids_state
);
564 if (tevent_req_is_nterror(req
, &status
)) {
565 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
569 *sids
= talloc_move(mem_ctx
, &state
->sids
);