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        6304 : 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             :         struct tevent_req *req, *subreq;
      54             :         struct wb_xids2sids_dom_state *state;
      55        6304 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
      56             :         size_t i;
      57             : 
      58        6304 :         req = tevent_req_create(mem_ctx, &state,
      59             :                                 struct wb_xids2sids_dom_state);
      60        6304 :         if (req == NULL) {
      61           0 :                 return NULL;
      62             :         }
      63             : 
      64        6304 :         D_DEBUG("Searching for %zu xid(s) in domain %s.\n",
      65             :                 num_xids,
      66             :                 dom_map->name);
      67             : 
      68        6304 :         state->ev = ev;
      69        6304 :         state->all_xids = xids;
      70        6304 :         state->cached = cached;
      71        6304 :         state->num_all_xids = num_xids;
      72        6304 :         state->all_sids = sids;
      73        6304 :         state->dom_map = dom_map;
      74             : 
      75        6304 :         state->dom_xids = talloc_array(state, struct unixid, num_xids);
      76        6304 :         if (tevent_req_nomem(state->dom_xids, req)) {
      77           0 :                 return tevent_req_post(req, ev);
      78             :         }
      79        6304 :         state->dom_sids = talloc_array(state, struct dom_sid, num_xids);
      80        6304 :         if (tevent_req_nomem(state->dom_sids, req)) {
      81           0 :                 return tevent_req_post(req, ev);
      82             :         }
      83             : 
      84       13973 :         for (i=0; i<num_xids; i++) {
      85        7669 :                 struct unixid id = state->all_xids[i];
      86             : 
      87        7669 :                 if ((id.id < dom_map->low_id) || (id.id > dom_map->high_id)) {
      88             :                         /* out of range */
      89         683 :                         D_DEBUG("%zu: XID %"PRIu32" is out of range.\n",
      90             :                                 i, id.id);
      91        7719 :                         continue;
      92             :                 }
      93        6986 :                 if (state->cached[i]) {
      94             :                         /* already found in cache */
      95        6668 :                         D_DEBUG("%zu: XID %"PRIu32" is already found in cache.\n",
      96             :                                 i, id.id);
      97        6668 :                         continue;
      98             :                 }
      99         318 :                 if (!is_null_sid(&state->all_sids[i])) {
     100             :                         /* already mapped in a previously asked domain */
     101           2 :                         D_DEBUG("%zu: XID %"PRIu32" is already mapped in a previously asked domain.\n",
     102             :                                 i, id.id);
     103           2 :                         continue;
     104             :                 }
     105         316 :                 D_DEBUG("%zu: XID %"PRIu32" will be looked up via dcerpc_wbint_UnixIDs2Sids_send().\n",
     106             :                         i, id.id);
     107         316 :                 state->dom_xids[state->num_dom_xids++] = id;
     108             :         }
     109             : 
     110        6304 :         if (state->num_dom_xids == 0) {
     111        6124 :                 tevent_req_done(req);
     112        6124 :                 return tevent_req_post(req, ev);
     113             :         }
     114             : 
     115         180 :         child_binding_handle = idmap_child_handle();
     116         400 :         subreq = dcerpc_wbint_UnixIDs2Sids_send(
     117          70 :                 state, ev, child_binding_handle, dom_map->name, dom_map->sid,
     118         400 :                 state->num_dom_xids, state->dom_xids, state->dom_sids);
     119         180 :         if (tevent_req_nomem(subreq, req)) {
     120           0 :                 return tevent_req_post(req, ev);
     121             :         }
     122         180 :         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
     123         180 :         return req;
     124             : }
     125             : 
     126         182 : static void wb_xids2sids_dom_done(struct tevent_req *subreq)
     127             : {
     128         182 :         struct tevent_req *req = tevent_req_callback_data(
     129             :                 subreq, struct tevent_req);
     130         182 :         struct wb_xids2sids_dom_state *state = tevent_req_data(
     131             :                 req, struct wb_xids2sids_dom_state);
     132         182 :         const struct wb_parent_idmap_config_dom *dom_map = state->dom_map;
     133             :         NTSTATUS status, result;
     134             :         size_t i;
     135             :         size_t dom_sid_idx;
     136             : 
     137         182 :         status = dcerpc_wbint_UnixIDs2Sids_recv(subreq, state, &result);
     138         182 :         TALLOC_FREE(subreq);
     139         182 :         if (tevent_req_nterror(req, status)) {
     140           2 :                 return;
     141             :         }
     142             : 
     143         183 :         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
     144           2 :             !state->tried_dclookup) {
     145             : 
     146           2 :                 const char *domain_name = find_dns_domain_name(
     147           2 :                         state->dom_map->name);
     148             : 
     149           2 :                 subreq = wb_dsgetdcname_send(state,
     150             :                                              state->ev,
     151             :                                              domain_name,
     152             :                                              NULL,
     153             :                                              NULL,
     154             :                                              DS_RETURN_DNS_NAME);
     155           2 :                 if (tevent_req_nomem(subreq, req)) {
     156           1 :                         return;
     157             :                 }
     158           2 :                 tevent_req_set_callback(subreq, wb_xids2sids_dom_gotdc, req);
     159           2 :                 return;
     160             :         }
     161             : 
     162         360 :         if (!NT_STATUS_EQUAL(result, NT_STATUS_NONE_MAPPED) &&
     163         180 :             tevent_req_nterror(req, result)) {
     164           0 :                 return;
     165             :         }
     166             : 
     167         180 :         dom_sid_idx = 0;
     168             : 
     169         180 :         D_DEBUG("Processing response for %zu xid(s).\n", state->num_all_xids);
     170         497 :         for (i=0; i<state->num_all_xids; i++) {
     171         317 :                 struct unixid *id = &state->all_xids[i];
     172             :                 struct dom_sid_buf buf;
     173             : 
     174         317 :                 if ((id->id < dom_map->low_id) || (id->id > dom_map->high_id)) {
     175             :                         /* out of range */
     176           1 :                         continue;
     177             :                 }
     178         317 :                 if (state->cached[i]) {
     179             :                         /* already found in cache */
     180           1 :                         continue;
     181             :                 }
     182         316 :                 if (!is_null_sid(&state->all_sids[i])) {
     183             :                         /* already mapped in a previously asked domain */
     184           0 :                         continue;
     185             :                 }
     186             : 
     187         316 :                 sid_copy(&state->all_sids[i], &state->dom_sids[dom_sid_idx]);
     188         316 :                 *id = state->dom_xids[dom_sid_idx];
     189         316 :                 D_DEBUG("%zu: XID %"PRIu32" mapped to SID %s.\n",
     190             :                         i,
     191             :                         id->id,
     192             :                         dom_sid_str_buf(&state->all_sids[i], &buf));
     193             : 
     194         316 :                 dom_sid_idx += 1;
     195             :         }
     196             : 
     197         180 :         tevent_req_done(req);
     198             : }
     199             : 
     200           2 : static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq)
     201             : {
     202           2 :         struct tevent_req *req = tevent_req_callback_data(
     203             :                 subreq, struct tevent_req);
     204           2 :         struct wb_xids2sids_dom_state *state = tevent_req_data(
     205             :                 req, struct wb_xids2sids_dom_state);
     206           2 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     207             :         struct netr_DsRGetDCNameInfo *dcinfo;
     208             :         NTSTATUS status;
     209             : 
     210           2 :         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
     211           2 :         TALLOC_FREE(subreq);
     212           2 :         if (tevent_req_nterror(req, status)) {
     213           0 :                 return;
     214             :         }
     215             : 
     216           2 :         state->tried_dclookup = true;
     217             : 
     218           2 :         status = wb_dsgetdcname_gencache_set(state->dom_map->name, dcinfo);
     219           2 :         if (tevent_req_nterror(req, status)) {
     220           0 :                 return;
     221             :         }
     222             : 
     223           2 :         child_binding_handle = idmap_child_handle();
     224           4 :         subreq = dcerpc_wbint_UnixIDs2Sids_send(
     225           2 :                 state, state->ev, child_binding_handle, state->dom_map->name,
     226           3 :                 state->dom_map->sid, state->num_dom_xids,
     227             :                 state->dom_xids, state->dom_sids);
     228           2 :         if (tevent_req_nomem(subreq, req)) {
     229           0 :                 return;
     230             :         }
     231           2 :         tevent_req_set_callback(subreq, wb_xids2sids_dom_done, req);
     232             : }
     233             : 
     234        6304 : static NTSTATUS wb_xids2sids_dom_recv(struct tevent_req *req)
     235             : {
     236        6304 :         return tevent_req_simple_recv_ntstatus(req);
     237             : }
     238             : 
     239             : struct wb_xids2sids_state {
     240             :         struct tevent_context *ev;
     241             :         struct unixid *xids;
     242             :         size_t num_xids;
     243             :         struct dom_sid *sids;
     244             :         bool *cached;
     245             : 
     246             :         size_t dom_idx;
     247             :         const struct wb_parent_idmap_config *cfg;
     248             : };
     249             : 
     250             : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq);
     251             : static void wb_xids2sids_done(struct tevent_req *subreq);
     252             : 
     253        4470 : struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx,
     254             :                                      struct tevent_context *ev,
     255             :                                      const struct unixid *xids,
     256             :                                      uint32_t num_xids)
     257             : {
     258             :         struct tevent_req *req, *subreq;
     259             :         struct wb_xids2sids_state *state;
     260             : 
     261        4470 :         req = tevent_req_create(mem_ctx, &state,
     262             :                                 struct wb_xids2sids_state);
     263        4470 :         if (req == NULL) {
     264           0 :                 return NULL;
     265             :         }
     266             : 
     267        4470 :         D_INFO("WB command xids2sids start.\nLooking up %"PRIu32" XID(s).\n",
     268             :                num_xids);
     269             : 
     270        4470 :         state->ev = ev;
     271        4470 :         state->num_xids = num_xids;
     272             : 
     273        4470 :         state->xids = talloc_array(state, struct unixid, num_xids);
     274        4470 :         if (tevent_req_nomem(state->xids, req)) {
     275           0 :                 return tevent_req_post(req, ev);
     276             :         }
     277        4470 :         memcpy(state->xids, xids, num_xids * sizeof(struct unixid));
     278             : 
     279        4470 :         state->sids = talloc_zero_array(state, struct dom_sid, num_xids);
     280        4470 :         if (tevent_req_nomem(state->sids, req)) {
     281           0 :                 return tevent_req_post(req, ev);
     282             :         }
     283             : 
     284        4470 :         state->cached = talloc_zero_array(state, bool, num_xids);
     285        4470 :         if (tevent_req_nomem(state->cached, req)) {
     286           0 :                 return tevent_req_post(req, ev);
     287             :         }
     288             : 
     289        4470 :         if (winbindd_use_idmap_cache()) {
     290             :                 uint32_t i;
     291             : 
     292       10169 :                 for (i=0; i<num_xids; i++) {
     293        5699 :                         struct dom_sid sid = {0};
     294        5699 :                         bool ok, expired = true;
     295             : 
     296        5699 :                         ok = idmap_cache_find_xid2sid(
     297        5699 :                                 &xids[i], &sid, &expired);
     298        5699 :                         if (ok && !expired) {
     299             :                                 struct dom_sid_buf buf;
     300        5469 :                                 DBG_DEBUG("Found %cID in cache: %s\n",
     301             :                                           xids[i].type == ID_TYPE_UID?'U':'G',
     302             :                                           dom_sid_str_buf(&sid, &buf));
     303             : 
     304        5469 :                                 sid_copy(&state->sids[i], &sid);
     305        5469 :                                 state->cached[i] = true;
     306             :                         }
     307             :                 }
     308             :         }
     309             : 
     310        4470 :         subreq = wb_parent_idmap_setup_send(state, state->ev);
     311        4470 :         if (tevent_req_nomem(subreq, req)) {
     312           0 :                 return tevent_req_post(req, ev);
     313             :         }
     314        4470 :         tevent_req_set_callback(subreq, wb_xids2sids_idmap_setup_done, req);
     315        4470 :         return req;
     316             : }
     317             : 
     318        4470 : static void wb_xids2sids_idmap_setup_done(struct tevent_req *subreq)
     319             : {
     320        4470 :         struct tevent_req *req = tevent_req_callback_data(
     321             :                 subreq, struct tevent_req);
     322        4470 :         struct wb_xids2sids_state *state = tevent_req_data(
     323             :                 req, struct wb_xids2sids_state);
     324             :         NTSTATUS status;
     325             : 
     326        4470 :         status = wb_parent_idmap_setup_recv(subreq, &state->cfg);
     327        4470 :         TALLOC_FREE(subreq);
     328        4470 :         if (tevent_req_nterror(req, status)) {
     329           0 :                 return;
     330             :         }
     331        4470 :         SMB_ASSERT(state->cfg->num_doms > 0);
     332             : 
     333       12012 :         subreq = wb_xids2sids_dom_send(
     334             :                 state, state->ev,
     335        4470 :                 &state->cfg->doms[state->dom_idx],
     336        4470 :                 state->xids, state->cached, state->num_xids, state->sids);
     337        4470 :         if (tevent_req_nomem(subreq, req)) {
     338           0 :                 return;
     339             :         }
     340        4470 :         tevent_req_set_callback(subreq, wb_xids2sids_done, req);
     341        4470 :         return;
     342             : }
     343             : 
     344        6304 : static void wb_xids2sids_done(struct tevent_req *subreq)
     345             : {
     346        6304 :         struct tevent_req *req = tevent_req_callback_data(
     347             :                 subreq, struct tevent_req);
     348        6304 :         struct wb_xids2sids_state *state = tevent_req_data(
     349             :                 req, struct wb_xids2sids_state);
     350             :         size_t i;
     351             :         NTSTATUS status;
     352             : 
     353        6304 :         status = wb_xids2sids_dom_recv(subreq);
     354        6304 :         TALLOC_FREE(subreq);
     355        6304 :         if (tevent_req_nterror(req, status)) {
     356           0 :                 return;
     357             :         }
     358             : 
     359        6304 :         state->dom_idx += 1;
     360        6304 :         if (state->dom_idx < state->cfg->num_doms) {
     361        1834 :                 const struct wb_parent_idmap_config_dom *dom_map =
     362        1834 :                         &state->cfg->doms[state->dom_idx];
     363             : 
     364        2776 :                 subreq = wb_xids2sids_dom_send(state,
     365             :                                                state->ev,
     366             :                                                dom_map,
     367             :                                                state->xids,
     368        1834 :                                                state->cached,
     369             :                                                state->num_xids,
     370             :                                                state->sids);
     371        1834 :                 if (tevent_req_nomem(subreq, req)) {
     372           0 :                         return;
     373             :                 }
     374        1834 :                 tevent_req_set_callback(subreq, wb_xids2sids_done, req);
     375        1834 :                 return;
     376             :         }
     377             : 
     378             : 
     379       10169 :         for (i = 0; i < state->num_xids; i++) {
     380             :                 /*
     381             :                  * Prime the cache after an xid2sid call. It's important that we
     382             :                  * use the xid value returned from the backend for the xid value
     383             :                  * passed to idmap_cache_set_sid2unixid(), not the input to
     384             :                  * wb_xids2sids_send: the input carries what was asked for,
     385             :                  * e.g. a ID_TYPE_UID. The result from the backend something the
     386             :                  * idmap child possibly changed to ID_TYPE_BOTH.
     387             :                  *
     388             :                  * And of course If the value was from the cache don't update
     389             :                  * the cache.
     390             :                  */
     391             : 
     392        5699 :                 if (state->cached[i]) {
     393        5469 :                         continue;
     394             :                 }
     395             : 
     396         230 :                 idmap_cache_set_sid2unixid(&state->sids[i], &state->xids[i]);
     397             :         }
     398             : 
     399        4470 :         tevent_req_done(req);
     400        4470 :         return;
     401             : }
     402             : 
     403        4470 : NTSTATUS wb_xids2sids_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     404             :                            struct dom_sid **sids)
     405             : {
     406        4470 :         struct wb_xids2sids_state *state = tevent_req_data(
     407             :                 req, struct wb_xids2sids_state);
     408             :         NTSTATUS status;
     409             :         size_t i;
     410             : 
     411        4470 :         D_INFO("WB command xids2sids end.\n");
     412        4470 :         if (tevent_req_is_nterror(req, &status)) {
     413           0 :                 D_WARNING("wb_sids_to_xids failed: %s\n", nt_errstr(status));
     414           0 :                 return status;
     415             :         }
     416             : 
     417        4470 :         *sids = talloc_move(mem_ctx, &state->sids);
     418        4470 :         if (CHECK_DEBUGLVL(DBGLVL_INFO)) {
     419           0 :                 for (i = 0; i <  state->num_xids; i++) {
     420             :                         struct dom_sid_buf buf;
     421           0 :                         D_INFO("%zu: XID %"PRIu32" mapped to SID %s\n",
     422             :                                i,
     423             :                                state->xids[i].id,
     424             :                                dom_sid_str_buf(&((*sids)[i]), &buf));
     425             :                 }
     426             :         }
     427        4470 :         return NT_STATUS_OK;
     428             : }
       |