LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_idmap.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 124 191 64.9 %
Date: 2024-04-21 15:09:00 Functions: 11 13 84.6 %

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

Generated by: LCOV version 1.14