s4:rpc_srv:getncchanges: 4.5 anc emulation uses qsort(), not ldb_qsort()
[samba.git] / source3 / winbindd / wb_sids2xids.c
blobf0f6c23fc20bd74eada9b270dc45e57ffffc583b
1 /*
2 Unix SMB/CIFS implementation.
3 async sids2xids
4 Copyright (C) Volker Lendecke 2011
5 Copyright (C) Michael Adam 2012
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "winbindd.h"
23 #include "../libcli/security/security.h"
24 #include "idmap_cache.h"
25 #include "librpc/gen_ndr/ndr_winbind_c.h"
26 #include "librpc/gen_ndr/ndr_netlogon.h"
27 #include "lsa.h"
29 struct wb_sids2xids_state {
30 struct tevent_context *ev;
32 const struct wb_parent_idmap_config *cfg;
34 struct dom_sid *sids;
35 uint32_t num_sids;
37 struct wbint_TransIDArray all_ids;
39 /* Used to translated the idx back into all_ids.ids[idx] */
40 uint32_t *tmp_idx;
42 uint32_t lookup_count;
43 struct dom_sid *lookup_sids;
45 struct wbint_TransIDArray map_ids_in;
46 struct wbint_TransIDArray map_ids_out;
49 * Domain array to use for the idmap call. The output from
50 * lookupsids cannot be used directly since for migrated
51 * objects the returned domain SID can be different than the
52 * original one. The new domain SID cannot be combined with
53 * the RID from the previous domain.
55 * The proper way would be asking for the correct RID in the
56 * new domain, but this approach avoids id mappings for
57 * invalid SIDs.
59 struct lsa_RefDomainList idmap_doms;
61 uint32_t dom_index;
62 struct lsa_RefDomainList idmap_dom;
63 bool tried_dclookup;
66 static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq);
67 static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map);
68 static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq);
69 static void wb_sids2xids_done(struct tevent_req *subreq);
70 static void wb_sids2xids_gotdc(struct tevent_req *subreq);
71 static void wb_sids2xids_next_sids2unix(struct tevent_req *req);
72 static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type);
74 struct tevent_req *wb_sids2xids_send(TALLOC_CTX *mem_ctx,
75 struct tevent_context *ev,
76 const struct dom_sid *sids,
77 const uint32_t num_sids)
79 struct tevent_req *req, *subreq;
80 struct wb_sids2xids_state *state;
81 uint32_t i;
82 uint32_t num_valid = 0;
84 req = tevent_req_create(mem_ctx, &state,
85 struct wb_sids2xids_state);
86 if (req == NULL) {
87 return NULL;
90 D_INFO("WB command sids2xids start.\n"
91 "Resolving %"PRIu32" SID(s).\n", num_sids);
93 state->ev = ev;
95 state->num_sids = num_sids;
97 state->sids = talloc_zero_array(state, struct dom_sid, num_sids);
98 if (tevent_req_nomem(state->sids, req)) {
99 return tevent_req_post(req, ev);
102 for (i = 0; i < num_sids; i++) {
103 sid_copy(&state->sids[i], &sids[i]);
106 state->all_ids.num_ids = num_sids;
107 state->all_ids.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
108 if (tevent_req_nomem(state->all_ids.ids, req)) {
109 return tevent_req_post(req, ev);
112 state->tmp_idx = talloc_zero_array(state, uint32_t, num_sids);
113 if (tevent_req_nomem(state->tmp_idx, req)) {
114 return tevent_req_post(req, ev);
117 state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids);
118 if (tevent_req_nomem(state->lookup_sids, req)) {
119 return tevent_req_post(req, ev);
122 state->map_ids_in.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
123 if (tevent_req_nomem(state->map_ids_in.ids, req)) {
124 return tevent_req_post(req, ev);
128 * Extract those sids that can not be resolved from cache
129 * into a separate list to be handed to id mapping, keeping
130 * the same index.
132 for (i=0; i<state->num_sids; i++) {
133 struct wbint_TransID *cur_id = &state->all_ids.ids[i];
134 struct dom_sid domain_sid;
135 struct dom_sid_buf buf;
136 struct id_map map = { .status = ID_UNMAPPED, };
137 uint32_t rid = 0;
138 bool in_cache;
140 sid_copy(&domain_sid, &state->sids[i]);
141 sid_split_rid(&domain_sid, &rid);
144 * Start with an invalid entry.
146 *cur_id = (struct wbint_TransID) {
147 .type_hint = ID_TYPE_NOT_SPECIFIED,
148 .domain_index = UINT32_MAX - 1, /* invalid */
149 .rid = rid,
150 .xid = {
151 .id = UINT32_MAX,
152 .type = ID_TYPE_NOT_SPECIFIED,
156 D_DEBUG("%"PRIu32": SID %s\n",
157 i, dom_sid_str_buf(&state->sids[i], &buf));
159 in_cache = wb_sids2xids_in_cache(&state->sids[i], &map);
160 if (in_cache) {
162 * We used to ignore map.status and just rely
163 * on map.xid.type.
165 * Lets keep this logic for now...
168 cur_id->xid = map.xid;
169 cur_id->domain_index = UINT32_MAX; /* this marks it as filled entry */
170 num_valid += 1;
171 continue;
175 D_DEBUG("Found %"PRIu32" (out of %"PRIu32") SID(s) in cache.\n",
176 num_valid, num_sids);
177 if (num_valid == num_sids) {
178 tevent_req_done(req);
179 return tevent_req_post(req, ev);
182 subreq = wb_parent_idmap_setup_send(state, state->ev);
183 if (tevent_req_nomem(subreq, req)) {
184 return tevent_req_post(req, ev);
186 tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req);
187 return req;
190 static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
192 struct tevent_req *req = tevent_req_callback_data(
193 subreq, struct tevent_req);
194 struct wb_sids2xids_state *state = tevent_req_data(
195 req, struct wb_sids2xids_state);
196 NTSTATUS status;
197 uint32_t i;
199 status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
200 TALLOC_FREE(subreq);
201 if (tevent_req_nterror(req, status)) {
202 D_WARNING("Failed with %s.\n", nt_errstr(status));
203 return;
205 SMB_ASSERT(state->cfg->num_doms > 0);
206 D_DEBUG("We will loop over %"PRIu32" SID(s) (skipping those already resolved via cache) and over %"PRIu32" domain(s).\n",
207 state->num_sids,
208 state->cfg->num_doms);
211 * Now we build a list with all domain
212 * with non cached entries
214 for (i=0; i<state->num_sids; i++) {
215 struct wbint_TransID *t = &state->all_ids.ids[i];
216 struct dom_sid domain_sid;
217 const char *domain_name = NULL;
218 int domain_index;
219 uint32_t rid = 0;
220 uint32_t di;
221 struct dom_sid_buf buf0, buf1;
223 D_DEBUG("%"PRIu32": Processing SID %s\n",
225 dom_sid_str_buf(&state->sids[i], &buf0));
226 if (t->domain_index == UINT32_MAX) {
227 /* ignore already filled entries */
228 D_DEBUG("%"PRIu32": Ignoring already resolved SID %s\n",
230 dom_sid_str_buf(&state->sids[i], &buf0));
231 continue;
234 sid_copy(&domain_sid, &state->sids[i]);
235 sid_split_rid(&domain_sid, &rid);
236 D_DEBUG("%"PRIu32": Split SID %s into domain SID %s and RID %"PRIu32"\n",
238 dom_sid_str_buf(&state->sids[i], &buf0),
239 dom_sid_str_buf(&domain_sid, &buf1),
240 rid);
242 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
243 const char *tmp_name = NULL;
244 enum lsa_SidType sid_type = SID_NAME_USE_NONE;
245 const struct dom_sid *tmp_authority_sid = NULL;
246 const char *tmp_authority_name = NULL;
249 * Try to get a type hint from for predefined sids
251 status = dom_sid_lookup_predefined_sid(&state->sids[i],
252 &tmp_name,
253 &sid_type,
254 &tmp_authority_sid,
255 &tmp_authority_name);
256 if (NT_STATUS_IS_OK(status)) {
257 t->type_hint = lsa_SidType_to_id_type(sid_type);
258 D_DEBUG("Got a type hint: %d from predefined SID.\n",
259 t->type_hint);
263 D_DEBUG("Looping over %"PRIu32" domain(s) to find domain SID %s.\n",
264 state->cfg->num_doms,
265 dom_sid_str_buf(&domain_sid, &buf0));
266 for (di = 0; di < state->cfg->num_doms; di++) {
267 struct wb_parent_idmap_config_dom *dom =
268 &state->cfg->doms[di];
269 bool match;
271 match = dom_sid_equal(&domain_sid, &dom->sid);
272 if (!match) {
273 continue;
276 domain_name = dom->name;
277 D_DEBUG("Found domain '%s'.\n", domain_name);
278 break;
280 if (domain_name == NULL) {
281 struct winbindd_domain *wb_domain = NULL;
283 D_DEBUG("Could not find a domain for domain SID %s. Trying to fill the domain name from list of known domains.\n",
284 dom_sid_str_buf(&domain_sid, &buf0));
286 * Try to fill the name if we already know it
288 wb_domain = find_domain_from_sid_noinit(&state->sids[i]);
289 if (wb_domain != NULL) {
290 domain_name = wb_domain->name;
291 D_DEBUG("Found domain '%s' in list of known domains.\n", domain_name);
294 if (domain_name == NULL) {
295 domain_name = "";
296 D_DEBUG("Not found domain in list of known domains, setting empty domain name.\n");
299 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
300 if (domain_name[0] != '\0') {
302 * We know the domain, we indicate this
303 * by passing ID_TYPE_BOTH as a hint
305 * Maybe that's already enough for the backend
307 t->type_hint = ID_TYPE_BOTH;
308 D_DEBUG("Setting type hint ID_TYPE_BOTH for domain '%s'.\n", domain_name);
312 domain_index = init_lsa_ref_domain_list(state,
313 &state->idmap_doms,
314 domain_name,
315 &domain_sid);
316 if (domain_index == -1) {
317 tevent_req_oom(req);
318 return;
320 t->domain_index = domain_index;
324 * We defer lookupsids because it requires domain controller
325 * interaction.
327 * First we ask the idmap child without explicit type hints.
328 * In most cases mappings already exist in the backend and
329 * a type_hint is not needed.
331 wb_sids2xids_next_sids2unix(req);
334 static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
336 struct unixid id;
337 bool expired;
339 if (!winbindd_use_idmap_cache()) {
340 return false;
342 if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
343 if (expired && is_domain_online(find_our_domain())) {
344 return false;
346 map->sid = sid;
347 map->xid = id;
348 map->status = ID_MAPPED;
349 return true;
351 return false;
354 static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
356 struct tevent_req *req = tevent_req_callback_data(
357 subreq, struct tevent_req);
358 struct wb_sids2xids_state *state = tevent_req_data(
359 req, struct wb_sids2xids_state);
360 struct lsa_RefDomainList *domains = NULL;
361 struct lsa_TransNameArray *names = NULL;
362 NTSTATUS status;
363 uint32_t li;
365 status = wb_lookupsids_recv(subreq, state, &domains, &names);
366 TALLOC_FREE(subreq);
367 if (tevent_req_nterror(req, status)) {
368 D_WARNING("Failed with %s.\n", nt_errstr(status));
369 return;
372 if (domains == NULL) {
373 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
374 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
375 return;
378 if (names == NULL) {
379 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
380 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
381 return;
384 for (li = 0; li < state->lookup_count; li++) {
385 struct lsa_TranslatedName *n = &names->names[li];
386 uint32_t ai = state->tmp_idx[li];
387 struct wbint_TransID *t = &state->all_ids.ids[ai];
388 enum id_type type_hint;
390 type_hint = lsa_SidType_to_id_type(n->sid_type);
391 if (type_hint != ID_TYPE_NOT_SPECIFIED) {
393 * We know it's a valid user or group.
395 t->type_hint = type_hint;
396 continue;
399 if (n->sid_index == UINT32_MAX) {
401 * The domain is not known, there's
402 * no point to try mapping again.
403 * mark is done and add a negative cache
404 * entry.
406 t->domain_index = UINT32_MAX; /* mark as valid */
407 idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
408 continue;
411 if (n->sid_index >= domains->count) {
412 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
413 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
414 return;
417 if (domains->domains[n->sid_index].name.string == NULL) {
418 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
419 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
420 return;
422 if (domains->domains[n->sid_index].sid == NULL) {
423 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
424 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
425 return;
428 if (t->type_hint != ID_TYPE_NOT_SPECIFIED) {
430 * We already tried with a type hint there's
431 * no point to try mapping again with ID_TYPE_BOTH.
433 * Mark is done and add a negative cache entry.
435 t->domain_index = UINT32_MAX; /* mark as valid */
436 idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
437 continue;
441 * We only know the domain exists, but the user doesn't
443 t->type_hint = ID_TYPE_BOTH;
446 TALLOC_FREE(names);
447 TALLOC_FREE(domains);
450 * Now that we have type_hints for the remaining sids,
451 * we need to restart with the first domain.
453 state->dom_index = 0;
454 wb_sids2xids_next_sids2unix(req);
457 static void wb_sids2xids_next_sids2unix(struct tevent_req *req)
459 struct wb_sids2xids_state *state = tevent_req_data(
460 req, struct wb_sids2xids_state);
461 struct tevent_req *subreq = NULL;
462 struct dcerpc_binding_handle *child_binding_handle = NULL;
463 const struct wbint_TransIDArray *src = NULL;
464 struct wbint_TransIDArray *dst = NULL;
465 uint32_t si;
467 next_domain:
468 state->tried_dclookup = false;
470 D_DEBUG("Processing next domain (dom_index=%"PRIu32", idmap_doms.count=%"PRIu32", lookup_count=%"PRIu32").\n",
471 state->dom_index,
472 state->idmap_doms.count,
473 state->lookup_count);
474 if (state->dom_index == state->idmap_doms.count) {
475 if (state->lookup_count != 0) {
477 * We already called wb_lookupsids_send()
478 * before, so we're done.
480 D_DEBUG("We already called wb_lookupsids_send() before, so we're done.\n");
481 tevent_req_done(req);
482 return;
485 for (si=0; si < state->num_sids; si++) {
486 struct wbint_TransID *t = &state->all_ids.ids[si];
488 if (t->domain_index == UINT32_MAX) {
489 /* ignore already filled entries */
490 continue;
493 state->tmp_idx[state->lookup_count] = si;
494 sid_copy(&state->lookup_sids[state->lookup_count],
495 &state->sids[si]);
496 state->lookup_count += 1;
499 D_DEBUG("Prepared %"PRIu32" SID(s) for lookup wb_lookupsids_send().\n",
500 state->lookup_count);
501 if (state->lookup_count == 0) {
503 * no wb_lookupsids_send() needed...
505 tevent_req_done(req);
506 return;
509 subreq = wb_lookupsids_send(state,
510 state->ev,
511 state->lookup_sids,
512 state->lookup_count);
513 if (tevent_req_nomem(subreq, req)) {
514 return;
516 tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
517 return;
520 src = &state->all_ids;
521 dst = &state->map_ids_in;
522 dst->num_ids = 0;
524 for (si=0; si < src->num_ids; si++) {
525 if (src->ids[si].domain_index != state->dom_index) {
526 continue;
529 state->tmp_idx[dst->num_ids] = si;
530 dst->ids[dst->num_ids] = src->ids[si];
531 dst->ids[dst->num_ids].domain_index = 0;
532 dst->num_ids += 1;
535 if (dst->num_ids == 0) {
536 state->dom_index += 1;
537 D_DEBUG("Go to next domain.\n");
538 goto next_domain;
541 state->idmap_dom = (struct lsa_RefDomainList) {
542 .count = 1,
543 .domains = &state->idmap_doms.domains[state->dom_index],
544 .max_size = 1
548 * dcerpc_wbint_Sids2UnixIDs_send/recv will
549 * allocate a new array for the response
550 * and overwrite _ids->ids pointer.
552 * So we better make a temporary copy
553 * of state->map_ids_in (which contains the request array)
554 * into state->map_ids_out.
556 * That makes it possible to reuse the pre-allocated
557 * state->map_ids_in.ids array.
559 state->map_ids_out = state->map_ids_in;
560 child_binding_handle = idmap_child_handle();
561 subreq = dcerpc_wbint_Sids2UnixIDs_send(
562 state, state->ev, child_binding_handle, &state->idmap_dom,
563 &state->map_ids_out);
564 if (tevent_req_nomem(subreq, req)) {
565 return;
567 tevent_req_set_callback(subreq, wb_sids2xids_done, req);
570 static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
572 enum id_type type;
574 switch(sid_type) {
575 case SID_NAME_COMPUTER:
576 case SID_NAME_USER:
577 type = ID_TYPE_UID;
578 break;
579 case SID_NAME_DOM_GRP:
580 case SID_NAME_ALIAS:
581 case SID_NAME_WKN_GRP:
582 type = ID_TYPE_GID;
583 break;
584 default:
585 type = ID_TYPE_NOT_SPECIFIED;
586 break;
589 return type;
592 static void wb_sids2xids_done(struct tevent_req *subreq)
594 struct tevent_req *req = tevent_req_callback_data(
595 subreq, struct tevent_req);
596 struct wb_sids2xids_state *state = tevent_req_data(
597 req, struct wb_sids2xids_state);
598 NTSTATUS status, result;
599 const struct wbint_TransIDArray *src = NULL;
600 struct wbint_TransIDArray *dst = NULL;
601 uint32_t si;
603 status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
604 TALLOC_FREE(subreq);
606 if (tevent_req_nterror(req, status)) {
607 D_WARNING("Failed with %s.\n", nt_errstr(status));
608 return;
611 if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
612 !state->tried_dclookup) {
614 struct lsa_DomainInfo *d;
616 D_DEBUG("Domain controller not found. Calling wb_dsgetdcname_send() to get it.\n");
617 d = &state->idmap_doms.domains[state->dom_index];
619 subreq = wb_dsgetdcname_send(
620 state, state->ev, d->name.string, NULL, NULL,
621 DS_RETURN_DNS_NAME);
622 if (tevent_req_nomem(subreq, req)) {
623 return;
625 tevent_req_set_callback(subreq, wb_sids2xids_gotdc, req);
626 return;
629 src = &state->map_ids_out;
630 dst = &state->all_ids;
632 if (any_nt_status_not_ok(status, result, &status)) {
633 D_DEBUG("Either status %s or result %s is not ok. Report SIDs as not mapped.\n",
634 nt_errstr(status),
635 nt_errstr(result));
637 * All we can do here is to report "not mapped"
639 src = &state->map_ids_in;
640 for (si=0; si < src->num_ids; si++) {
641 src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
645 if (src->num_ids != state->map_ids_in.num_ids) {
646 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
647 D_WARNING("Number of mapped SIDs does not match. Failing with NT_STATUS_INTERNAL_ERROR.\n");
648 return;
651 for (si=0; si < src->num_ids; si++) {
652 uint32_t di = state->tmp_idx[si];
654 if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) {
655 if (state->lookup_count == 0) {
656 D_DEBUG("The backend asks for more information (a type_hint), we'll do a lookupsids later.\n");
658 * The backend asks for more information
659 * (a type_hint), we'll do a lookupsids
660 * later.
662 continue;
666 * lookupsids was not able to provide a type_hint that
667 * satisfied the backend.
669 * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE
670 * outside of winbindd!
672 D_DEBUG("lookupsids was not able to provide a type_hint that satisfied the backend. Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE outside of winbindd!\n");
673 src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
676 if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) {
677 dst->ids[di].xid = src->ids[si].xid;
678 D_DEBUG("%"PRIu32": Setting XID %"PRIu32"\n",
679 si, src->ids[si].xid.id);
681 dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */
682 idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid);
685 state->map_ids_in.num_ids = 0;
686 if (NT_STATUS_IS_OK(status)) {
688 * If we got a valid response, we expect
689 * state->map_ids_out.ids to be a new allocated
690 * array, which we want to free early.
692 SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids);
693 TALLOC_FREE(state->map_ids_out.ids);
695 state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, };
697 state->dom_index += 1;
699 wb_sids2xids_next_sids2unix(req);
702 static void wb_sids2xids_gotdc(struct tevent_req *subreq)
704 struct tevent_req *req = tevent_req_callback_data(
705 subreq, struct tevent_req);
706 struct wb_sids2xids_state *state = tevent_req_data(
707 req, struct wb_sids2xids_state);
708 struct dcerpc_binding_handle *child_binding_handle = NULL;
709 struct netr_DsRGetDCNameInfo *dcinfo;
710 NTSTATUS status;
712 status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
713 TALLOC_FREE(subreq);
714 if (tevent_req_nterror(req, status)) {
715 D_WARNING("Failed with %s.\n", nt_errstr(status));
716 return;
719 state->tried_dclookup = true;
722 struct lsa_DomainInfo *d =
723 &state->idmap_doms.domains[state->dom_index];
724 const char *dom_name = d->name.string;
726 status = wb_dsgetdcname_gencache_set(dom_name, dcinfo);
727 if (tevent_req_nterror(req, status)) {
728 D_WARNING("Failed with %s.\n", nt_errstr(status));
729 return;
734 * dcerpc_wbint_Sids2UnixIDs_send/recv will
735 * allocate a new array for the response
736 * and overwrite _ids->ids pointer.
738 * So we better make a temporary copy
739 * of state->map_ids_in (which contains the request array)
740 * into state->map_ids_out.
742 * That makes it possible to reuse the pre-allocated
743 * state->map_ids_in.ids array.
745 state->map_ids_out = state->map_ids_in;
746 child_binding_handle = idmap_child_handle();
747 subreq = dcerpc_wbint_Sids2UnixIDs_send(
748 state, state->ev, child_binding_handle, &state->idmap_dom,
749 &state->map_ids_out);
750 if (tevent_req_nomem(subreq, req)) {
751 return;
753 tevent_req_set_callback(subreq, wb_sids2xids_done, req);
756 NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
757 struct unixid xids[], uint32_t num_xids)
759 struct wb_sids2xids_state *state = tevent_req_data(
760 req, struct wb_sids2xids_state);
761 NTSTATUS status;
762 uint32_t i;
764 if (tevent_req_is_nterror(req, &status)) {
765 D_WARNING("Failed with %s.\n", nt_errstr(status));
766 return status;
769 if (num_xids != state->num_sids) {
770 D_WARNING("Error. We have resolved only %"PRIu32" XID(s), but caller asked for %"PRIu32".\n",
771 state->num_sids, num_xids);
772 return NT_STATUS_INTERNAL_ERROR;
775 D_INFO("WB command sids2xids end.\n");
776 for (i=0; i<state->num_sids; i++) {
777 struct dom_sid_buf buf;
778 xids[i] = state->all_ids.ids[i].xid;
779 D_INFO("%"PRIu32": Found XID %"PRIu32" for SID %s\n",
781 xids[i].id,
782 dom_sid_str_buf(&state->sids[i], &buf));
785 return NT_STATUS_OK;