LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_idmap.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 128 167 76.6 %
Date: 2024-06-13 04:01:37 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          28 : struct winbindd_child *idmap_child(void)
      43             : {
      44          28 :         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        6407 : 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        6407 :         SMB_ASSERT(static_parent_idmap_config.num_doms > 0);
      68        6407 :         return static_idmap_child.binding_handle;
      69             : }
      70             : 
      71             : static void init_idmap_child_done(struct tevent_req *subreq);
      72             : 
      73          68 : void init_idmap_child(void)
      74             : {
      75          68 :         struct tevent_req *subreq = NULL;
      76             : 
      77          68 :         subreq = wb_parent_idmap_setup_send(global_event_context(),
      78             :                                             global_event_context());
      79          68 :         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          68 :         tevent_req_set_callback(subreq, init_idmap_child_done, NULL);
      88          68 :         DBG_DEBUG("wb_parent_idmap_setup_send() started\n");
      89             : }
      90             : 
      91          62 : static void init_idmap_child_done(struct tevent_req *subreq)
      92             : {
      93          62 :         const struct wb_parent_idmap_config *cfg = NULL;
      94             :         NTSTATUS status;
      95             : 
      96          62 :         status = wb_parent_idmap_setup_recv(subreq, &cfg);
      97          62 :         TALLOC_FREE(subreq);
      98          62 :         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          62 :         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         124 : static void wb_parent_idmap_setup_cleanup(struct tevent_req *req,
     118             :                                           enum tevent_req_state req_state)
     119             : {
     120          98 :         struct wb_parent_idmap_setup_state *state =
     121         124 :                 tevent_req_data(req,
     122             :                 struct wb_parent_idmap_setup_state);
     123             : 
     124         124 :         if (req_state == TEVENT_REQ_DONE) {
     125          62 :                 state->cfg = NULL;
     126          62 :                 return;
     127             :         }
     128             : 
     129          62 :         if (state->cfg == NULL) {
     130          62 :                 return;
     131             :         }
     132             : 
     133           0 :         state->cfg->num_doms = 0;
     134           0 :         TALLOC_FREE(state->cfg->doms);
     135           0 :         state->cfg = NULL;
     136             : }
     137             : 
     138             : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq);
     139             : static bool wb_parent_idmap_setup_scan_config(const char *domname,
     140             :                                               void *private_data);
     141             : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req);
     142             : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq);
     143             : 
     144       10532 : struct tevent_req *wb_parent_idmap_setup_send(TALLOC_CTX *mem_ctx,
     145             :                                               struct tevent_context *ev)
     146             : {
     147       10532 :         struct tevent_req *req = NULL;
     148       10532 :         struct wb_parent_idmap_setup_state *state = NULL;
     149       10532 :         struct tevent_req *subreq = NULL;
     150             : 
     151       10532 :         req = tevent_req_create(mem_ctx, &state,
     152             :                                 struct wb_parent_idmap_setup_state);
     153       10532 :         if (req == NULL) {
     154           0 :                 return NULL;
     155             :         }
     156       10532 :         *state = (struct wb_parent_idmap_setup_state) {
     157             :                 .ev = ev,
     158             :                 .cfg = &static_parent_idmap_config,
     159             :                 .dom_idx = 0,
     160             :         };
     161             : 
     162       10532 :         if (state->cfg->queue == NULL) {
     163          68 :                 state->cfg->queue = tevent_queue_create(NULL,
     164             :                                                 "wb_parent_idmap_config_queue");
     165          68 :                 if (tevent_req_nomem(state->cfg->queue, req)) {
     166           0 :                         return tevent_req_post(req, ev);
     167             :                 }
     168             :         }
     169             : 
     170       10532 :         subreq = tevent_queue_wait_send(state, state->ev, state->cfg->queue);
     171       10532 :         if (tevent_req_nomem(subreq, req)) {
     172           0 :                 return tevent_req_post(req, ev);
     173             :         }
     174       10532 :         tevent_req_set_callback(subreq,
     175             :                                 wb_parent_idmap_setup_queue_wait_done,
     176             :                                 req);
     177             : 
     178       10532 :         return req;
     179             : }
     180             : 
     181       10532 : static void wb_parent_idmap_setup_queue_wait_done(struct tevent_req *subreq)
     182             : {
     183        8229 :         struct tevent_req *req =
     184       10532 :                 tevent_req_callback_data(subreq,
     185             :                 struct tevent_req);
     186        8229 :         struct wb_parent_idmap_setup_state *state =
     187       10532 :                 tevent_req_data(req,
     188             :                 struct wb_parent_idmap_setup_state);
     189             :         bool ok;
     190             : 
     191             :         /*
     192             :          * Note we don't call TALLOC_FREE(subreq) here in order to block the
     193             :          * queue until tevent_req_received() in wb_parent_idmap_setup_recv()
     194             :          * will destroy it implicitly.
     195             :          */
     196       10532 :         ok = tevent_queue_wait_recv(subreq);
     197       10532 :         if (!ok) {
     198           0 :                 DBG_ERR("tevent_queue_wait_recv() failed\n");
     199           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     200           0 :                 return;
     201             :         }
     202             : 
     203       10532 :         if (state->cfg->num_doms != 0) {
     204             :                 /*
     205             :                  * If we're not the first one we're done.
     206             :                  */
     207       10464 :                 tevent_req_done(req);
     208       10464 :                 return;
     209             :         }
     210             : 
     211             :         /*
     212             :          * From this point we start changing state->cfg,
     213             :          * which is &static_parent_idmap_config,
     214             :          * so we better setup a cleanup function
     215             :          * to undo the changes on failure.
     216             :          */
     217          68 :         tevent_req_set_cleanup_fn(req, wb_parent_idmap_setup_cleanup);
     218             : 
     219             :         /*
     220             :          * Put the passdb idmap domain first. We always need to try
     221             :          * there first.
     222             :          */
     223          68 :         state->cfg->doms = talloc_zero_array(NULL,
     224             :                                              struct wb_parent_idmap_config_dom,
     225             :                                              1);
     226          68 :         if (tevent_req_nomem(state->cfg->doms, req)) {
     227           0 :                 return;
     228             :         }
     229          68 :         state->cfg->doms[0].low_id = 0;
     230          68 :         state->cfg->doms[0].high_id = UINT_MAX;
     231          68 :         state->cfg->doms[0].name = talloc_strdup(state->cfg->doms,
     232             :                                                  get_global_sam_name());
     233          68 :         if (tevent_req_nomem(state->cfg->doms[0].name, req)) {
     234           0 :                 return;
     235             :         }
     236          68 :         state->cfg->num_doms += 1;
     237             : 
     238          68 :         lp_scan_idmap_domains(wb_parent_idmap_setup_scan_config, req);
     239          68 :         if (!tevent_req_is_in_progress(req)) {
     240           0 :                 return;
     241             :         }
     242             : 
     243          68 :         wb_parent_idmap_setup_lookupname_next(req);
     244             : }
     245             : 
     246          78 : static bool wb_parent_idmap_setup_scan_config(const char *domname,
     247             :                                               void *private_data)
     248             : {
     249          60 :         struct tevent_req *req =
     250          18 :                 talloc_get_type_abort(private_data,
     251             :                 struct tevent_req);
     252          60 :         struct wb_parent_idmap_setup_state *state =
     253          78 :                 tevent_req_data(req,
     254             :                 struct wb_parent_idmap_setup_state);
     255          78 :         struct wb_parent_idmap_config_dom *map = NULL;
     256             :         size_t i;
     257             :         const char *range;
     258             :         unsigned low_id, high_id;
     259             :         int ret;
     260             : 
     261          78 :         range = idmap_config_const_string(domname, "range", NULL);
     262          78 :         if (range == NULL) {
     263          38 :                 DBG_DEBUG("No range for domain %s found\n", domname);
     264          38 :                 return false;
     265             :         }
     266             : 
     267          40 :         ret = sscanf(range, "%u - %u", &low_id, &high_id);
     268          40 :         if (ret != 2) {
     269           0 :                 DBG_DEBUG("Invalid range spec \"%s\" for domain %s\n",
     270             :                           range, domname);
     271           0 :                 return false;
     272             :         }
     273             : 
     274          40 :         if (low_id > high_id) {
     275           0 :                 DBG_DEBUG("Invalid range %u - %u for domain %s\n",
     276             :                           low_id, high_id, domname);
     277           0 :                 return false;
     278             :         }
     279             : 
     280          92 :         for (i=0; i<state->cfg->num_doms; i++) {
     281          52 :                 if (strequal(domname, state->cfg->doms[i].name)) {
     282           0 :                         map = &state->cfg->doms[i];
     283           0 :                         break;
     284             :                 }
     285             :         }
     286             : 
     287          40 :         if (map == NULL) {
     288             :                 struct wb_parent_idmap_config_dom *tmp;
     289             :                 char *name;
     290             : 
     291          40 :                 name = talloc_strdup(state, domname);
     292          40 :                 if (name == NULL) {
     293           0 :                         DBG_ERR("talloc failed\n");
     294           0 :                         return false;
     295             :                 }
     296             : 
     297          40 :                 tmp = talloc_realloc(
     298             :                         NULL, state->cfg->doms, struct wb_parent_idmap_config_dom,
     299             :                         state->cfg->num_doms+1);
     300          40 :                 if (tmp == NULL) {
     301           0 :                         DBG_ERR("talloc failed\n");
     302           0 :                         return false;
     303             :                 }
     304          40 :                 state->cfg->doms = tmp;
     305             : 
     306          40 :                 map = &state->cfg->doms[state->cfg->num_doms];
     307          40 :                 state->cfg->num_doms += 1;
     308          40 :                 ZERO_STRUCTP(map);
     309          40 :                 map->name = talloc_move(state->cfg->doms, &name);
     310             :         }
     311             : 
     312          40 :         map->low_id = low_id;
     313          40 :         map->high_id = high_id;
     314             : 
     315          40 :         return false;
     316             : }
     317             : 
     318         140 : static void wb_parent_idmap_setup_lookupname_next(struct tevent_req *req)
     319             : {
     320         109 :         struct wb_parent_idmap_setup_state *state =
     321         140 :                 tevent_req_data(req,
     322             :                 struct wb_parent_idmap_setup_state);
     323         140 :         struct wb_parent_idmap_config_dom *dom =
     324         140 :                 &state->cfg->doms[state->dom_idx];
     325         140 :         struct tevent_req *subreq = NULL;
     326             : 
     327         170 :  next_domain:
     328         170 :         if (state->dom_idx == state->cfg->num_doms) {
     329             :                 /*
     330             :                  * We're done, so start the idmap child
     331             :                  */
     332          62 :                 setup_child(NULL, &static_idmap_child, "log.winbindd", "idmap");
     333          62 :                 tevent_req_done(req);
     334          62 :                 return;
     335             :         }
     336             : 
     337         108 :         if (strequal(dom->name, "*")) {
     338          30 :                 state->dom_idx++;
     339          30 :                 goto next_domain;
     340             :         }
     341             : 
     342          78 :         subreq = wb_lookupname_send(state,
     343             :                                     state->ev,
     344             :                                     dom->name,
     345             :                                     dom->name,
     346             :                                     "",
     347             :                                     LOOKUP_NAME_NO_NSS);
     348          78 :         if (tevent_req_nomem(subreq, req)) {
     349           0 :                 return;
     350             :         }
     351          78 :         tevent_req_set_callback(subreq,
     352             :                                 wb_parent_idmap_setup_lookupname_done,
     353             :                                 req);
     354             : }
     355             : 
     356          72 : static void wb_parent_idmap_setup_lookupname_done(struct tevent_req *subreq)
     357             : {
     358          54 :         struct tevent_req *req =
     359          72 :                 tevent_req_callback_data(subreq,
     360             :                 struct tevent_req);
     361          54 :         struct wb_parent_idmap_setup_state *state =
     362          72 :                 tevent_req_data(req,
     363             :                 struct wb_parent_idmap_setup_state);
     364          72 :         struct wb_parent_idmap_config_dom *dom =
     365          72 :                 &state->cfg->doms[state->dom_idx];
     366             :         enum lsa_SidType type;
     367             :         NTSTATUS status;
     368             : 
     369          72 :         status = wb_lookupname_recv(subreq, &dom->sid, &type);
     370          72 :         TALLOC_FREE(subreq);
     371          72 :         if (!NT_STATUS_IS_OK(status)) {
     372           0 :                 DBG_ERR("Lookup domain name '%s' failed '%s'\n",
     373             :                         dom->name,
     374             :                         nt_errstr(status));
     375             : 
     376           0 :                 state->dom_idx++;
     377           0 :                 wb_parent_idmap_setup_lookupname_next(req);
     378           0 :                 return;
     379             :         }
     380             : 
     381          72 :         if (type != SID_NAME_DOMAIN) {
     382             :                 struct dom_sid_buf buf;
     383             : 
     384           0 :                 DBG_ERR("SID %s for idmap domain name '%s' "
     385             :                         "not a domain SID\n",
     386             :                         dom_sid_str_buf(&dom->sid, &buf),
     387             :                         dom->name);
     388             : 
     389           0 :                 ZERO_STRUCT(dom->sid);
     390             :         }
     391             : 
     392          72 :         state->dom_idx++;
     393          72 :         wb_parent_idmap_setup_lookupname_next(req);
     394             : 
     395          72 :         return;
     396             : }
     397             : 
     398       10526 : NTSTATUS wb_parent_idmap_setup_recv(struct tevent_req *req,
     399             :                                     const struct wb_parent_idmap_config **_cfg)
     400             : {
     401       10526 :         const struct wb_parent_idmap_config *cfg = &static_parent_idmap_config;
     402             :         NTSTATUS status;
     403             : 
     404       10526 :         *_cfg = NULL;
     405             : 
     406       10526 :         if (tevent_req_is_nterror(req, &status)) {
     407           0 :                 tevent_req_received(req);
     408           0 :                 return status;
     409             :         }
     410             : 
     411             :         /*
     412             :          * Note state->cfg is already set to NULL by
     413             :          * wb_parent_idmap_setup_cleanup()
     414             :          */
     415       10526 :         *_cfg = cfg;
     416       10526 :         tevent_req_received(req);
     417       10526 :         return NT_STATUS_OK;
     418             : }

Generated by: LCOV version 1.13