smbd: Add reparse tag to smb3_posix_cc_info
[samba.git] / source3 / winbindd / wb_sids2xids.c
1 /*
2    Unix SMB/CIFS implementation.
3    async sids2xids
4    Copyright (C) Volker Lendecke 2011
5    Copyright (C) Michael Adam 2012
6
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.
11
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.
16
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/>.
19 */
20
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"
28
29 struct wb_sids2xids_state {
30         struct tevent_context *ev;
31
32         const struct wb_parent_idmap_config *cfg;
33
34         struct dom_sid *sids;
35         uint32_t num_sids;
36
37         struct wbint_TransIDArray all_ids;
38
39         /* Used to translated the idx back into all_ids.ids[idx] */
40         uint32_t *tmp_idx;
41
42         uint32_t lookup_count;
43         struct dom_sid *lookup_sids;
44
45         struct wbint_TransIDArray map_ids_in;
46         struct wbint_TransIDArray map_ids_out;
47
48         /*
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.
54          *
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.
58          */
59         struct lsa_RefDomainList idmap_doms;
60
61         uint32_t dom_index;
62         struct lsa_RefDomainList idmap_dom;
63         bool tried_dclookup;
64 };
65
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);
73
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)
78 {
79         struct tevent_req *req, *subreq;
80         struct wb_sids2xids_state *state;
81         uint32_t i;
82         uint32_t num_valid = 0;
83
84         req = tevent_req_create(mem_ctx, &state,
85                                 struct wb_sids2xids_state);
86         if (req == NULL) {
87                 return NULL;
88         }
89
90         D_INFO("WB command sids2xids start.\n"
91                "Resolving %"PRIu32" SID(s).\n", num_sids);
92
93         state->ev = ev;
94
95         state->num_sids = num_sids;
96
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);
100         }
101
102         for (i = 0; i < num_sids; i++) {
103                 sid_copy(&state->sids[i], &sids[i]);
104         }
105
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);
110         }
111
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);
115         }
116
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);
120         }
121
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);
125         }
126
127         /*
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.
131          */
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;
139
140                 sid_copy(&domain_sid, &state->sids[i]);
141                 sid_split_rid(&domain_sid, &rid);
142
143                 /*
144                  * Start with an invalid entry.
145                  */
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,
153                         },
154                 };
155
156                 D_DEBUG("%"PRIu32": SID %s\n",
157                         i, dom_sid_str_buf(&state->sids[i], &buf));
158
159                 in_cache = wb_sids2xids_in_cache(&state->sids[i], &map);
160                 if (in_cache) {
161                         /*
162                          * We used to ignore map.status and just rely
163                          * on map.xid.type.
164                          *
165                          * Lets keep this logic for now...
166                          */
167
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;
172                 }
173         }
174
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);
180         }
181
182         subreq = wb_parent_idmap_setup_send(state, state->ev);
183         if (tevent_req_nomem(subreq, req)) {
184                 return tevent_req_post(req, ev);
185         }
186         tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req);
187         return req;
188 }
189
190 static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
191 {
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;
198
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;
204         }
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);
209
210         /*
211          * Now we build a list with all domain
212          * with non cached entries
213          */
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;
222
223                 D_DEBUG("%"PRIu32": Processing SID %s\n",
224                         i,
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",
229                                 i,
230                                 dom_sid_str_buf(&state->sids[i], &buf0));
231                         continue;
232                 }
233
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",
237                         i,
238                         dom_sid_str_buf(&state->sids[i], &buf0),
239                         dom_sid_str_buf(&domain_sid, &buf1),
240                         rid);
241
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;
247
248                         /*
249                          * Try to get a type hint from for predefined sids
250                          */
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);
260                         }
261                 }
262
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;
270
271                         match = dom_sid_equal(&domain_sid, &dom->sid);
272                         if (!match) {
273                                 continue;
274                         }
275
276                         domain_name = dom->name;
277                         D_DEBUG("Found domain '%s'.\n", domain_name);
278                         break;
279                 }
280                 if (domain_name == NULL) {
281                         struct winbindd_domain *wb_domain = NULL;
282
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));
285                         /*
286                          * Try to fill the name if we already know it
287                          */
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);
292                         }
293                 }
294                 if (domain_name == NULL) {
295                         domain_name = "";
296                         D_DEBUG("Not found domain in list of known domains, setting empty domain name.\n");
297                 }
298
299                 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
300                         if (domain_name[0] != '\0') {
301                                 /*
302                                  * We know the domain, we indicate this
303                                  * by passing ID_TYPE_BOTH as a hint
304                                  *
305                                  * Maybe that's already enough for the backend
306                                  */
307                                 t->type_hint = ID_TYPE_BOTH;
308                                 D_DEBUG("Setting type hint ID_TYPE_BOTH for domain '%s'.\n", domain_name);
309                         }
310                 }
311
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;
319                 }
320                 t->domain_index = domain_index;
321         }
322
323         /*
324          * We defer lookupsids because it requires domain controller
325          * interaction.
326          *
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.
330          */
331         wb_sids2xids_next_sids2unix(req);
332 }
333
334 static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
335 {
336         struct unixid id;
337         bool expired;
338
339         if (!winbindd_use_idmap_cache()) {
340                 return false;
341         }
342         if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
343                 if (expired && is_domain_online(find_our_domain())) {
344                         return false;
345                 }
346                 map->sid = sid;
347                 map->xid = id;
348                 map->status = ID_MAPPED;
349                 return true;
350         }
351         return false;
352 }
353
354 static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
355 {
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;
364
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;
370         }
371
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;
376         }
377
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;
382         }
383
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;
389
390                 type_hint = lsa_SidType_to_id_type(n->sid_type);
391                 if (type_hint != ID_TYPE_NOT_SPECIFIED) {
392                         /*
393                          * We know it's a valid user or group.
394                          */
395                         t->type_hint = type_hint;
396                         continue;
397                 }
398
399                 if (n->sid_index == UINT32_MAX) {
400                         /*
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.
405                          */
406                         t->domain_index = UINT32_MAX; /* mark as valid */
407                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
408                         continue;
409                 }
410
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;
415                 }
416
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;
421                 }
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;
426                 }
427
428                 if (t->type_hint != ID_TYPE_NOT_SPECIFIED) {
429                         /*
430                          * We already tried with a type hint there's
431                          * no point to try mapping again with ID_TYPE_BOTH.
432                          *
433                          * Mark is done and add a negative cache entry.
434                          */
435                         t->domain_index = UINT32_MAX; /* mark as valid */
436                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
437                         continue;
438                 }
439
440                 /*
441                  * We only know the domain exists, but the user doesn't
442                  */
443                 t->type_hint = ID_TYPE_BOTH;
444         }
445
446         TALLOC_FREE(names);
447         TALLOC_FREE(domains);
448
449         /*
450          * Now that we have type_hints for the remaining sids,
451          * we need to restart with the first domain.
452          */
453         state->dom_index = 0;
454         wb_sids2xids_next_sids2unix(req);
455 }
456
457 static void wb_sids2xids_next_sids2unix(struct tevent_req *req)
458 {
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;
466
467  next_domain:
468         state->tried_dclookup = false;
469
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) {
476                         /*
477                          * We already called wb_lookupsids_send()
478                          * before, so we're done.
479                          */
480                         D_DEBUG("We already called wb_lookupsids_send() before, so we're done.\n");
481                         tevent_req_done(req);
482                         return;
483                 }
484
485                 for (si=0; si < state->num_sids; si++) {
486                         struct wbint_TransID *t = &state->all_ids.ids[si];
487
488                         if (t->domain_index == UINT32_MAX) {
489                                 /* ignore already filled entries */
490                                 continue;
491                         }
492
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;
497                 }
498
499                 D_DEBUG("Prepared %"PRIu32" SID(s) for lookup wb_lookupsids_send().\n",
500                         state->lookup_count);
501                 if (state->lookup_count == 0) {
502                         /*
503                          * no wb_lookupsids_send() needed...
504                          */
505                         tevent_req_done(req);
506                         return;
507                 }
508
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;
515                 }
516                 tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
517                 return;
518         }
519
520         src = &state->all_ids;
521         dst = &state->map_ids_in;
522         dst->num_ids = 0;
523
524         for (si=0; si < src->num_ids; si++) {
525                 if (src->ids[si].domain_index != state->dom_index) {
526                         continue;
527                 }
528
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;
533         }
534
535         if (dst->num_ids == 0) {
536                 state->dom_index += 1;
537                 D_DEBUG("Go to next domain.\n");
538                 goto next_domain;
539         }
540
541         state->idmap_dom = (struct lsa_RefDomainList) {
542                 .count = 1,
543                 .domains = &state->idmap_doms.domains[state->dom_index],
544                 .max_size = 1
545         };
546
547         /*
548          * dcerpc_wbint_Sids2UnixIDs_send/recv will
549          * allocate a new array for the response
550          * and overwrite _ids->ids pointer.
551          *
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.
555          *
556          * That makes it possible to reuse the pre-allocated
557          * state->map_ids_in.ids array.
558          */
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;
566         }
567         tevent_req_set_callback(subreq, wb_sids2xids_done, req);
568 }
569
570 static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
571 {
572         enum id_type type;
573
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;
587         }
588
589         return type;
590 }
591
592 static void wb_sids2xids_done(struct tevent_req *subreq)
593 {
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;
602
603         status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
604         TALLOC_FREE(subreq);
605
606         if (tevent_req_nterror(req, status)) {
607                 D_WARNING("Failed with %s.\n", nt_errstr(status));
608                 return;
609         }
610
611         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
612             !state->tried_dclookup) {
613
614                 struct lsa_DomainInfo *d;
615
616                 D_DEBUG("Domain controller not found. Calling wb_dsgetdcname_send() to get it.\n");
617                 d = &state->idmap_doms.domains[state->dom_index];
618
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;
624                 }
625                 tevent_req_set_callback(subreq, wb_sids2xids_gotdc, req);
626                 return;
627         }
628
629         src = &state->map_ids_out;
630         dst = &state->all_ids;
631
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));
636                 /*
637                  * All we can do here is to report "not mapped"
638                  */
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;
642                 }
643         }
644
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;
649         }
650
651         for (si=0; si < src->num_ids; si++) {
652                 uint32_t di = state->tmp_idx[si];
653
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");
657                                 /*
658                                  * The backend asks for more information
659                                  * (a type_hint), we'll do a lookupsids
660                                  * later.
661                                  */
662                                 continue;
663                         }
664
665                         /*
666                          * lookupsids was not able to provide a type_hint that
667                          * satisfied the backend.
668                          *
669                          * Make sure we don't expose ID_TYPE_WB_REQUIRE_TYPE
670                          * outside of winbindd!
671                          */
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;
674                 }
675
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);
680                 }
681                 dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */
682                 idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid);
683         }
684
685         state->map_ids_in.num_ids = 0;
686         if (NT_STATUS_IS_OK(status)) {
687                 /*
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.
691                  */
692                 SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids);
693                 TALLOC_FREE(state->map_ids_out.ids);
694         }
695         state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, };
696
697         state->dom_index += 1;
698
699         wb_sids2xids_next_sids2unix(req);
700 }
701
702 static void wb_sids2xids_gotdc(struct tevent_req *subreq)
703 {
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;
711
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;
717         }
718
719         state->tried_dclookup = true;
720
721         {
722                 struct lsa_DomainInfo *d =
723                         &state->idmap_doms.domains[state->dom_index];
724                 const char *dom_name = d->name.string;
725
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;
730                 }
731         }
732
733         /*
734          * dcerpc_wbint_Sids2UnixIDs_send/recv will
735          * allocate a new array for the response
736          * and overwrite _ids->ids pointer.
737          *
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.
741          *
742          * That makes it possible to reuse the pre-allocated
743          * state->map_ids_in.ids array.
744          */
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;
752         }
753         tevent_req_set_callback(subreq, wb_sids2xids_done, req);
754 }
755
756 NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
757                            struct unixid xids[], uint32_t num_xids)
758 {
759         struct wb_sids2xids_state *state = tevent_req_data(
760                 req, struct wb_sids2xids_state);
761         NTSTATUS status;
762         uint32_t i;
763
764         if (tevent_req_is_nterror(req, &status)) {
765                 D_WARNING("Failed with %s.\n", nt_errstr(status));
766                 return status;
767         }
768
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;
773         }
774
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",
780                        i,
781                        xids[i].id,
782                        dom_sid_str_buf(&state->sids[i], &buf));
783         }
784
785         return NT_STATUS_OK;
786 }