LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_idmap.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 122 184 66.3 %
Date: 2023-11-21 12:31:41 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Async helpers for blocking functions
       5             : 
       6             :    Copyright (C) Volker Lendecke 2005
       7             :    Copyright (C) Gerald Carter 2006
       8             :    Copyright (C) Simo Sorce 2007
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "winbindd.h"
      26             : #include "../libcli/security/security.h"
      27             : #include "passdb/lookup_sid.h"
      28             : #include "lib/global_contexts.h"
      29             : 
      30             : #undef DBGC_CLASS
      31             : #define DBGC_CLASS DBGC_WINBIND
      32             : 
      33             : static struct winbindd_child static_idmap_child;
      34             : 
      35             : /*
      36             :  * Map idmap ranges to domain names, taken from smb.conf. This is
      37             :  * stored in the parent winbind and used to assemble xids2sids/sids2xids calls
      38             :  * into per-idmap-domain chunks.
      39             :  */
      40             : static struct wb_parent_idmap_config static_parent_idmap_config;
      41             : 
      42         107 : struct winbindd_child *idmap_child(void)
      43             : {
      44         107 :         return &static_idmap_child;
      45             : }
      46             : 
      47           0 : bool is_idmap_child(const struct winbindd_child *child)
      48             : {
      49           0 :         if (child == &static_idmap_child) {
      50           0 :                 return true;
      51             :         }
      52             : 
      53           0 :         return false;
      54             : }
      55             : 
      56           2 : pid_t idmap_child_pid(void)
      57             : {
      58           2 :         return static_idmap_child.pid;
      59             : }
      60             : 
      61       98019 : struct dcerpc_binding_handle *idmap_child_handle(void)
      62             : {
      63             :         /*
      64             :          * The caller needs to use wb_parent_idmap_setup_send/recv
      65             :          * before talking to the idmap child!
      66             :          */
      67       98019 :         SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
      68       98019 :         return static_idmap_child.binding_handle;
      69             : }
      70             : 
      71             : static void init_idmap_child_done(struct tevent_req *subreq);
      72             : 
      73          41 : void init_idmap_child(void)
      74             : {
      75          41 :         struct tevent_req *subreq = NULL;
      76             : 
      77          41 :         subreq = wb_parent_idmap_setup_send(global_event_context(),
      78             :                                             global_event_context());
      79          41 :         if (subreq == NULL) {
      80             :                 /*
      81             :                  * This is only an optimization, so we're free to
      82             :                  * to ignore errors
      83             :                  */
      84           0 :                 DBG_ERR("wb_parent_idmap_setup_send() failed\n");
      85           0 :                 return;
      86             :         }
      87          41 :         tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
      88          41 :         DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
      89             : }
      90             : 
      91          41 : static void init_idmap_child_done(struct tevent_req *subreq)
      92             : {
      93          41 :         const struct wb_parent_idmap_config *cfg = NULL;
      94           0 :         NTSTATUS status;
      95             : 
      96          41 :         status = wb_parent_idmap_setup_recv(subreq, &cfg);
      97          41 :         TALLOC_FREE(subreq);
      98          41 :         if (!NT_STATUS_IS_OK(status)) {
      99             :                 /*
     100             :                  * This is only an optimization, so we're free to
     101             :                  * to ignore errors
     102             :                  */
     103           0 :                 DBG_ERR("wb_parent_idmap_setup_recv() failed %s\n",
     104             :                         nt_errstr(status));
     105           0 :                 return;
     106             :         }
     107             : 
     108          41 :         DBG_DEBUG("wb_parent_idmap_setup_recv() finished\n");
     109             : }
     110             : 
     111             : struct wb_parent_idmap_setup_state {
     112             :         struct tevent_context *ev;
     113             :         struct wb_parent_idmap_config *cfg;
     114             :         size_t dom_idx;
     115             : };
     116             : 
     117          82 : static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
     118             :                                           enum tevent_req_state req_state)
     119             : {
     120           0 :         struct wb_parent_idmap_setup_state *state =
     121          82 :                 tevent_req_data(req,
     122             :                 struct wb_parent_idmap_setup_state);
     123             : 
     124          82 :         if (req_state == TEVENT_REQ_DONE) {
     125          41 :                 state->cfg = NULL;
     126          41 :                 return;
     127             :         }
     128             : 
     129          41 :         if (state->cfg == NULL) {
     130          41 :                 return;
     131             :         }
     132             : 
     133           0 :         state->cfg->num_doms = 0;
     134           0 :         state->cfg->initialized = false;
     135           0 :         TALLOC_FREE(state->cfg->doms);
     136           0 :         state->cfg = NULL;
     137             : }
     138             : 
     139             : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
     140             : static bool wb_parent_idmap_setup_scan_config(const char *domname,
     141             :                                               void *private_data);
     142             : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
     143             : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
     144             : 
     145      105913 : struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
     146             :                                               struct tevent_context *ev)
     147             : {
     148      105913 :         struct tevent_req *req = NULL;
     149      105913 :         struct wb_parent_idmap_setup_state *state = NULL;
     150      105913 :         struct tevent_req *subreq = NULL;
     151             : 
     152      105913 :         req = tevent_req_create(mem_ctx, &state,
     153             :                                 struct wb_parent_idmap_setup_state);
     154      105913 :         if (req == NULL) {
     155           0 :                 return NULL;
     156             :         }
     157      105913 :         *state = (struct wb_parent_idmap_setup_state) {
     158             :                 .ev = ev,
     159             :                 .cfg = &static_parent_idmap_config,
     160             :                 .dom_idx = 0,
     161             :         };
     162             : 
     163      105913 :         if (state->cfg->initialized) {
     164      105858 :                 tevent_req_done(req);
     165      105858 :                 return tevent_req_post(req, ev);
     166             :         }
     167             : 
     168          55 :         if (state->cfg->queue == NULL) {
     169          41 :                 state->cfg->queue = tevent_queue_create(NULL,
     170             :                                                 "wb_parent_idmap_config_queue");
     171          41 :                 if (tevent_req_nomem(state->cfg->queue, req)) {
     172           0 :                         return tevent_req_post(req, ev);
     173             :                 }
     174             :         }
     175             : 
     176          55 :         subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
     177          55 :         if (tevent_req_nomem(subreq, req)) {
     178           0 :                 return tevent_req_post(req, ev);
     179             :         }
     180          55 :         tevent_req_set_callback(subreq,
     181             :                                 wb_parent_idmap_setup_queue_wait_done,
     182             :                                 req);
     183             : 
     184          55 :         return req;
     185             : }
     186             : 
     187          55 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
     188             : {
     189           0 :         struct tevent_req *req =
     190          55 :                 tevent_req_callback_data(subreq,
     191             :                 struct tevent_req);
     192           0 :         struct wb_parent_idmap_setup_state *state =
     193          55 :                 tevent_req_data(req,
     194             :                 struct wb_parent_idmap_setup_state);
     195           0 :         bool ok;
     196             : 
     197             :         /*
     198             :          * Note we don't call TALLOC_FREE(subreq) here in order to block the
     199             :          * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
     200             :          * will destroy it implicitly.
     201             :          */
     202          55 :         ok = tevent_queue_wait_recv(subreq);
     203          55 :         if (!ok) {
     204           0 :                 DBG_ERR("tevent_queue_wait_recv() failed\n");
     205           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     206           0 :                 return;
     207             :         }
     208             : 
     209          55 :         if (state->cfg->num_doms != 0) {
     210             :                 /*
     211             :                  * If we're not the first one we're done.
     212             :                  */
     213          14 :                 tevent_req_done(req);
     214          14 :                 return;
     215             :         }
     216             : 
     217             :         /*
     218             :          * From this point we start changing state->cfg,
     219             :          * which is &static_parent_idmap_config,
     220             :          * so we better setup a cleanup function
     221             :          * to undo the changes on failure.
     222             :          */
     223          41 :         tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
     224             : 
     225             :         /*
     226             :          * Put the passdb idmap domain first. We always need to try
     227             :          * there first.
     228             :          */
     229          41 :         state->cfg->doms = talloc_zero_array(NULL,
     230             :                                              struct wb_parent_idmap_config_dom,
     231             :                                              1);
     232          41 :         if (tevent_req_nomem(state->cfg->doms, req)) {
     233           0 :                 return;
     234             :         }
     235          41 :         state->cfg->doms[0].low_id = 0;
     236          41 :         state->cfg->doms[0].high_id = UINT_MAX;
     237          41 :         state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
     238             :                                                  get_global_sam_name());
     239          41 :         if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
     240           0 :                 return;
     241             :         }
     242          41 :         state->cfg->num_doms += 1;
     243             : 
     244          41 :         lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
     245          41 :         if (!tevent_req_is_in_progress(req)) {
     246           0 :                 return;
     247             :         }
     248             : 
     249          41 :         wb_parent_idmap_setup_lookupname_next(req);
     250             : }
     251             : 
     252          51 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
     253             :                                               void *private_data)
     254             : {
     255           0 :         struct tevent_req *req =
     256          51 :                 talloc_get_type_abort(private_data,
     257             :                 struct tevent_req);
     258           0 :         struct wb_parent_idmap_setup_state *state =
     259          51 :                 tevent_req_data(req,
     260             :                 struct wb_parent_idmap_setup_state);
     261          51 :         struct wb_parent_idmap_config_dom *map = NULL;
     262           0 :         size_t i;
     263           0 :         const char *range;
     264           0 :         unsigned low_id, high_id;
     265           0 :         int ret;
     266             : 
     267          51 :         range = idmap_config_const_string(domname, "range", NULL);
     268          51 :         if (range == NULL) {
     269           0 :                 DBG_DEBUG("No range for domain %s found\n", domname);
     270           0 :                 return false;
     271             :         }
     272             : 
     273          51 :         ret = sscanf(range, "%u - %u", &low_id, &high_id);
     274          51 :         if (ret != 2) {
     275           0 :                 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
     276             :                           range, domname);
     277           0 :                 return false;
     278             :         }
     279             : 
     280          51 :         if (low_id > high_id) {
     281           0 :                 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
     282             :                           low_id, high_id, domname);
     283           0 :                 return false;
     284             :         }
     285             : 
     286         114 :         for (i=0; i<state->cfg->num_doms; i++) {
     287          63 :                 if (strequal(domname, state->cfg->doms[i].name)) {
     288           0 :                         map = &state->cfg->doms[i];
     289           0 :                         break;
     290             :                 }
     291             :         }
     292             : 
     293          51 :         if (map == NULL) {
     294           0 :                 struct wb_parent_idmap_config_dom *tmp;
     295           0 :                 char *name;
     296             : 
     297          51 :                 name = talloc_strdup(state, domname);
     298          51 :                 if (name == NULL) {
     299           0 :                         DBG_ERR("talloc failed\n");
     300           0 :                         return false;
     301             :                 }
     302             : 
     303          51 :                 tmp = talloc_realloc(
     304             :                         NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
     305             :                         state->cfg->num_doms+1);
     306          51 :                 if (tmp == NULL) {
     307           0 :                         DBG_ERR("talloc failed\n");
     308           0 :                         return false;
     309             :                 }
     310          51 :                 state->cfg->doms = tmp;
     311             : 
     312          51 :                 map = &state->cfg->doms[state->cfg->num_doms];
     313          51 :                 state->cfg->num_doms += 1;
     314          51 :                 ZERO_STRUCTP(map);
     315          51 :                 map->name = talloc_move(state->cfg->doms, &name);
     316             :         }
     317             : 
     318          51 :         map->low_id = low_id;
     319          51 :         map->high_id = high_id;
     320             : 
     321          51 :         return false;
     322             : }
     323             : 
     324          92 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
     325             : {
     326           0 :         struct wb_parent_idmap_setup_state *state =
     327          92 :                 tevent_req_data(req,
     328             :                 struct wb_parent_idmap_setup_state);
     329          92 :         struct wb_parent_idmap_config_dom *dom =
     330          92 :                 &state->cfg->doms[state->dom_idx];
     331          92 :         struct tevent_req *subreq = NULL;
     332             : 
     333         133 :  next_domain:
     334         133 :         if (state->dom_idx == state->cfg->num_doms) {
     335             :                 /*
     336             :                  * We're done, so start the idmap child
     337             :                  */
     338          41 :                 setup_child(NULL, &static_idmap_child, "log.winbindd", "idmap");
     339          41 :                 static_parent_idmap_config.initialized = true;
     340          41 :                 tevent_req_done(req);
     341          41 :                 return;
     342             :         }
     343             : 
     344          92 :         if (strequal(dom->name, "*")) {
     345          41 :                 state->dom_idx++;
     346          41 :                 goto next_domain;
     347             :         }
     348             : 
     349          51 :         subreq = wb_lookupname_send(state,
     350             :                                     state->ev,
     351             :                                     dom->name,
     352             :                                     dom->name,
     353             :                                     "",
     354             :                                     LOOKUP_NAME_NO_NSS);
     355          51 :         if (tevent_req_nomem(subreq, req)) {
     356           0 :                 return;
     357             :         }
     358          51 :         tevent_req_set_callback(subreq,
     359             :                                 wb_parent_idmap_setup_lookupname_done,
     360             :                                 req);
     361             : }
     362             : 
     363          51 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
     364             : {
     365           0 :         struct tevent_req *req =
     366          51 :                 tevent_req_callback_data(subreq,
     367             :                 struct tevent_req);
     368           0 :         struct wb_parent_idmap_setup_state *state =
     369          51 :                 tevent_req_data(req,
     370             :                 struct wb_parent_idmap_setup_state);
     371          51 :         struct wb_parent_idmap_config_dom *dom =
     372          51 :                 &state->cfg->doms[state->dom_idx];
     373           0 :         enum lsa_SidType type;
     374           0 :         NTSTATUS status;
     375             : 
     376          51 :         status = wb_lookupname_recv(subreq, &dom->sid, &type);
     377          51 :         TALLOC_FREE(subreq);
     378          51 :         if (!NT_STATUS_IS_OK(status)) {
     379           0 :                 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
     380             :                         dom->name,
     381             :                         nt_errstr(status));
     382             : 
     383           0 :                 state->dom_idx++;
     384           0 :                 wb_parent_idmap_setup_lookupname_next(req);
     385           0 :                 return;
     386             :         }
     387             : 
     388          51 :         if (type != SID_NAME_DOMAIN) {
     389           0 :                 struct dom_sid_buf buf;
     390             : 
     391           0 :                 DBG_ERR("SID %s for idmap domain name '%s' "
     392             :                         "not a domain SID\n",
     393             :                         dom_sid_str_buf(&dom->sid, &buf),
     394             :                         dom->name);
     395             : 
     396           0 :                 ZERO_STRUCT(dom->sid);
     397             :         }
     398             : 
     399          51 :         state->dom_idx++;
     400          51 :         wb_parent_idmap_setup_lookupname_next(req);
     401             : 
     402          51 :         return;
     403             : }
     404             : 
     405      105913 : NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
     406             :                                     const struct wb_parent_idmap_config **_cfg)
     407             : {
     408      105913 :         const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
     409           0 :         NTSTATUS status;
     410             : 
     411      105913 :         *_cfg = NULL;
     412             : 
     413      105913 :         if (tevent_req_is_nterror(req, &status)) {
     414           0 :                 tevent_req_received(req);
     415           0 :                 return status;
     416             :         }
     417             : 
     418             :         /*
     419             :          * Note state->cfg is already set to NULL by
     420             :          * wb_parent_idmap_setup_cleanup()
     421             :          */
     422      105913 :         *_cfg = cfg;
     423      105913 :         tevent_req_received(req);
     424      105913 :         return NT_STATUS_OK;
     425             : }

Generated by: LCOV version 1.14