LCOV - code coverage report
Current view: top level - source3/winbindd - wb_sids2xids.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 274 350 78.3 %
Date: 2024-02-28 12:06:22 Functions: 9 9 100.0 %

          Line data    Source code
       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      209161 : 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           0 :         struct tevent_req *req, *subreq;
      80           0 :         struct wb_sids2xids_state *state;
      81           0 :         uint32_t i;
      82      209161 :         uint32_t num_valid = 0;
      83             : 
      84      209161 :         req = tevent_req_create(mem_ctx, &state,
      85             :                                 struct wb_sids2xids_state);
      86      209161 :         if (req == NULL) {
      87           0 :                 return NULL;
      88             :         }
      89             : 
      90      209161 :         D_INFO("WB command sids2xids start.\n"
      91             :                "Resolving %"PRIu32" SID(s).\n", num_sids);
      92             : 
      93      209161 :         state->ev = ev;
      94             : 
      95      209161 :         state->num_sids = num_sids;
      96             : 
      97      209161 :         state->sids = talloc_zero_array(state, struct dom_sid, num_sids);
      98      209161 :         if (tevent_req_nomem(state->sids, req)) {
      99           0 :                 return tevent_req_post(req, ev);
     100             :         }
     101             : 
     102      421401 :         for (i = 0; i < num_sids; i++) {
     103      212240 :                 sid_copy(&state->sids[i], &sids[i]);
     104             :         }
     105             : 
     106      209161 :         state->all_ids.num_ids = num_sids;
     107      209161 :         state->all_ids.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
     108      209161 :         if (tevent_req_nomem(state->all_ids.ids, req)) {
     109           0 :                 return tevent_req_post(req, ev);
     110             :         }
     111             : 
     112      209161 :         state->tmp_idx = talloc_zero_array(state, uint32_t, num_sids);
     113      209161 :         if (tevent_req_nomem(state->tmp_idx, req)) {
     114           0 :                 return tevent_req_post(req, ev);
     115             :         }
     116             : 
     117      209161 :         state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids);
     118      209161 :         if (tevent_req_nomem(state->lookup_sids, req)) {
     119           0 :                 return tevent_req_post(req, ev);
     120             :         }
     121             : 
     122      209161 :         state->map_ids_in.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
     123      209161 :         if (tevent_req_nomem(state->map_ids_in.ids, req)) {
     124           0 :                 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      421401 :         for (i=0; i<state->num_sids; i++) {
     133      212240 :                 struct wbint_TransID *cur_id = &state->all_ids.ids[i];
     134           0 :                 struct dom_sid domain_sid;
     135           0 :                 struct dom_sid_buf buf;
     136      212240 :                 struct id_map map = { .status = ID_UNMAPPED, };
     137      212240 :                 uint32_t rid = 0;
     138           0 :                 bool in_cache;
     139             : 
     140      212240 :                 sid_copy(&domain_sid, &state->sids[i]);
     141      212240 :                 sid_split_rid(&domain_sid, &rid);
     142             : 
     143             :                 /*
     144             :                  * Start with an invalid entry.
     145             :                  */
     146      212240 :                 *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      212240 :                 D_DEBUG("%"PRIu32": SID %s\n",
     157             :                         i, dom_sid_str_buf(&state->sids[i], &buf));
     158             : 
     159      212240 :                 in_cache = wb_sids2xids_in_cache(&state->sids[i], &map);
     160      212240 :                 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      208575 :                         cur_id->xid = map.xid;
     169      208575 :                         cur_id->domain_index = UINT32_MAX; /* this marks it as filled entry */
     170      208575 :                         num_valid += 1;
     171      208575 :                         continue;
     172             :                 }
     173             :         }
     174             : 
     175      209161 :         D_DEBUG("Found %"PRIu32" (out of %"PRIu32") SID(s) in cache.\n",
     176             :                 num_valid, num_sids);
     177      209161 :         if (num_valid == num_sids) {
     178      206333 :                 tevent_req_done(req);
     179      206333 :                 return tevent_req_post(req, ev);
     180             :         }
     181             : 
     182        2828 :         subreq = wb_parent_idmap_setup_send(state, state->ev);
     183        2828 :         if (tevent_req_nomem(subreq, req)) {
     184           0 :                 return tevent_req_post(req, ev);
     185             :         }
     186        2828 :         tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req);
     187        2828 :         return req;
     188             : }
     189             : 
     190        2828 : static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
     191             : {
     192        2828 :         struct tevent_req *req = tevent_req_callback_data(
     193             :                 subreq, struct tevent_req);
     194        2828 :         struct wb_sids2xids_state *state = tevent_req_data(
     195             :                 req, struct wb_sids2xids_state);
     196           0 :         NTSTATUS status;
     197           0 :         uint32_t i;
     198             : 
     199        2828 :         status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
     200        2828 :         TALLOC_FREE(subreq);
     201        2828 :         if (tevent_req_nterror(req, status)) {
     202           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     203           0 :                 return;
     204             :         }
     205        2828 :         SMB_ASSERT(state->cfg->num_doms > 0);
     206        2828 :         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        6523 :         for (i=0; i<state->num_sids; i++) {
     215        3695 :                 struct wbint_TransID *t = &state->all_ids.ids[i];
     216           0 :                 struct dom_sid domain_sid;
     217        3695 :                 const char *domain_name = NULL;
     218           0 :                 int domain_index;
     219        3695 :                 uint32_t rid = 0;
     220           0 :                 uint32_t di;
     221           0 :                 struct dom_sid_buf buf0, buf1;
     222             : 
     223        3695 :                 D_DEBUG("%"PRIu32": Processing SID %s\n",
     224             :                         i,
     225             :                         dom_sid_str_buf(&state->sids[i], &buf0));
     226        3695 :                 if (t->domain_index == UINT32_MAX) {
     227             :                         /* ignore already filled entries */
     228          30 :                         D_DEBUG("%"PRIu32": Ignoring already resolved SID %s\n",
     229             :                                 i,
     230             :                                 dom_sid_str_buf(&state->sids[i], &buf0));
     231          30 :                         continue;
     232             :                 }
     233             : 
     234        3665 :                 sid_copy(&domain_sid, &state->sids[i]);
     235        3665 :                 sid_split_rid(&domain_sid, &rid);
     236        3665 :                 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        3665 :                 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
     243        3665 :                         const char *tmp_name = NULL;
     244        3665 :                         enum lsa_SidType sid_type = SID_NAME_USE_NONE;
     245        3665 :                         const struct dom_sid *tmp_authority_sid = NULL;
     246        3665 :                         const char *tmp_authority_name = NULL;
     247             : 
     248             :                         /*
     249             :                          * Try to get a type hint from for predefined sids
     250             :                          */
     251        3665 :                         status = dom_sid_lookup_predefined_sid(&state->sids[i],
     252             :                                                                &tmp_name,
     253             :                                                                &sid_type,
     254             :                                                                &tmp_authority_sid,
     255             :                                                                &tmp_authority_name);
     256        3665 :                         if (NT_STATUS_IS_OK(status)) {
     257         213 :                                 t->type_hint = lsa_SidType_to_id_type(sid_type);
     258         213 :                                 D_DEBUG("Got a type hint: %d from predefined SID.\n",
     259             :                                         t->type_hint);
     260             :                         }
     261             :                 }
     262             : 
     263        3665 :                 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        9273 :                 for (di = 0; di < state->cfg->num_doms; di++) {
     267        6868 :                         struct wb_parent_idmap_config_dom *dom =
     268        6868 :                                 &state->cfg->doms[di];
     269           0 :                         bool match;
     270             : 
     271        6868 :                         match = dom_sid_equal(&domain_sid, &dom->sid);
     272        6868 :                         if (!match) {
     273        5608 :                                 continue;
     274             :                         }
     275             : 
     276        1260 :                         domain_name = dom->name;
     277        1260 :                         D_DEBUG("Found domain '%s'.\n", domain_name);
     278        1260 :                         break;
     279             :                 }
     280        3665 :                 if (domain_name == NULL) {
     281        2405 :                         struct winbindd_domain *wb_domain = NULL;
     282             : 
     283        2405 :                         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        2405 :                         wb_domain = find_domain_from_sid_noinit(&state->sids[i]);
     289        2405 :                         if (wb_domain != NULL) {
     290         971 :                                 domain_name = wb_domain->name;
     291         971 :                                 D_DEBUG("Found domain '%s' in list of known domains.\n", domain_name);
     292             :                         }
     293             :                 }
     294        3665 :                 if (domain_name == NULL) {
     295        1434 :                         domain_name = "";
     296        1434 :                         D_DEBUG("Not found domain in list of known domains, setting empty domain name.\n");
     297             :                 }
     298             : 
     299        3665 :                 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
     300        3458 :                         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        2231 :                                 t->type_hint = ID_TYPE_BOTH;
     308        2231 :                                 D_DEBUG("Setting type hint ID_TYPE_BOTH for domain '%s'.\n", domain_name);
     309             :                         }
     310             :                 }
     311             : 
     312        3665 :                 domain_index = init_lsa_ref_domain_list(state,
     313             :                                                         &state->idmap_doms,
     314             :                                                         domain_name,
     315             :                                                         &domain_sid);
     316        3665 :                 if (domain_index == -1) {
     317           0 :                         tevent_req_oom(req);
     318           0 :                         return;
     319             :                 }
     320        3665 :                 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        2828 :         wb_sids2xids_next_sids2unix(req);
     332             : }
     333             : 
     334      212240 : static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
     335             : {
     336           0 :         struct unixid id;
     337           0 :         bool expired;
     338             : 
     339      212240 :         if (!winbindd_use_idmap_cache()) {
     340           0 :                 return false;
     341             :         }
     342      212240 :         if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
     343      208575 :                 if (expired && is_domain_online(find_our_domain())) {
     344           0 :                         return false;
     345             :                 }
     346      208575 :                 map->sid = sid;
     347      208575 :                 map->xid = id;
     348      208575 :                 map->status = ID_MAPPED;
     349      208575 :                 return true;
     350             :         }
     351        3665 :         return false;
     352             : }
     353             : 
     354        1454 : static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
     355             : {
     356        1454 :         struct tevent_req *req = tevent_req_callback_data(
     357             :                 subreq, struct tevent_req);
     358        1454 :         struct wb_sids2xids_state *state = tevent_req_data(
     359             :                 req, struct wb_sids2xids_state);
     360        1454 :         struct lsa_RefDomainList *domains = NULL;
     361        1454 :         struct lsa_TransNameArray *names = NULL;
     362           0 :         NTSTATUS status;
     363           0 :         uint32_t li;
     364             : 
     365        1454 :         status = wb_lookupsids_recv(subreq, state, &domains, &names);
     366        1454 :         TALLOC_FREE(subreq);
     367        1454 :         if (tevent_req_nterror(req, status)) {
     368         728 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     369         728 :                 return;
     370             :         }
     371             : 
     372         726 :         if (domains == NULL) {
     373           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     374           0 :                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     375           0 :                 return;
     376             :         }
     377             : 
     378         726 :         if (names == NULL) {
     379           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     380           0 :                 D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     381           0 :                 return;
     382             :         }
     383             : 
     384        1460 :         for (li = 0; li < state->lookup_count; li++) {
     385         734 :                 struct lsa_TranslatedName *n = &names->names[li];
     386         734 :                 uint32_t ai = state->tmp_idx[li];
     387         734 :                 struct wbint_TransID *t = &state->all_ids.ids[ai];
     388           0 :                 enum id_type type_hint;
     389             : 
     390         734 :                 type_hint = lsa_SidType_to_id_type(n->sid_type);
     391         734 :                 if (type_hint != ID_TYPE_NOT_SPECIFIED) {
     392             :                         /*
     393             :                          * We know it's a valid user or group.
     394             :                          */
     395         714 :                         t->type_hint = type_hint;
     396         714 :                         continue;
     397             :                 }
     398             : 
     399          20 :                 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          14 :                         t->domain_index = UINT32_MAX; /* mark as valid */
     407          14 :                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
     408          14 :                         continue;
     409             :                 }
     410             : 
     411           6 :                 if (n->sid_index >= domains->count) {
     412           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     413           0 :                         D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     414           0 :                         return;
     415             :                 }
     416             : 
     417           6 :                 if (domains->domains[n->sid_index].name.string == NULL) {
     418           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     419           0 :                         D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     420           0 :                         return;
     421             :                 }
     422           6 :                 if (domains->domains[n->sid_index].sid == NULL) {
     423           0 :                         tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     424           0 :                         D_WARNING("Failed with NT_STATUS_INTERNAL_ERROR.\n");
     425           0 :                         return;
     426             :                 }
     427             : 
     428           6 :                 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           6 :                         t->domain_index = UINT32_MAX; /* mark as valid */
     436           6 :                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
     437           6 :                         continue;
     438             :                 }
     439             : 
     440             :                 /*
     441             :                  * We only know the domain exists, but the user doesn't
     442             :                  */
     443           0 :                 t->type_hint = ID_TYPE_BOTH;
     444             :         }
     445             : 
     446         726 :         TALLOC_FREE(names);
     447         726 :         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         726 :         state->dom_index = 0;
     454         726 :         wb_sids2xids_next_sids2unix(req);
     455             : }
     456             : 
     457        7719 : static void wb_sids2xids_next_sids2unix(struct tevent_req *req)
     458             : {
     459        7719 :         struct wb_sids2xids_state *state = tevent_req_data(
     460             :                 req, struct wb_sids2xids_state);
     461        7719 :         struct tevent_req *subreq = NULL;
     462        7719 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     463        7719 :         const struct wbint_TransIDArray *src = NULL;
     464        7719 :         struct wbint_TransIDArray *dst = NULL;
     465           0 :         uint32_t si;
     466             : 
     467        7739 :  next_domain:
     468        7739 :         state->tried_dclookup = false;
     469             : 
     470        7739 :         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        7739 :         if (state->dom_index == state->idmap_doms.count) {
     475        3554 :                 if (state->lookup_count != 0) {
     476             :                         /*
     477             :                          * We already called wb_lookupsids_send()
     478             :                          * before, so we're done.
     479             :                          */
     480         726 :                         D_DEBUG("We already called wb_lookupsids_send() before, so we're done.\n");
     481         726 :                         tevent_req_done(req);
     482        3554 :                         return;
     483             :                 }
     484             : 
     485        6523 :                 for (si=0; si < state->num_sids; si++) {
     486        3695 :                         struct wbint_TransID *t = &state->all_ids.ids[si];
     487             : 
     488        3695 :                         if (t->domain_index == UINT32_MAX) {
     489             :                                 /* ignore already filled entries */
     490        1735 :                                 continue;
     491             :                         }
     492             : 
     493        1960 :                         state->tmp_idx[state->lookup_count] = si;
     494        1960 :                         sid_copy(&state->lookup_sids[state->lookup_count],
     495        1960 :                                  &state->sids[si]);
     496        1960 :                         state->lookup_count += 1;
     497             :                 }
     498             : 
     499        2828 :                 D_DEBUG("Prepared %"PRIu32" SID(s) for lookup wb_lookupsids_send().\n",
     500             :                         state->lookup_count);
     501        2828 :                 if (state->lookup_count == 0) {
     502             :                         /*
     503             :                          * no wb_lookupsids_send() needed...
     504             :                          */
     505        1374 :                         tevent_req_done(req);
     506        1374 :                         return;
     507             :                 }
     508             : 
     509        1454 :                 subreq = wb_lookupsids_send(state,
     510             :                                             state->ev,
     511             :                                             state->lookup_sids,
     512             :                                             state->lookup_count);
     513        1454 :                 if (tevent_req_nomem(subreq, req)) {
     514           0 :                         return;
     515             :                 }
     516        1454 :                 tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
     517        1454 :                 return;
     518             :         }
     519             : 
     520        4185 :         src = &state->all_ids;
     521        4185 :         dst = &state->map_ids_in;
     522        4185 :         dst->num_ids = 0;
     523             : 
     524       10653 :         for (si=0; si < src->num_ids; si++) {
     525        6468 :                 if (src->ids[si].domain_index != state->dom_index) {
     526        2089 :                         continue;
     527             :                 }
     528             : 
     529        4379 :                 state->tmp_idx[dst->num_ids] = si;
     530        4379 :                 dst->ids[dst->num_ids] = src->ids[si];
     531        4379 :                 dst->ids[dst->num_ids].domain_index = 0;
     532        4379 :                 dst->num_ids += 1;
     533             :         }
     534             : 
     535        4185 :         if (dst->num_ids == 0) {
     536          20 :                 state->dom_index += 1;
     537          20 :                 D_DEBUG("Go to next domain.\n");
     538          20 :                 goto next_domain;
     539             :         }
     540             : 
     541        4165 :         state->idmap_dom = (struct lsa_RefDomainList) {
     542             :                 .count = 1,
     543        4165 :                 .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        4165 :         state->map_ids_out = state->map_ids_in;
     560        4165 :         child_binding_handle = idmap_child_handle();
     561        4165 :         subreq = dcerpc_wbint_Sids2UnixIDs_send(
     562             :                 state, state->ev, child_binding_handle, &state->idmap_dom,
     563             :                 &state->map_ids_out);
     564        4165 :         if (tevent_req_nomem(subreq, req)) {
     565           0 :                 return;
     566             :         }
     567        4165 :         tevent_req_set_callback(subreq, wb_sids2xids_done, req);
     568             : }
     569             : 
     570         947 : static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
     571             : {
     572           0 :         enum id_type type;
     573             : 
     574         947 :         switch(sid_type) {
     575         366 :         case SID_NAME_COMPUTER:
     576             :         case SID_NAME_USER:
     577         366 :                 type = ID_TYPE_UID;
     578         366 :                 break;
     579         555 :         case SID_NAME_DOM_GRP:
     580             :         case SID_NAME_ALIAS:
     581             :         case SID_NAME_WKN_GRP:
     582         555 :                 type = ID_TYPE_GID;
     583         555 :                 break;
     584          26 :         default:
     585          26 :                 type = ID_TYPE_NOT_SPECIFIED;
     586          26 :                 break;
     587             :         }
     588             : 
     589         947 :         return type;
     590             : }
     591             : 
     592        4167 : static void wb_sids2xids_done(struct tevent_req *subreq)
     593             : {
     594        4167 :         struct tevent_req *req = tevent_req_callback_data(
     595             :                 subreq, struct tevent_req);
     596        4167 :         struct wb_sids2xids_state *state = tevent_req_data(
     597             :                 req, struct wb_sids2xids_state);
     598           0 :         NTSTATUS status, result;
     599        4167 :         const struct wbint_TransIDArray *src = NULL;
     600        4167 :         struct wbint_TransIDArray *dst = NULL;
     601           0 :         uint32_t si;
     602             : 
     603        4167 :         status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
     604        4167 :         TALLOC_FREE(subreq);
     605             : 
     606        4167 :         if (tevent_req_nterror(req, status)) {
     607           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     608           2 :                 return;
     609             :         }
     610             : 
     611        4167 :         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
     612           2 :             !state->tried_dclookup) {
     613             : 
     614           0 :                 struct lsa_DomainInfo *d;
     615             : 
     616           2 :                 D_DEBUG("Domain controller not found. Calling wb_dsgetdcname_send() to get it.\n");
     617           2 :                 d = &state->idmap_doms.domains[state->dom_index];
     618             : 
     619           2 :                 subreq = wb_dsgetdcname_send(
     620             :                         state, state->ev, d->name.string, NULL, NULL,
     621             :                         DS_RETURN_DNS_NAME);
     622           2 :                 if (tevent_req_nomem(subreq, req)) {
     623           2 :                         return;
     624             :                 }
     625           2 :                 tevent_req_set_callback(subreq, wb_sids2xids_gotdc, req);
     626           2 :                 return;
     627             :         }
     628             : 
     629        4165 :         src = &state->map_ids_out;
     630        4165 :         dst = &state->all_ids;
     631             : 
     632        4165 :         if (any_nt_status_not_ok(status, result, &status)) {
     633           0 :                 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           0 :                 src = &state->map_ids_in;
     640           0 :                 for (si=0; si < src->num_ids; si++) {
     641           0 :                         src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
     642             :                 }
     643             :         }
     644             : 
     645        4165 :         if (src->num_ids != state->map_ids_in.num_ids) {
     646           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     647           0 :                 D_WARNING("Number of mapped SIDs does not match. Failing with NT_STATUS_INTERNAL_ERROR.\n");
     648           0 :                 return;
     649             :         }
     650             : 
     651        8544 :         for (si=0; si < src->num_ids; si++) {
     652        4379 :                 uint32_t di = state->tmp_idx[si];
     653             : 
     654        4379 :                 if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) {
     655        1960 :                         if (state->lookup_count == 0) {
     656        1960 :                                 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        1960 :                                 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           0 :                         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           0 :                         src->ids[si].xid.type = ID_TYPE_NOT_SPECIFIED;
     674             :                 }
     675             : 
     676        2419 :                 if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) {
     677        2326 :                         dst->ids[di].xid = src->ids[si].xid;
     678        2326 :                         D_DEBUG("%"PRIu32": Setting XID %"PRIu32"\n",
     679             :                                 si, src->ids[si].xid.id);
     680             :                 }
     681        2419 :                 dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */
     682        2419 :                 idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid);
     683             :         }
     684             : 
     685        4165 :         state->map_ids_in.num_ids = 0;
     686        4165 :         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        4165 :                 SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids);
     693        4165 :                 TALLOC_FREE(state->map_ids_out.ids);
     694             :         }
     695        4165 :         state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, };
     696             : 
     697        4165 :         state->dom_index += 1;
     698             : 
     699        4165 :         wb_sids2xids_next_sids2unix(req);
     700             : }
     701             : 
     702           2 : static void wb_sids2xids_gotdc(struct tevent_req *subreq)
     703             : {
     704           2 :         struct tevent_req *req = tevent_req_callback_data(
     705             :                 subreq, struct tevent_req);
     706           2 :         struct wb_sids2xids_state *state = tevent_req_data(
     707             :                 req, struct wb_sids2xids_state);
     708           2 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     709           0 :         struct netr_DsRGetDCNameInfo *dcinfo;
     710           0 :         NTSTATUS status;
     711             : 
     712           2 :         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
     713           2 :         TALLOC_FREE(subreq);
     714           2 :         if (tevent_req_nterror(req, status)) {
     715           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     716           0 :                 return;
     717             :         }
     718             : 
     719           2 :         state->tried_dclookup = true;
     720             : 
     721             :         {
     722           2 :                 struct lsa_DomainInfo *d =
     723           2 :                         &state->idmap_doms.domains[state->dom_index];
     724           2 :                 const char *dom_name = d->name.string;
     725             : 
     726           2 :                 status = wb_dsgetdcname_gencache_set(dom_name, dcinfo);
     727           2 :                 if (tevent_req_nterror(req, status)) {
     728           0 :                         D_WARNING("Failed with %s.\n", nt_errstr(status));
     729           0 :                         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           2 :         state->map_ids_out = state->map_ids_in;
     746           2 :         child_binding_handle = idmap_child_handle();
     747           2 :         subreq = dcerpc_wbint_Sids2UnixIDs_send(
     748             :                 state, state->ev, child_binding_handle, &state->idmap_dom,
     749             :                 &state->map_ids_out);
     750           2 :         if (tevent_req_nomem(subreq, req)) {
     751           0 :                 return;
     752             :         }
     753           2 :         tevent_req_set_callback(subreq, wb_sids2xids_done, req);
     754             : }
     755             : 
     756      209161 : NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
     757             :                            struct unixid xids[], uint32_t num_xids)
     758             : {
     759      209161 :         struct wb_sids2xids_state *state = tevent_req_data(
     760             :                 req, struct wb_sids2xids_state);
     761           0 :         NTSTATUS status;
     762           0 :         uint32_t i;
     763             : 
     764      209161 :         if (tevent_req_is_nterror(req, &status)) {
     765         728 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     766         728 :                 return status;
     767             :         }
     768             : 
     769      208433 :         if (num_xids != state->num_sids) {
     770           0 :                 D_WARNING("Error. We have resolved only %"PRIu32" XID(s), but caller asked for %"PRIu32".\n",
     771             :                           state->num_sids, num_xids);
     772           0 :                 return NT_STATUS_INTERNAL_ERROR;
     773             :         }
     774             : 
     775      208433 :         D_INFO("WB command sids2xids end.\n");
     776      419426 :         for (i=0; i<state->num_sids; i++) {
     777           0 :                 struct dom_sid_buf buf;
     778      210993 :                 xids[i] = state->all_ids.ids[i].xid;
     779      210993 :                 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      208433 :         return NT_STATUS_OK;
     786             : }

Generated by: LCOV version 1.14