LCOV - code coverage report
Current view: top level - source3/winbindd - wb_xids2sids.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 154 196 78.6 %
Date: 2024-04-21 15:09:00 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  * async xids2sids
       4             :  * Copyright (C) Volker Lendecke 2015
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "includes.h"
      21             : #include "winbindd.h"
      22             : #include "../libcli/security/security.h"
      23             : #include "idmap_cache.h"
      24             : #include "librpc/gen_ndr/ndr_winbind_c.h"
      25             : #include "librpc/gen_ndr/ndr_netlogon.h"
      26             : #include "passdb/lookup_sid.h"
      27             : 
      28             : struct wb_xids2sids_dom_state {
      29             :         struct tevent_context *ev;
      30             :         struct unixid *all_xids;
      31             :         const bool *cached;
      32             :         size_t num_all_xids;
      33             :         struct dom_sid *all_sids;
      34             :         const struct wb_parent_idmap_config_dom *dom_map;
      35             :         bool tried_dclookup;
      36             : 
      37             :         size_t num_dom_xids;
      38             :         struct unixid *dom_xids;
      39             :         struct dom_sid *dom_sids;
      40             : };
      41             : 
      42             : static void wb_xids2sids_dom_done(struct tevent_req *subreq);
      43             : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq);
      44             : 
      45       18056 : static struct tevent_req *wb_xids2sids_dom_send(
      46             :         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
      47             :         const struct wb_parent_idmap_config_dom *dom_map,
      48             :         struct unixid *xids,
      49             :         const bool *cached,
      50             :         size_t num_xids,
      51             :         struct dom_sid *sids)
      52             : {
      53           0 :         struct tevent_req *req, *subreq;
      54           0 :         struct wb_xids2sids_dom_state *state;
      55       18056 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
      56           0 :         size_t i;
      57             : 
      58       18056 :         req = tevent_req_create(mem_ctx, &state,
      59             :                                 struct wb_xids2sids_dom_state);
      60       18056 :         if (req == NULL) {
      61           0 :                 return NULL;
      62             :         }
      63             : 
      64       18056 :         D_DEBUG("Searching for %zu xid(s) in domain %s.\n",
      65             :                 num_xids,
      66             :                 dom_map->name);
      67             : 
      68       18056 :         state->ev = ev;
      69       18056 :         state->all_xids = xids;
      70       18056 :         state->cached = cached;
      71       18056 :         state->num_all_xids = num_xids;
      72       18056 :         state->all_sids = sids;
      73       18056 :         state->dom_map = dom_map;
      74             : 
      75       18056 :         state->dom_xids = talloc_array(state, struct unixid, num_xids);
      76       18056 :         if (tevent_req_nomem(state->dom_xids, req)) {
      77           0 :                 return tevent_req_post(req, ev);
      78             :         }
      79       18056 :         state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
      80       18056 :         if (tevent_req_nomem(state->dom_sids, req)) {
      81           0 :                 return tevent_req_post(req, ev);
      82             :         }
      83             : 
      84       36316 :         for (i=0; i<num_xids; i++) {
      85       18260 :                 struct unixid id = state->all_xids[i];
      86             : 
      87       18260 :                 if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
      88             :                         /* out of range */
      89        3408 :                         D_DEBUG("%zu: XID %"PRIu32" is out of range.\n",
      90             :                                 i, id.id);
      91       17638 :                         continue;
      92             :                 }
      93       14852 :                 if (state->cached[i]) {
      94             :                         /* already found in cache */
      95       14222 :                         D_DEBUG("%zu: XID %"PRIu32" is already found in cache.\n",
      96             :                                 i, id.id);
      97       14222 :                         continue;
      98             :                 }
      99         630 :                 if (!is_null_sid(&state->all_sids[i])) {
     100             :                         /* already mapped in a previously asked domain */
     101           8 :                         D_DEBUG("%zu: XID %"PRIu32" is already mapped in a previously asked domain.\n",
     102             :                                 i, id.id);
     103           8 :                         continue;
     104             :                 }
     105         622 :                 D_DEBUG("%zu: XID %"PRIu32" will be looked up via dcerpc_wbint_UnixIDs2Sids_send().\n",
     106             :                         i, id.id);
     107         622 :                 state->dom_xids[state->num_dom_xids++] = id;
     108             :         }
     109             : 
     110       18056 :         if (state->num_dom_xids == 0) {
     111       17570 :                 tevent_req_done(req);
     112       17570 :                 return tevent_req_post(req, ev);
     113             :         }
     114             : 
     115         486 :         child_binding_handle = idmap_child_handle();
     116         486 :         subreq = dcerpc_wbint_UnixIDs2Sids_send(
     117         486 :                 state, ev, child_binding_handle, dom_map->name, dom_map->sid,
     118         486 :                 state->num_dom_xids, state->dom_xids, state->dom_sids);
     119         486 :         if (tevent_req_nomem(subreq, req)) {
     120           0 :                 return tevent_req_post(req, ev);
     121             :         }
     122         486 :         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
     123         486 :         return req;
     124             : }
     125             : 
     126         488 : static void wb_xids2sids_dom_done(struct tevent_req *subreq)
     127             : {
     128         488 :         struct tevent_req *req = tevent_req_callback_data(
     129             :                 subreq, struct tevent_req);
     130         488 :         struct wb_xids2sids_dom_state *state = tevent_req_data(
     131             :                 req, struct wb_xids2sids_dom_state);
     132         488 :         const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
     133           0 :         NTSTATUS status, result;
     134           0 :         size_t i;
     135           0 :         size_t dom_sid_idx;
     136             : 
     137         488 :         status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
     138         488 :         TALLOC_FREE(subreq);
     139         488 :         if (tevent_req_nterror(req, status)) {
     140           2 :                 return;
     141             :         }
     142             : 
     143         488 :         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
     144           2 :             !state->tried_dclookup) {
     145             : 
     146           2 :                 subreq = wb_dsgetdcname_send(
     147           2 :                         state, state->ev, state->dom_map->name, NULL, NULL,
     148             :                         DS_RETURN_DNS_NAME);
     149           2 :                 if (tevent_req_nomem(subreq, req)) {
     150           2 :                         return;
     151             :                 }
     152           2 :                 tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
     153           2 :                 return;
     154             :         }
     155             : 
     156         972 :         if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
     157         486 :             tevent_req_nterror(req, result)) {
     158           0 :                 return;
     159             :         }
     160             : 
     161         486 :         dom_sid_idx = 0;
     162             : 
     163         486 :         D_DEBUG("Processing response for %zu xid(s).\n", state->num_all_xids);
     164        1108 :         for (i=0; i<state->num_all_xids; i++) {
     165         622 :                 struct unixid *id = &state->all_xids[i];
     166           0 :                 struct dom_sid_buf buf;
     167             : 
     168         622 :                 if ((id->id < dom_map->low_id) || (id->id > dom_map->high_id)) {
     169             :                         /* out of range */
     170           0 :                         continue;
     171             :                 }
     172         622 :                 if (state->cached[i]) {
     173             :                         /* already found in cache */
     174           0 :                         continue;
     175             :                 }
     176         622 :                 if (!is_null_sid(&state->all_sids[i])) {
     177             :                         /* already mapped in a previously asked domain */
     178           0 :                         continue;
     179             :                 }
     180             : 
     181         622 :                 sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
     182         622 :                 *id = state->dom_xids[dom_sid_idx];
     183         622 :                 D_DEBUG("%zu: XID %"PRIu32" mapped to SID %s.\n",
     184             :                         i,
     185             :                         id->id,
     186             :                         dom_sid_str_buf(&state->all_sids[i], &buf));
     187             : 
     188         622 :                 dom_sid_idx += 1;
     189             :         }
     190             : 
     191         486 :         tevent_req_done(req);
     192             : }
     193             : 
     194           2 : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
     195             : {
     196           2 :         struct tevent_req *req = tevent_req_callback_data(
     197             :                 subreq, struct tevent_req);
     198           2 :         struct wb_xids2sids_dom_state *state = tevent_req_data(
     199             :                 req, struct wb_xids2sids_dom_state);
     200           2 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     201           0 :         struct netr_DsRGetDCNameInfo *dcinfo;
     202           0 :         NTSTATUS status;
     203             : 
     204           2 :         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
     205           2 :         TALLOC_FREE(subreq);
     206           2 :         if (tevent_req_nterror(req, status)) {
     207           0 :                 return;
     208             :         }
     209             : 
     210           2 :         state->tried_dclookup = true;
     211             : 
     212           2 :         status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
     213           2 :         if (tevent_req_nterror(req, status)) {
     214           0 :                 return;
     215             :         }
     216             : 
     217           2 :         child_binding_handle = idmap_child_handle();
     218           2 :         subreq = dcerpc_wbint_UnixIDs2Sids_send(
     219           2 :                 state, state->ev, child_binding_handle, state->dom_map->name,
     220           2 :                 state->dom_map->sid, state->num_dom_xids,
     221             :                 state->dom_xids, state->dom_sids);
     222           2 :         if (tevent_req_nomem(subreq, req)) {
     223           0 :                 return;
     224             :         }
     225           2 :         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
     226             : }
     227             : 
     228       18056 : static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
     229             : {
     230       18056 :         return tevent_req_simple_recv_ntstatus(req);
     231             : }
     232             : 
     233             : struct wb_xids2sids_state {
     234             :         struct tevent_context *ev;
     235             :         struct unixid *xids;
     236             :         size_t num_xids;
     237             :         struct dom_sid *sids;
     238             :         bool *cached;
     239             : 
     240             :         size_t dom_idx;
     241             :         const struct wb_parent_idmap_config *cfg;
     242             : };
     243             : 
     244             : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
     245             : static void wb_xids2sids_done(struct tevent_req *subreq);
     246             : 
     247        8831 : struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
     248             :                                      struct tevent_context *ev,
     249             :                                      const struct unixid *xids,
     250             :                                      uint32_t num_xids)
     251             : {
     252           0 :         struct tevent_req *req, *subreq;
     253           0 :         struct wb_xids2sids_state *state;
     254             : 
     255        8831 :         req = tevent_req_create(mem_ctx, &state,
     256             :                                 struct wb_xids2sids_state);
     257        8831 :         if (req == NULL) {
     258           0 :                 return NULL;
     259             :         }
     260             : 
     261        8831 :         D_INFO("WB command xids2sids start.\nLooking up %"PRIu32" XID(s).\n",
     262             :                num_xids);
     263             : 
     264        8831 :         state->ev = ev;
     265        8831 :         state->num_xids = num_xids;
     266             : 
     267        8831 :         state->xids = talloc_array(state, struct unixid, num_xids);
     268        8831 :         if (tevent_req_nomem(state->xids, req)) {
     269           0 :                 return tevent_req_post(req, ev);
     270             :         }
     271        8831 :         memcpy(state->xids, xids, num_xids * sizeof(struct unixid));
     272             : 
     273        8831 :         state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
     274        8831 :         if (tevent_req_nomem(state->sids, req)) {
     275           0 :                 return tevent_req_post(req, ev);
     276             :         }
     277             : 
     278        8831 :         state->cached = talloc_zero_array(state, bool, num_xids);
     279        8831 :         if (tevent_req_nomem(state->cached, req)) {
     280           0 :                 return tevent_req_post(req, ev);
     281             :         }
     282             : 
     283        8831 :         if (winbindd_use_idmap_cache()) {
     284             :                 uint32_t i;
     285             : 
     286       17730 :                 for (i=0; i<num_xids; i++) {
     287        8899 :                         struct dom_sid sid = {0};
     288        8899 :                         bool ok, expired = true;
     289             : 
     290        8899 :                         ok = idmap_cache_find_xid2sid(
     291        8899 :                                 &xids[i], &sid, &expired);
     292        8899 :                         if (ok && !expired) {
     293           0 :                                 struct dom_sid_buf buf;
     294        8387 :                                 DBG_DEBUG("Found %cID in cache: %s\n",
     295             :                                           xids[i].type == ID_TYPE_UID?'U':'G',
     296             :                                           dom_sid_str_buf(&sid, &buf));
     297             : 
     298        8387 :                                 sid_copy(&state->sids[i], &sid);
     299        8387 :                                 state->cached[i] = true;
     300             :                         }
     301             :                 }
     302             :         }
     303             : 
     304        8831 :         subreq = wb_parent_idmap_setup_send(state, state->ev);
     305        8831 :         if (tevent_req_nomem(subreq, req)) {
     306           0 :                 return tevent_req_post(req, ev);
     307             :         }
     308        8831 :         tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
     309        8831 :         return req;
     310             : }
     311             : 
     312        8831 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
     313             : {
     314        8831 :         struct tevent_req *req = tevent_req_callback_data(
     315             :                 subreq, struct tevent_req);
     316        8831 :         struct wb_xids2sids_state *state = tevent_req_data(
     317             :                 req, struct wb_xids2sids_state);
     318           0 :         NTSTATUS status;
     319             : 
     320        8831 :         status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
     321        8831 :         TALLOC_FREE(subreq);
     322        8831 :         if (tevent_req_nterror(req, status)) {
     323           0 :                 return;
     324             :         }
     325        8831 :         SMB_ASSERT(state->cfg->num_doms > 0);
     326             : 
     327        8831 :         subreq = wb_xids2sids_dom_send(
     328             :                 state, state->ev,
     329        8831 :                 &state->cfg->doms[state->dom_idx],
     330        8831 :                 state->xids, state->cached, state->num_xids, state->sids);
     331        8831 :         if (tevent_req_nomem(subreq, req)) {
     332           0 :                 return;
     333             :         }
     334        8831 :         tevent_req_set_callback(subreq, wb_xids2sids_done, req);
     335        8831 :         return;
     336             : }
     337             : 
     338       18056 : static void wb_xids2sids_done(struct tevent_req *subreq)
     339             : {
     340       18056 :         struct tevent_req *req = tevent_req_callback_data(
     341             :                 subreq, struct tevent_req);
     342       18056 :         struct wb_xids2sids_state *state = tevent_req_data(
     343             :                 req, struct wb_xids2sids_state);
     344           0 :         size_t i;
     345           0 :         NTSTATUS status;
     346             : 
     347       18056 :         status = wb_xids2sids_dom_recv(subreq);
     348       18056 :         TALLOC_FREE(subreq);
     349       18056 :         if (tevent_req_nterror(req, status)) {
     350           0 :                 return;
     351             :         }
     352             : 
     353       18056 :         state->dom_idx += 1;
     354       18056 :         if (state->dom_idx < state->cfg->num_doms) {
     355        9225 :                 const struct wb_parent_idmap_config_dom *dom_map =
     356        9225 :                         &state->cfg->doms[state->dom_idx];
     357             : 
     358        9225 :                 subreq = wb_xids2sids_dom_send(state,
     359             :                                                state->ev,
     360             :                                                dom_map,
     361             :                                                state->xids,
     362        9225 :                                                state->cached,
     363             :                                                state->num_xids,
     364             :                                                state->sids);
     365        9225 :                 if (tevent_req_nomem(subreq, req)) {
     366           0 :                         return;
     367             :                 }
     368        9225 :                 tevent_req_set_callback(subreq, wb_xids2sids_done, req);
     369        9225 :                 return;
     370             :         }
     371             : 
     372             : 
     373       17730 :         for (i = 0; i < state->num_xids; i++) {
     374             :                 /*
     375             :                  * Prime the cache after an xid2sid call. It's important that we
     376             :                  * use the xid value returned from the backend for the xid value
     377             :                  * passed to idmap_cache_set_sid2unixid(), not the input to
     378             :                  * wb_xids2sids_send: the input carries what was asked for,
     379             :                  * e.g. a ID_TYPE_UID. The result from the backend something the
     380             :                  * idmap child possibly changed to ID_TYPE_BOTH.
     381             :                  *
     382             :                  * And of course If the value was from the cache don't update
     383             :                  * the cache.
     384             :                  */
     385             : 
     386        8899 :                 if (state->cached[i]) {
     387        8387 :                         continue;
     388             :                 }
     389             : 
     390         512 :                 idmap_cache_set_sid2unixid(&state->sids[i], &state->xids[i]);
     391             :         }
     392             : 
     393        8831 :         tevent_req_done(req);
     394        8831 :         return;
     395             : }
     396             : 
     397        8831 : NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     398             :                            struct dom_sid **sids)
     399             : {
     400        8831 :         struct wb_xids2sids_state *state = tevent_req_data(
     401             :                 req, struct wb_xids2sids_state);
     402           0 :         NTSTATUS status;
     403           0 :         size_t i;
     404             : 
     405        8831 :         D_INFO("WB command xids2sids end.\n");
     406        8831 :         if (tevent_req_is_nterror(req, &status)) {
     407           0 :                 D_WARNING("wb_sids_to_xids failed: %s\n", nt_errstr(status));
     408           0 :                 return status;
     409             :         }
     410             : 
     411        8831 :         *sids = talloc_move(mem_ctx, &state->sids);
     412        8831 :         if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
     413           0 :                 for (i = 0; i <  state->num_xids; i++) {
     414           0 :                         struct dom_sid_buf buf;
     415           0 :                         D_INFO("%zu: XID %"PRIu32" mapped to SID %s\n",
     416             :                                i,
     417             :                                state->xids[i].id,
     418             :                                dom_sid_str_buf(&((*sids)[i]), &buf));
     419             :                 }
     420             :         }
     421        8831 :         return NT_STATUS_OK;
     422             : }

Generated by: LCOV version 1.14