LCOV - code coverage report
Current view: top level - source3/winbindd - wb_sids2xids.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 274 322 85.1 %
Date: 2024-06-13 04:01:37 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       17616 : 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       17616 :         uint32_t num_valid = 0;
      83             : 
      84       17616 :         D_INFO("WB command sids2xids start.\n"
      85             :                "Resolving %"PRIu32" SID(s).\n", num_sids);
      86             : 
      87       17616 :         req = tevent_req_create(mem_ctx, &state,
      88             :                                 struct wb_sids2xids_state);
      89       17616 :         if (req == NULL) {
      90           0 :                 return NULL;
      91             :         }
      92             : 
      93       17616 :         state->ev = ev;
      94             : 
      95       17616 :         state->num_sids = num_sids;
      96             : 
      97       17616 :         state->sids = talloc_zero_array(state, struct dom_sid, num_sids);
      98       17616 :         if (tevent_req_nomem(state->sids, req)) {
      99           0 :                 return tevent_req_post(req, ev);
     100             :         }
     101             : 
     102       77218 :         for (i = 0; i < num_sids; i++) {
     103       59602 :                 sid_copy(&state->sids[i], &sids[i]);
     104             :         }
     105             : 
     106       17616 :         state->all_ids.num_ids = num_sids;
     107       17616 :         state->all_ids.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
     108       17616 :         if (tevent_req_nomem(state->all_ids.ids, req)) {
     109           0 :                 return tevent_req_post(req, ev);
     110             :         }
     111             : 
     112       17616 :         state->tmp_idx = talloc_zero_array(state, uint32_t, num_sids);
     113       17616 :         if (tevent_req_nomem(state->tmp_idx, req)) {
     114           0 :                 return tevent_req_post(req, ev);
     115             :         }
     116             : 
     117       17616 :         state->lookup_sids = talloc_zero_array(state, struct dom_sid, num_sids);
     118       17616 :         if (tevent_req_nomem(state->lookup_sids, req)) {
     119           0 :                 return tevent_req_post(req, ev);
     120             :         }
     121             : 
     122       17616 :         state->map_ids_in.ids = talloc_zero_array(state, struct wbint_TransID, num_sids);
     123       17616 :         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       77218 :         for (i=0; i<state->num_sids; i++) {
     133       59602 :                 struct wbint_TransID *cur_id = &state->all_ids.ids[i];
     134             :                 struct dom_sid domain_sid;
     135             :                 struct dom_sid_buf buf;
     136       59602 :                 struct id_map map = { .status = ID_UNMAPPED, };
     137       59602 :                 uint32_t rid = 0;
     138             :                 bool in_cache;
     139             : 
     140       59602 :                 sid_copy(&domain_sid, &state->sids[i]);
     141       59602 :                 sid_split_rid(&domain_sid, &rid);
     142             : 
     143             :                 /*
     144             :                  * Start with an invalid entry.
     145             :                  */
     146       59602 :                 *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       59602 :                 D_DEBUG("%"PRIu32": SID %s\n",
     157             :                         i, dom_sid_str_buf(&state->sids[i], &buf));
     158             : 
     159       59602 :                 in_cache = wb_sids2xids_in_cache(&state->sids[i], &map);
     160       59602 :                 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       57899 :                         cur_id->xid = map.xid;
     169       57899 :                         cur_id->domain_index = UINT32_MAX; /* this marks it as filled entry */
     170       57899 :                         num_valid += 1;
     171       57899 :                         continue;
     172             :                 }
     173             :         }
     174             : 
     175       17616 :         D_DEBUG("Found %"PRIu32" (out of %"PRIu32") SID(s) in cache.\n",
     176             :                 num_valid, num_sids);
     177       17616 :         if (num_valid == num_sids) {
     178       16495 :                 tevent_req_done(req);
     179       16495 :                 return tevent_req_post(req, ev);
     180             :         }
     181             : 
     182        1121 :         subreq = wb_parent_idmap_setup_send(state, state->ev);
     183        1121 :         if (tevent_req_nomem(subreq, req)) {
     184           0 :                 return tevent_req_post(req, ev);
     185             :         }
     186        1121 :         tevent_req_set_callback(subreq, wb_sids2xids_idmap_setup_done, req);
     187        1121 :         return req;
     188             : }
     189             : 
     190        1121 : static void wb_sids2xids_idmap_setup_done(struct tevent_req *subreq)
     191             : {
     192        1121 :         struct tevent_req *req = tevent_req_callback_data(
     193             :                 subreq, struct tevent_req);
     194        1121 :         struct wb_sids2xids_state *state = tevent_req_data(
     195             :                 req, struct wb_sids2xids_state);
     196             :         NTSTATUS status;
     197             :         uint32_t i;
     198             : 
     199        1121 :         status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
     200        1121 :         TALLOC_FREE(subreq);
     201        1121 :         if (tevent_req_nterror(req, status)) {
     202           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     203           0 :                 return;
     204             :         }
     205        1121 :         SMB_ASSERT(state->cfg->num_doms > 0);
     206        1121 :         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        4891 :         for (i=0; i<state->num_sids; i++) {
     215        3770 :                 struct wbint_TransID *t = &state->all_ids.ids[i];
     216             :                 struct dom_sid domain_sid;
     217        3770 :                 const char *domain_name = NULL;
     218             :                 int domain_index;
     219        3770 :                 uint32_t rid = 0;
     220             :                 uint32_t di;
     221             :                 struct dom_sid_buf buf0, buf1;
     222             : 
     223        3770 :                 D_DEBUG("%"PRIu32": Processing SID %s\n",
     224             :                         i,
     225             :                         dom_sid_str_buf(&state->sids[i], &buf0));
     226        3770 :                 if (t->domain_index == UINT32_MAX) {
     227             :                         /* ignore already filled entries */
     228        2067 :                         D_DEBUG("%"PRIu32": Ignoring already resolved SID %s\n",
     229             :                                 i,
     230             :                                 dom_sid_str_buf(&state->sids[i], &buf0));
     231        2067 :                         continue;
     232             :                 }
     233             : 
     234        1703 :                 sid_copy(&domain_sid, &state->sids[i]);
     235        1703 :                 sid_split_rid(&domain_sid, &rid);
     236        1703 :                 D_DEBUG("%"PRIu32": Splitted 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        1703 :                 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
     243        1703 :                         const char *tmp_name = NULL;
     244        1703 :                         enum lsa_SidType sid_type = SID_NAME_USE_NONE;
     245        1703 :                         const struct dom_sid *tmp_authority_sid = NULL;
     246        1703 :                         const char *tmp_authority_name = NULL;
     247             : 
     248             :                         /*
     249             :                          * Try to get a type hint from for predefined sids
     250             :                          */
     251        1703 :                         status = dom_sid_lookup_predefined_sid(&state->sids[i],
     252             :                                                                &tmp_name,
     253             :                                                                &sid_type,
     254             :                                                                &tmp_authority_sid,
     255             :                                                                &tmp_authority_name);
     256        1703 :                         if (NT_STATUS_IS_OK(status)) {
     257         170 :                                 t->type_hint = lsa_SidType_to_id_type(sid_type);
     258         170 :                                 D_DEBUG("Got a type hint: %d from predefined SID.\n",
     259             :                                         t->type_hint);
     260             :                         }
     261             :                 }
     262             : 
     263        1703 :                 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        6824 :                 for (di = 0; di < state->cfg->num_doms; di++) {
     267        3109 :                         struct wb_parent_idmap_config_dom *dom =
     268        3109 :                                 &state->cfg->doms[di];
     269             :                         bool match;
     270             : 
     271        3109 :                         match = dom_sid_equal(&domain_sid, &dom->sid);
     272        3109 :                         if (!match) {
     273        2524 :                                 continue;
     274             :                         }
     275             : 
     276         585 :                         domain_name = dom->name;
     277         585 :                         D_DEBUG("Found domain '%s'.\n", domain_name);
     278         585 :                         break;
     279             :                 }
     280        1703 :                 if (domain_name == NULL) {
     281        1118 :                         struct winbindd_domain *wb_domain = NULL;
     282             : 
     283        1118 :                         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        1118 :                         wb_domain = find_domain_from_sid_noinit(&state->sids[i]);
     289        1118 :                         if (wb_domain != NULL) {
     290         377 :                                 domain_name = wb_domain->name;
     291         377 :                                 D_DEBUG("Found domain '%s' in list of known domains.\n", domain_name);
     292             :                         }
     293             :                 }
     294        1703 :                 if (domain_name == NULL) {
     295         741 :                         domain_name = "";
     296         741 :                         D_DEBUG("Not found domain in list of known domains, setting empty domain name.\n");
     297             :                 }
     298             : 
     299        1703 :                 if (t->type_hint == ID_TYPE_NOT_SPECIFIED) {
     300        1540 :                         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         962 :                                 t->type_hint = ID_TYPE_BOTH;
     308         962 :                                 D_DEBUG("Setting type hint ID_TYPE_BOTH for domain '%s'.\n", domain_name);
     309             :                         }
     310             :                 }
     311             : 
     312        1703 :                 domain_index = init_lsa_ref_domain_list(state,
     313             :                                                         &state->idmap_doms,
     314             :                                                         domain_name,
     315             :                                                         &domain_sid);
     316        1703 :                 if (domain_index == -1) {
     317           0 :                         tevent_req_oom(req);
     318           0 :                         return;
     319             :                 }
     320        1703 :                 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        1121 :         wb_sids2xids_next_sids2unix(req);
     332             : }
     333             : 
     334       59602 : static bool wb_sids2xids_in_cache(struct dom_sid *sid, struct id_map *map)
     335             : {
     336             :         struct unixid id;
     337             :         bool expired;
     338             : 
     339       59602 :         if (!winbindd_use_idmap_cache()) {
     340           0 :                 return false;
     341             :         }
     342       59602 :         if (idmap_cache_find_sid2unixid(sid, &id, &expired)) {
     343       57899 :                 if (expired && is_domain_online(find_our_domain())) {
     344           0 :                         return false;
     345             :                 }
     346       57899 :                 map->sid = sid;
     347       57899 :                 map->xid = id;
     348       57899 :                 map->status = ID_MAPPED;
     349       57899 :                 return true;
     350             :         }
     351        1703 :         return false;
     352             : }
     353             : 
     354         609 : static void wb_sids2xids_lookupsids_done(struct tevent_req *subreq)
     355             : {
     356         609 :         struct tevent_req *req = tevent_req_callback_data(
     357             :                 subreq, struct tevent_req);
     358         609 :         struct wb_sids2xids_state *state = tevent_req_data(
     359             :                 req, struct wb_sids2xids_state);
     360         609 :         struct lsa_RefDomainList *domains = NULL;
     361         609 :         struct lsa_TransNameArray *names = NULL;
     362             :         NTSTATUS status;
     363             :         uint32_t li;
     364             : 
     365         609 :         status = wb_lookupsids_recv(subreq, state, &domains, &names);
     366         609 :         TALLOC_FREE(subreq);
     367         609 :         if (tevent_req_nterror(req, status)) {
     368         516 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     369         774 :                 return;
     370             :         }
     371             : 
     372          93 :         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          93 :         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         194 :         for (li = 0; li < state->lookup_count; li++) {
     385         101 :                 struct lsa_TranslatedName *n = &names->names[li];
     386         101 :                 uint32_t ai = state->tmp_idx[li];
     387         101 :                 struct wbint_TransID *t = &state->all_ids.ids[ai];
     388             :                 enum id_type type_hint;
     389             : 
     390         101 :                 type_hint = lsa_SidType_to_id_type(n->sid_type);
     391         101 :                 if (type_hint != ID_TYPE_NOT_SPECIFIED) {
     392             :                         /*
     393             :                          * We know it's a valid user or group.
     394             :                          */
     395          84 :                         t->type_hint = type_hint;
     396          84 :                         continue;
     397             :                 }
     398             : 
     399          17 :                 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          10 :                         t->domain_index = UINT32_MAX; /* mark as valid */
     407          10 :                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
     408          10 :                         continue;
     409             :                 }
     410             : 
     411           7 :                 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           7 :                 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           7 :                 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           7 :                 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           7 :                         t->domain_index = UINT32_MAX; /* mark as valid */
     436           7 :                         idmap_cache_set_sid2unixid(&state->sids[ai], &t->xid);
     437           7 :                         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          93 :         TALLOC_FREE(names);
     447          93 :         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          93 :         state->dom_index = 0;
     454          93 :         wb_sids2xids_next_sids2unix(req);
     455             : }
     456             : 
     457        2601 : static void wb_sids2xids_next_sids2unix(struct tevent_req *req)
     458             : {
     459        2601 :         struct wb_sids2xids_state *state = tevent_req_data(
     460             :                 req, struct wb_sids2xids_state);
     461        2601 :         struct tevent_req *subreq = NULL;
     462        2601 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     463        2601 :         const struct wbint_TransIDArray *src = NULL;
     464        2601 :         struct wbint_TransIDArray *dst = NULL;
     465             :         uint32_t si;
     466             : 
     467        2618 :  next_domain:
     468        2618 :         state->tried_dclookup = false;
     469             : 
     470        2618 :         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        2618 :         if (state->dom_index == state->idmap_doms.count) {
     475        1203 :                 if (state->lookup_count != 0) {
     476             :                         /*
     477             :                          * We already called wb_lookupsids_send()
     478             :                          * before, so we're done.
     479             :                          */
     480          93 :                         D_DEBUG("We already called wb_lookupsids_send() before, so we're done.\n");
     481          93 :                         tevent_req_done(req);
     482         479 :                         return;
     483             :                 }
     484             : 
     485        4736 :                 for (si=0; si < state->num_sids; si++) {
     486        3626 :                         struct wbint_TransID *t = &state->all_ids.ids[si];
     487             : 
     488        3626 :                         if (t->domain_index == UINT32_MAX) {
     489             :                                 /* ignore already filled entries */
     490        2959 :                                 continue;
     491             :                         }
     492             : 
     493         667 :                         state->tmp_idx[state->lookup_count] = si;
     494         667 :                         sid_copy(&state->lookup_sids[state->lookup_count],
     495         667 :                                  &state->sids[si]);
     496         667 :                         state->lookup_count += 1;
     497             :                 }
     498             : 
     499        1110 :                 D_DEBUG("Prepared %"PRIu32" SID(s) for lookup wb_lookupsids_send().\n",
     500             :                         state->lookup_count);
     501        1110 :                 if (state->lookup_count == 0) {
     502             :                         /*
     503             :                          * no wb_lookupsids_send() needed...
     504             :                          */
     505         501 :                         tevent_req_done(req);
     506         501 :                         return;
     507             :                 }
     508             : 
     509         609 :                 subreq = wb_lookupsids_send(state,
     510             :                                             state->ev,
     511             :                                             state->lookup_sids,
     512             :                                             state->lookup_count);
     513         609 :                 if (tevent_req_nomem(subreq, req)) {
     514           0 :                         return;
     515             :                 }
     516         609 :                 tevent_req_set_callback(subreq, wb_sids2xids_lookupsids_done, req);
     517         609 :                 return;
     518             :         }
     519             : 
     520        1415 :         src = &state->all_ids;
     521        1415 :         dst = &state->map_ids_in;
     522        1415 :         dst->num_ids = 0;
     523             : 
     524        6842 :         for (si=0; si < src->num_ids; si++) {
     525        5427 :                 if (src->ids[si].domain_index != state->dom_index) {
     526        3676 :                         continue;
     527             :                 }
     528             : 
     529        1751 :                 state->tmp_idx[dst->num_ids] = si;
     530        1751 :                 dst->ids[dst->num_ids] = src->ids[si];
     531        1751 :                 dst->ids[dst->num_ids].domain_index = 0;
     532        1751 :                 dst->num_ids += 1;
     533             :         }
     534             : 
     535        1415 :         if (dst->num_ids == 0) {
     536          17 :                 state->dom_index += 1;
     537          17 :                 D_DEBUG("Go to next domain.\n");
     538          17 :                 goto next_domain;
     539             :         }
     540             : 
     541        1398 :         state->idmap_dom = (struct lsa_RefDomainList) {
     542             :                 .count = 1,
     543        1398 :                 .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        1398 :         state->map_ids_out = state->map_ids_in;
     560        1398 :         child_binding_handle = idmap_child_handle();
     561        1398 :         subreq = dcerpc_wbint_Sids2UnixIDs_send(
     562             :                 state, state->ev, child_binding_handle, &state->idmap_dom,
     563             :                 &state->map_ids_out);
     564        1398 :         if (tevent_req_nomem(subreq, req)) {
     565           0 :                 return;
     566             :         }
     567        1398 :         tevent_req_set_callback(subreq, wb_sids2xids_done, req);
     568             : }
     569             : 
     570         271 : static enum id_type lsa_SidType_to_id_type(const enum lsa_SidType sid_type)
     571             : {
     572             :         enum id_type type;
     573             : 
     574         271 :         switch(sid_type) {
     575          42 :         case SID_NAME_COMPUTER:
     576             :         case SID_NAME_USER:
     577          42 :                 type = ID_TYPE_UID;
     578          42 :                 break;
     579         205 :         case SID_NAME_DOM_GRP:
     580             :         case SID_NAME_ALIAS:
     581             :         case SID_NAME_WKN_GRP:
     582         205 :                 type = ID_TYPE_GID;
     583         205 :                 break;
     584          24 :         default:
     585          24 :                 type = ID_TYPE_NOT_SPECIFIED;
     586          24 :                 break;
     587             :         }
     588             : 
     589         271 :         return type;
     590             : }
     591             : 
     592        1389 : static void wb_sids2xids_done(struct tevent_req *subreq)
     593             : {
     594        1389 :         struct tevent_req *req = tevent_req_callback_data(
     595             :                 subreq, struct tevent_req);
     596        1389 :         struct wb_sids2xids_state *state = tevent_req_data(
     597             :                 req, struct wb_sids2xids_state);
     598             :         NTSTATUS status, result;
     599        1389 :         const struct wbint_TransIDArray *src = NULL;
     600        1389 :         struct wbint_TransIDArray *dst = NULL;
     601             :         uint32_t si;
     602             : 
     603        1389 :         status = dcerpc_wbint_Sids2UnixIDs_recv(subreq, state, &result);
     604        1389 :         TALLOC_FREE(subreq);
     605             : 
     606        1389 :         if (tevent_req_nterror(req, status)) {
     607           0 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     608           2 :                 return;
     609             :         }
     610             : 
     611        1390 :         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
     612           2 :             !state->tried_dclookup) {
     613             : 
     614             :                 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           1 :                         return;
     624             :                 }
     625           2 :                 tevent_req_set_callback(subreq, wb_sids2xids_gotdc, req);
     626           2 :                 return;
     627             :         }
     628             : 
     629        1387 :         src = &state->map_ids_out;
     630        1387 :         dst = &state->all_ids;
     631             : 
     632        1387 :         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        1387 :         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        3091 :         for (si=0; si < src->num_ids; si++) {
     652        1704 :                 uint32_t di = state->tmp_idx[si];
     653             : 
     654        1704 :                 if (src->ids[si].xid.type == ID_TYPE_WB_REQUIRE_TYPE) {
     655         667 :                         if (state->lookup_count == 0) {
     656         667 :                                 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         667 :                                 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        1037 :                 if (src->ids[si].xid.type != ID_TYPE_NOT_SPECIFIED) {
     677         977 :                         dst->ids[di].xid = src->ids[si].xid;
     678         977 :                         D_DEBUG("%"PRIu32": Setting XID %"PRIu32"\n",
     679             :                                 si, src->ids[si].xid.id);
     680             :                 }
     681        1037 :                 dst->ids[di].domain_index = UINT32_MAX; /* mark as valid */
     682        1037 :                 idmap_cache_set_sid2unixid(&state->sids[di], &dst->ids[di].xid);
     683             :         }
     684             : 
     685        1387 :         state->map_ids_in.num_ids = 0;
     686        1387 :         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        1387 :                 SMB_ASSERT(state->map_ids_out.ids != state->map_ids_in.ids);
     693        1387 :                 TALLOC_FREE(state->map_ids_out.ids);
     694             :         }
     695        1387 :         state->map_ids_out = (struct wbint_TransIDArray) { .num_ids = 0, };
     696             : 
     697        1387 :         state->dom_index += 1;
     698             : 
     699        1387 :         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             :         struct netr_DsRGetDCNameInfo *dcinfo;
     710             :         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       17605 : NTSTATUS wb_sids2xids_recv(struct tevent_req *req,
     757             :                            struct unixid xids[], uint32_t num_xids)
     758             : {
     759       17605 :         struct wb_sids2xids_state *state = tevent_req_data(
     760             :                 req, struct wb_sids2xids_state);
     761             :         NTSTATUS status;
     762             :         uint32_t i;
     763             : 
     764       17605 :         if (tevent_req_is_nterror(req, &status)) {
     765         516 :                 D_WARNING("Failed with %s.\n", nt_errstr(status));
     766         516 :                 return status;
     767             :         }
     768             : 
     769       17089 :         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       17089 :         D_INFO("WB command sids2xids end.\n");
     776       75959 :         for (i=0; i<state->num_sids; i++) {
     777             :                 struct dom_sid_buf buf;
     778       58870 :                 xids[i] = state->all_ids.ids[i].xid;
     779       58870 :                 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       17089 :         return NT_STATUS_OK;
     786             : }

Generated by: LCOV version 1.13