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
,
190 if (tevent_req_nomem(subreq
, state
->req
)) {
193 tevent_req_set_callback(subreq
,
194 wb_xids2sids_init_dom_maps_lookupname_done
,
198 static void wb_xids2sids_init_dom_maps_lookupname_done(
199 struct tevent_req
*subreq
)
201 struct tevent_req
*req
= tevent_req_callback_data(
202 subreq
, struct tevent_req
);
203 struct wb_xids2sids_init_dom_maps_state
*state
= tevent_req_data(
204 req
, struct wb_xids2sids_init_dom_maps_state
);
205 enum lsa_SidType type
;
208 status
= wb_lookupname_recv(subreq
,
209 &dom_maps
[state
->dom_idx
].sid
,
212 if (!NT_STATUS_IS_OK(status
)) {
213 DBG_WARNING("Lookup domain name '%s' failed '%s'\n",
214 dom_maps
[state
->dom_idx
].name
,
218 wb_xids2sids_init_dom_maps_lookupname_next(state
);
222 if (type
!= SID_NAME_DOMAIN
) {
223 DBG_WARNING("SID %s for idmap domain name '%s' "
224 "not a domain SID\n",
225 sid_string_dbg(&dom_maps
[state
->dom_idx
].sid
),
226 dom_maps
[state
->dom_idx
].name
);
228 ZERO_STRUCT(dom_maps
[state
->dom_idx
].sid
);
232 wb_xids2sids_init_dom_maps_lookupname_next(state
);
237 static NTSTATUS
wb_xids2sids_init_dom_maps_recv(struct tevent_req
*req
)
239 return tevent_req_simple_recv_ntstatus(req
);
242 struct wb_xids2sids_dom_state
{
243 struct tevent_context
*ev
;
244 struct unixid
*all_xids
;
246 struct dom_sid
*all_sids
;
247 struct wb_xids2sids_dom_map
*dom_map
;
251 struct unixid
*dom_xids
;
252 struct dom_sid
*dom_sids
;
255 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
);
256 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
);
258 static struct tevent_req
*wb_xids2sids_dom_send(
259 TALLOC_CTX
*mem_ctx
, struct tevent_context
*ev
,
260 struct wb_xids2sids_dom_map
*dom_map
,
261 struct unixid
*xids
, size_t num_xids
, struct dom_sid
*sids
)
263 struct tevent_req
*req
, *subreq
;
264 struct wb_xids2sids_dom_state
*state
;
265 struct winbindd_child
*child
;
268 req
= tevent_req_create(mem_ctx
, &state
,
269 struct wb_xids2sids_dom_state
);
274 state
->all_xids
= xids
;
275 state
->num_all_xids
= num_xids
;
276 state
->all_sids
= sids
;
277 state
->dom_map
= dom_map
;
279 state
->dom_xids
= talloc_array(state
, struct unixid
, num_xids
);
280 if (tevent_req_nomem(state
->dom_xids
, req
)) {
281 return tevent_req_post(req
, ev
);
283 state
->dom_sids
= talloc_array(state
, struct dom_sid
, num_xids
);
284 if (tevent_req_nomem(state
->dom_sids
, req
)) {
285 return tevent_req_post(req
, ev
);
288 for (i
=0; i
<num_xids
; i
++) {
289 struct unixid id
= state
->all_xids
[i
];
291 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
295 if (!is_null_sid(&state
->all_sids
[i
])) {
299 state
->dom_xids
[state
->num_dom_xids
++] = id
;
302 if (state
->num_dom_xids
== 0) {
303 tevent_req_done(req
);
304 return tevent_req_post(req
, ev
);
307 child
= idmap_child();
308 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
309 state
, ev
, child
->binding_handle
, dom_map
->name
, dom_map
->sid
,
310 state
->num_dom_xids
, state
->dom_xids
, state
->dom_sids
);
311 if (tevent_req_nomem(subreq
, req
)) {
312 return tevent_req_post(req
, ev
);
314 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
318 static void wb_xids2sids_dom_done(struct tevent_req
*subreq
)
320 struct tevent_req
*req
= tevent_req_callback_data(
321 subreq
, struct tevent_req
);
322 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
323 req
, struct wb_xids2sids_dom_state
);
324 struct wb_xids2sids_dom_map
*dom_map
= state
->dom_map
;
325 NTSTATUS status
, result
;
329 status
= dcerpc_wbint_UnixIDs2Sids_recv(subreq
, state
, &result
);
331 if (tevent_req_nterror(req
, status
)) {
335 if (NT_STATUS_EQUAL(result
, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
) &&
336 !state
->tried_dclookup
) {
338 subreq
= wb_dsgetdcname_send(
339 state
, state
->ev
, state
->dom_map
->name
, NULL
, NULL
,
341 if (tevent_req_nomem(subreq
, req
)) {
344 tevent_req_set_callback(subreq
, wb_xids2sids_dom_gotdc
, req
);
348 if (!NT_STATUS_EQUAL(result
, NT_STATUS_NONE_MAPPED
) &&
349 tevent_req_nterror(req
, result
)) {
355 for (i
=0; i
<state
->num_all_xids
; i
++) {
356 struct unixid id
= state
->all_xids
[i
];
358 if ((id
.id
< dom_map
->low_id
) || (id
.id
> dom_map
->high_id
)) {
362 if (!is_null_sid(&state
->all_sids
[i
])) {
367 sid_copy(&state
->all_sids
[i
], &state
->dom_sids
[dom_sid_idx
]);
370 * Prime the cache after an xid2sid call. It's
371 * important that we use state->dom_xids for the xid
372 * value, not state->all_xids: state->all_xids carries
373 * what we asked for, e.g. a
374 * ID_TYPE_UID. state->dom_xids holds something the
375 * idmap child possibly changed to ID_TYPE_BOTH.
377 idmap_cache_set_sid2unixid(
378 &state
->all_sids
[i
], &state
->dom_xids
[dom_sid_idx
]);
383 tevent_req_done(req
);
386 static void wb_xids2sids_dom_gotdc(struct tevent_req
*subreq
)
388 struct tevent_req
*req
= tevent_req_callback_data(
389 subreq
, struct tevent_req
);
390 struct wb_xids2sids_dom_state
*state
= tevent_req_data(
391 req
, struct wb_xids2sids_dom_state
);
392 struct winbindd_child
*child
= idmap_child();
393 struct netr_DsRGetDCNameInfo
*dcinfo
;
396 status
= wb_dsgetdcname_recv(subreq
, state
, &dcinfo
);
398 if (tevent_req_nterror(req
, status
)) {
402 state
->tried_dclookup
= true;
404 status
= wb_dsgetdcname_gencache_set(state
->dom_map
->name
, dcinfo
);
405 if (tevent_req_nterror(req
, status
)) {
409 child
= idmap_child();
410 subreq
= dcerpc_wbint_UnixIDs2Sids_send(
411 state
, state
->ev
, child
->binding_handle
, state
->dom_map
->name
,
412 state
->dom_map
->sid
, state
->num_dom_xids
,
413 state
->dom_xids
, state
->dom_sids
);
414 if (tevent_req_nomem(subreq
, req
)) {
417 tevent_req_set_callback(subreq
, wb_xids2sids_dom_done
, req
);
420 static NTSTATUS
wb_xids2sids_dom_recv(struct tevent_req
*req
)
422 return tevent_req_simple_recv_ntstatus(req
);
425 struct wb_xids2sids_state
{
426 struct tevent_context
*ev
;
429 struct dom_sid
*sids
;
434 static void wb_xids2sids_done(struct tevent_req
*subreq
);
435 static void wb_xids2sids_init_dom_maps_done(struct tevent_req
*subreq
);
437 struct tevent_req
*wb_xids2sids_send(TALLOC_CTX
*mem_ctx
,
438 struct tevent_context
*ev
,
442 struct tevent_req
*req
, *subreq
;
443 struct wb_xids2sids_state
*state
;
445 req
= tevent_req_create(mem_ctx
, &state
,
446 struct wb_xids2sids_state
);
452 state
->num_xids
= num_xids
;
454 state
->sids
= talloc_zero_array(state
, struct dom_sid
, num_xids
);
455 if (tevent_req_nomem(state
->sids
, req
)) {
456 return tevent_req_post(req
, ev
);
459 if (winbindd_use_idmap_cache()) {
462 for (i
=0; i
<num_xids
; i
++) {
466 switch (xids
[i
].type
) {
468 ok
= idmap_cache_find_uid2sid(
469 xids
[i
].id
, &sid
, &expired
);
472 ok
= idmap_cache_find_gid2sid(
473 xids
[i
].id
, &sid
, &expired
);
479 if (ok
&& !expired
) {
480 sid_copy(&state
->sids
[i
], &sid
);
485 subreq
= wb_xids2sids_init_dom_maps_send(
487 if (tevent_req_nomem(subreq
, req
)) {
488 return tevent_req_post(req
, ev
);
490 tevent_req_set_callback(subreq
, wb_xids2sids_init_dom_maps_done
, req
);
494 static void wb_xids2sids_init_dom_maps_done(struct tevent_req
*subreq
)
496 struct tevent_req
*req
= tevent_req_callback_data(
497 subreq
, struct tevent_req
);
498 struct wb_xids2sids_state
*state
= tevent_req_data(
499 req
, struct wb_xids2sids_state
);
503 status
= wb_xids2sids_init_dom_maps_recv(subreq
);
505 if (tevent_req_nterror(req
, status
)) {
509 num_domains
= talloc_array_length(dom_maps
);
510 if (num_domains
== 0) {
511 tevent_req_done(req
);
515 subreq
= wb_xids2sids_dom_send(
516 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
517 state
->xids
, state
->num_xids
, state
->sids
);
518 if (tevent_req_nomem(subreq
, req
)) {
521 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
525 static void wb_xids2sids_done(struct tevent_req
*subreq
)
527 struct tevent_req
*req
= tevent_req_callback_data(
528 subreq
, struct tevent_req
);
529 struct wb_xids2sids_state
*state
= tevent_req_data(
530 req
, struct wb_xids2sids_state
);
531 size_t num_domains
= talloc_array_length(dom_maps
);
534 status
= wb_xids2sids_dom_recv(subreq
);
536 if (tevent_req_nterror(req
, status
)) {
542 if (state
->dom_idx
>= num_domains
) {
543 tevent_req_done(req
);
547 subreq
= wb_xids2sids_dom_send(
548 state
, state
->ev
, &dom_maps
[state
->dom_idx
],
549 state
->xids
, state
->num_xids
, state
->sids
);
550 if (tevent_req_nomem(subreq
, req
)) {
553 tevent_req_set_callback(subreq
, wb_xids2sids_done
, req
);
556 NTSTATUS
wb_xids2sids_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
557 struct dom_sid
**sids
)
559 struct wb_xids2sids_state
*state
= tevent_req_data(
560 req
, struct wb_xids2sids_state
);
563 if (tevent_req_is_nterror(req
, &status
)) {
564 DEBUG(5, ("wb_sids_to_xids failed: %s\n", nt_errstr(status
)));
568 *sids
= talloc_move(mem_ctx
, &state
->sids
);