LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - partition.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 536 727 73.7 %
Date: 2024-04-21 15:09:00 Functions: 27 27 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Partitions ldb module
       3             : 
       4             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
       5             :    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             :    
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             :    
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : /*
      22             :  *  Name: ldb
      23             :  *
      24             :  *  Component: ldb partitions module
      25             :  *
      26             :  *  Description: Implement LDAP partitions
      27             :  *
      28             :  *  Author: Andrew Bartlett
      29             :  *  Author: Stefan Metzmacher
      30             :  */
      31             : 
      32             : #include "dsdb/samdb/ldb_modules/partition.h"
      33             : 
      34             : struct part_request {
      35             :         struct ldb_module *module;
      36             :         struct ldb_request *req;
      37             : };
      38             : 
      39             : struct partition_context {
      40             :         struct ldb_module *module;
      41             :         struct ldb_request *req;
      42             : 
      43             :         struct part_request *part_req;
      44             :         unsigned int num_requests;
      45             :         unsigned int finished_requests;
      46             : 
      47             :         const char **referrals;
      48             : };
      49             : 
      50    55736059 : static struct partition_context *partition_init_ctx(struct ldb_module *module, struct ldb_request *req)
      51             : {
      52     2454981 :         struct partition_context *ac;
      53             : 
      54    55736059 :         ac = talloc_zero(req, struct partition_context);
      55    55736059 :         if (ac == NULL) {
      56           0 :                 ldb_set_errstring(ldb_module_get_ctx(module), "Out of Memory");
      57           0 :                 return NULL;
      58             :         }
      59             : 
      60    55736059 :         ac->module = module;
      61    55736059 :         ac->req = req;
      62             : 
      63    55736059 :         return ac;
      64             : }
      65             : 
      66             : /*
      67             :  * helper functions to call the next module in chain
      68             :  */
      69   127237071 : int partition_request(struct ldb_module *module, struct ldb_request *request)
      70             : {
      71   127237071 :         if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) { \
      72           0 :                 const struct dsdb_control_current_partition *partition = NULL;
      73           0 :                 struct ldb_control *partition_ctrl = ldb_request_get_control(request, DSDB_CONTROL_CURRENT_PARTITION_OID);
      74           0 :                 if (partition_ctrl) {
      75           0 :                         partition = talloc_get_type(partition_ctrl->data,
      76             :                                                     struct dsdb_control_current_partition);
      77             :                 }
      78             : 
      79           0 :                 if (partition != NULL) {
      80           0 :                         ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_request() -> %s",
      81           0 :                                   ldb_dn_get_linearized(partition->dn));                     
      82             :                 } else {
      83           0 :                         ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_request() -> (metadata partition)");
      84             :                 }
      85             :         }
      86             : 
      87   127237071 :         return ldb_next_request(module, request);
      88             : }
      89             : 
      90    57776017 : static struct dsdb_partition *find_partition(struct partition_private_data *data,
      91             :                                              struct ldb_dn *dn,
      92             :                                              struct ldb_request *req)
      93             : {
      94     2504508 :         unsigned int i;
      95     2504508 :         struct ldb_control *partition_ctrl;
      96             : 
      97             :         /* see if the request has the partition DN specified in a
      98             :          * control. The repl_meta_data module can specify this to
      99             :          * ensure that replication happens to the right partition
     100             :          */
     101    57776017 :         partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
     102    57776017 :         if (partition_ctrl) {
     103      621419 :                 const struct dsdb_control_current_partition *partition;
     104     7583398 :                 partition = talloc_get_type(partition_ctrl->data,
     105             :                                             struct dsdb_control_current_partition);
     106     7583398 :                 if (partition != NULL) {
     107      285413 :                         dn = partition->dn;
     108             :                 }
     109             :         }
     110             : 
     111    57776017 :         if (dn == NULL) {
     112    52881872 :                 return NULL;
     113             :         }
     114             : 
     115             :         /* Look at base DN */
     116             :         /* Figure out which partition it is under */
     117             :         /* Skip the lot if 'data' isn't here yet (initialisation) */
     118     7501225 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
     119     7500467 :                 if (ldb_dn_compare_base(data->partitions[i]->ctrl->dn, dn) == 0) {
     120     2504139 :                         return data->partitions[i];
     121             :                 }
     122             :         }
     123             : 
     124         702 :         return NULL;
     125             : }
     126             : 
     127             : /**
     128             :  * fire the caller's callback for every entry, but only send 'done' once.
     129             :  */
     130   226500776 : static int partition_req_callback(struct ldb_request *req,
     131             :                                   struct ldb_reply *ares)
     132             : {
     133     6790384 :         struct partition_context *ac;
     134     6790384 :         struct ldb_module *module;
     135     6790384 :         struct ldb_request *nreq;
     136     6790384 :         int ret;
     137     6790384 :         struct ldb_control *partition_ctrl;
     138             : 
     139   226500776 :         ac = talloc_get_type(req->context, struct partition_context);
     140             : 
     141   226500776 :         if (!ares) {
     142           0 :                 return ldb_module_done(ac->req, NULL, NULL,
     143             :                                         LDB_ERR_OPERATIONS_ERROR);
     144             :         }
     145             : 
     146   226500776 :         partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID);
     147   226500776 :         if (partition_ctrl && (ac->num_requests == 1 || ares->type == LDB_REPLY_ENTRY)) {
     148             :                 /* If we didn't fan this request out to multiple partitions,
     149             :                  * or this is an individual search result, we can
     150             :                  * deterministically tell the caller what partition this was
     151             :                  * written to (repl_meta_data likes to know) */
     152    11660691 :                 ret = ldb_reply_add_control(ares,
     153             :                                             DSDB_CONTROL_CURRENT_PARTITION_OID,
     154             :                                             false, partition_ctrl->data);
     155    11660691 :                 if (ret != LDB_SUCCESS) {
     156           0 :                         return ldb_module_done(ac->req, NULL, NULL,
     157             :                                                ret);
     158             :                 }
     159             :         }
     160             : 
     161   226500776 :         if (ares->error != LDB_SUCCESS) {
     162     2173823 :                 return ldb_module_done(ac->req, ares->controls,
     163             :                                         ares->response, ares->error);
     164             :         }
     165             : 
     166   224326953 :         switch (ares->type) {
     167           0 :         case LDB_REPLY_REFERRAL:
     168           0 :                 return ldb_module_send_referral(ac->req, ares->referral);
     169             : 
     170    99317516 :         case LDB_REPLY_ENTRY:
     171    99317516 :                 if (ac->req->operation != LDB_SEARCH) {
     172           0 :                         ldb_set_errstring(ldb_module_get_ctx(ac->module),
     173             :                                 "partition_req_callback:"
     174             :                                 " Unsupported reply type for this request");
     175           0 :                         return ldb_module_done(ac->req, NULL, NULL,
     176             :                                                 LDB_ERR_OPERATIONS_ERROR);
     177             :                 }
     178             :                 
     179    99317516 :                 return ldb_module_send_entry(ac->req, ares->message, ares->controls);
     180             : 
     181   125009437 :         case LDB_REPLY_DONE:
     182   125009437 :                 if (ac->req->operation == LDB_EXTENDED) {
     183             :                         /* FIXME: check for ares->response, replmd does not fill it ! */
     184           0 :                         if (ares->response) {
     185           0 :                                 if (strcmp(ares->response->oid, LDB_EXTENDED_START_TLS_OID) != 0) {
     186           0 :                                         ldb_set_errstring(ldb_module_get_ctx(ac->module),
     187             :                                                           "partition_req_callback:"
     188             :                                                           " Unknown extended reply, "
     189             :                                                           "only supports START_TLS");
     190           0 :                                         talloc_free(ares);
     191           0 :                                         return ldb_module_done(ac->req, NULL, NULL,
     192             :                                                                 LDB_ERR_OPERATIONS_ERROR);
     193             :                                 }
     194             :                         }
     195             :                 }
     196             : 
     197   125009437 :                 ac->finished_requests++;
     198   125009437 :                 if (ac->finished_requests == ac->num_requests) {
     199             :                         /* Send back referrals if they do exist (search ops) */
     200    53507644 :                         if (ac->referrals != NULL) {
     201             :                                 const char **ref;
     202     6135418 :                                 for (ref = ac->referrals; *ref != NULL; ++ref) {
     203     4190615 :                                         ret = ldb_module_send_referral(ac->req,
     204     4190615 :                                                                        talloc_strdup(ac->req, *ref));
     205     4190615 :                                         if (ret != LDB_SUCCESS) {
     206           0 :                                                 return ldb_module_done(ac->req, NULL, NULL,
     207             :                                                                        ret);
     208             :                                         }
     209             :                                 }
     210             :                         }
     211             : 
     212             :                         /* this was the last one, call callback */
     213    53507644 :                         return ldb_module_done(ac->req, ares->controls,
     214             :                                                ares->response, 
     215             :                                                ares->error);
     216             :                 }
     217             : 
     218             :                 /* not the last, now call the next one */
     219    71501793 :                 module = ac->part_req[ac->finished_requests].module;
     220    71501793 :                 nreq = ac->part_req[ac->finished_requests].req;
     221             : 
     222    71501793 :                 ret = partition_request(module, nreq);
     223    71501793 :                 if (ret != LDB_SUCCESS) {
     224           0 :                         talloc_free(ares);
     225           0 :                         return ldb_module_done(ac->req, NULL, NULL, ret);
     226             :                 }
     227             : 
     228    69820228 :                 break;
     229             :         }
     230             : 
     231    71501793 :         talloc_free(ares);
     232    71501793 :         return LDB_SUCCESS;
     233             : }
     234             : 
     235   127237047 : static int partition_prep_request(struct partition_context *ac,
     236             :                                   struct dsdb_partition *partition)
     237             : {
     238     4136485 :         int ret;
     239     4136485 :         struct ldb_request *req;
     240   127237047 :         struct ldb_control *partition_ctrl = NULL;
     241   127237047 :         void *part_data = NULL;
     242             : 
     243   127237047 :         ac->part_req = talloc_realloc(ac, ac->part_req,
     244             :                                         struct part_request,
     245             :                                         ac->num_requests + 1);
     246   127237047 :         if (ac->part_req == NULL) {
     247           0 :                 return ldb_oom(ldb_module_get_ctx(ac->module));
     248             :         }
     249             : 
     250   127237047 :         switch (ac->req->operation) {
     251   124951595 :         case LDB_SEARCH:
     252   124951595 :                 ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(ac->module),
     253   120929560 :                                         ac->part_req,
     254   120929560 :                                         ac->req->op.search.base,
     255   120929560 :                                         ac->req->op.search.scope,
     256   120929560 :                                         ac->req->op.search.tree,
     257   120929560 :                                         ac->req->op.search.attrs,
     258   120929560 :                                         ac->req->controls,
     259             :                                         ac, partition_req_callback,
     260             :                                         ac->req);
     261   124951595 :                 LDB_REQ_SET_LOCATION(req);
     262   124951595 :                 break;
     263      923595 :         case LDB_ADD:
     264      923595 :                 ret = ldb_build_add_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
     265      839862 :                                         ac->req->op.add.message,
     266      839862 :                                         ac->req->controls,
     267             :                                         ac, partition_req_callback,
     268             :                                         ac->req);
     269      923595 :                 LDB_REQ_SET_LOCATION(req);
     270      923595 :                 break;
     271     1281027 :         case LDB_MODIFY:
     272     1281027 :                 ret = ldb_build_mod_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
     273     1250493 :                                         ac->req->op.mod.message,
     274     1250493 :                                         ac->req->controls,
     275             :                                         ac, partition_req_callback,
     276             :                                         ac->req);
     277     1281027 :                 LDB_REQ_SET_LOCATION(req);
     278     1281027 :                 break;
     279          33 :         case LDB_DELETE:
     280          33 :                 ret = ldb_build_del_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
     281           7 :                                         ac->req->op.del.dn,
     282           7 :                                         ac->req->controls,
     283             :                                         ac, partition_req_callback,
     284             :                                         ac->req);
     285          33 :                 LDB_REQ_SET_LOCATION(req);
     286          33 :                 break;
     287       80797 :         case LDB_RENAME:
     288       80797 :                 ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ac->module), ac->part_req,
     289       80640 :                                         ac->req->op.rename.olddn,
     290       80640 :                                         ac->req->op.rename.newdn,
     291       80640 :                                         ac->req->controls,
     292             :                                         ac, partition_req_callback,
     293             :                                         ac->req);
     294       80797 :                 LDB_REQ_SET_LOCATION(req);
     295       80797 :                 break;
     296           0 :         case LDB_EXTENDED:
     297           0 :                 ret = ldb_build_extended_req(&req, ldb_module_get_ctx(ac->module),
     298           0 :                                         ac->part_req,
     299           0 :                                         ac->req->op.extended.oid,
     300           0 :                                         ac->req->op.extended.data,
     301           0 :                                         ac->req->controls,
     302             :                                         ac, partition_req_callback,
     303             :                                         ac->req);
     304           0 :                 LDB_REQ_SET_LOCATION(req);
     305           0 :                 break;
     306           0 :         default:
     307           0 :                 ldb_set_errstring(ldb_module_get_ctx(ac->module),
     308             :                                   "Unsupported request type!");
     309           0 :                 ret = LDB_ERR_UNWILLING_TO_PERFORM;
     310             :         }
     311             : 
     312   127237047 :         if (ret != LDB_SUCCESS) {
     313           0 :                 return ret;
     314             :         }
     315             : 
     316   127237047 :         ac->part_req[ac->num_requests].req = req;
     317             : 
     318   127237047 :         if (ac->req->controls) {
     319             :                 /* Duplicate everything beside the current partition control */
     320   120823186 :                 partition_ctrl = ldb_request_get_control(ac->req,
     321             :                                                          DSDB_CONTROL_CURRENT_PARTITION_OID);
     322   120823186 :                 if (!ldb_save_controls(partition_ctrl, req, NULL)) {
     323           0 :                         return ldb_module_oom(ac->module);
     324             :                 }
     325             :         }
     326             : 
     327   127237047 :         part_data = partition->ctrl;
     328             : 
     329   127237047 :         ac->part_req[ac->num_requests].module = partition->module;
     330             : 
     331   127237047 :         if (partition_ctrl != NULL) {
     332     7525472 :                 if (partition_ctrl->data != NULL) {
     333      228096 :                         part_data = partition_ctrl->data;
     334             :                 }
     335             : 
     336             :                 /*
     337             :                  * If the provided current partition control is without
     338             :                  * data then use the calculated one.
     339             :                  */
     340     7525472 :                 ret = ldb_request_add_control(req,
     341             :                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
     342             :                                               false, part_data);
     343     7525472 :                 if (ret != LDB_SUCCESS) {
     344           0 :                         return ret;
     345             :                 }
     346             :         }
     347             : 
     348   127237047 :         if (req->operation == LDB_SEARCH) {
     349             :                 /*
     350             :                  * If the search is for 'more' than this partition,
     351             :                  * then change the basedn, so the check of the BASE DN
     352             :                  * still passes in the ldb_key_value layer
     353             :                  */
     354   124951595 :                 if (ldb_dn_compare_base(partition->ctrl->dn,
     355   120929560 :                                         req->op.search.base) != 0) {
     356    91094050 :                         req->op.search.base = partition->ctrl->dn;
     357             :                 }
     358             :         }
     359             : 
     360   127237047 :         ac->num_requests++;
     361             : 
     362   127237047 :         return LDB_SUCCESS;
     363             : }
     364             : 
     365    55735254 : static int partition_call_first(struct partition_context *ac)
     366             : {
     367    55735254 :         return partition_request(ac->part_req[0].module, ac->part_req[0].req);
     368             : }
     369             : 
     370             : /**
     371             :  * Send a request down to all the partitions (but not the sam.ldb file)
     372             :  */
     373    19592257 : static int partition_send_all(struct ldb_module *module, 
     374             :                               struct partition_context *ac, 
     375             :                               struct ldb_request *req) 
     376             : {
     377      466066 :         unsigned int i;
     378    19592257 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
     379             :                                                               struct partition_private_data);
     380      466066 :         int ret;
     381             : 
     382   111061632 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
     383    91003309 :                 ret = partition_prep_request(ac, data->partitions[i]);
     384    91003309 :                 if (ret != LDB_SUCCESS) {
     385           0 :                         return ret;
     386             :                 }
     387             :         }
     388             : 
     389             :         /* fire the first one */
     390    19592257 :         return partition_call_first(ac);
     391             : }
     392             : 
     393             : struct partition_copy_context {
     394             :         struct ldb_module *module;
     395             :         struct partition_context *partition_context;
     396             :         struct ldb_request *request;
     397             :         struct ldb_dn *dn;
     398             : };
     399             : 
     400             : /*
     401             :  * A special DN has been updated in the primary partition. Now propagate those
     402             :  * changes to the remaining partitions.
     403             :  *
     404             :  * Note: that the operations are asynchronous and this function is called
     405             :  *       from partition_copy_all_callback_handler in response to an async
     406             :  *       callback.
     407             :  */
     408         272 : static int partition_copy_all_callback_action(
     409             :         struct ldb_module *module,
     410             :         struct partition_context *ac,
     411             :         struct ldb_request *req,
     412             :         struct ldb_dn *dn)
     413             : 
     414             : {
     415             : 
     416          32 :         unsigned int i;
     417          32 :         struct partition_private_data *data =
     418         272 :                 talloc_get_type(
     419             :                         ldb_module_get_private(module),
     420             :                         struct partition_private_data);
     421          32 :         int search_ret;
     422          32 :         struct ldb_result *res;
     423             :         /* now fetch the resulting object, and then copy it to all the
     424             :          * other partitions. We need this approach to cope with the
     425             :          * partitions getting out of sync. If for example the
     426             :          * @ATTRIBUTES object exists on one partition but not the
     427             :          * others then just doing each of the partitions in turn will
     428             :          * lead to an error
     429             :          */
     430         272 :         search_ret = dsdb_module_search_dn(module, ac, &res, dn, NULL, DSDB_FLAG_NEXT_MODULE, req);
     431         272 :         if (search_ret != LDB_SUCCESS && search_ret != LDB_ERR_NO_SUCH_OBJECT) {
     432           0 :                 return search_ret;
     433             :         }
     434             : 
     435             :         /* now delete the object in the other partitions, if required
     436             :         */
     437         272 :         if (search_ret == LDB_ERR_NO_SUCH_OBJECT) {
     438           0 :                 for (i=0; data->partitions && data->partitions[i]; i++) {
     439           0 :                         int pret;
     440           0 :                         pret = dsdb_module_del(data->partitions[i]->module,
     441             :                                                dn,
     442             :                                                DSDB_FLAG_NEXT_MODULE,
     443             :                                                req);
     444           0 :                         if (pret != LDB_SUCCESS && pret != LDB_ERR_NO_SUCH_OBJECT) {
     445             :                                 /* we should only get success or no
     446             :                                    such object from the other partitions */
     447           0 :                                 return pret;
     448             :                         }
     449             :                 }
     450             : 
     451           0 :                 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     452             :         }
     453             : 
     454             :         /* now add/modify in the other partitions */
     455        1566 :         for (i=0; data->partitions && data->partitions[i]; i++) {
     456        1294 :                 struct ldb_message *modify_msg = NULL;
     457         152 :                 int pret;
     458         152 :                 unsigned int el_idx;
     459             : 
     460        1446 :                 pret = dsdb_module_add(data->partitions[i]->module,
     461        1294 :                                        res->msgs[0],
     462             :                                        DSDB_FLAG_NEXT_MODULE,
     463             :                                        req);
     464        1294 :                 if (pret == LDB_SUCCESS) {
     465           0 :                         continue;
     466             :                 }
     467             : 
     468        1294 :                 if (pret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
     469           0 :                         return pret;
     470             :                 }
     471             : 
     472        1294 :                 modify_msg = ldb_msg_copy(req, res->msgs[0]);
     473        1294 :                 if (modify_msg == NULL) {
     474           0 :                         return ldb_module_oom(module);
     475             :                 }
     476             : 
     477             :                 /*
     478             :                  * mark all the message elements as
     479             :                  * LDB_FLAG_MOD_REPLACE
     480             :                  */
     481        1142 :                 for (el_idx=0;
     482      548377 :                      el_idx < modify_msg->num_elements;
     483      547083 :                      el_idx++) {
     484      547083 :                         modify_msg->elements[el_idx].flags
     485      547083 :                                 = LDB_FLAG_MOD_REPLACE;
     486             :                 }
     487             : 
     488        1294 :                 if (req->operation == LDB_MODIFY) {
     489        1294 :                         const struct ldb_message *req_msg = req->op.mod.message;
     490             :                         /*
     491             :                          * mark elements to be removed, if these were
     492             :                          * deleted entirely above we need to delete
     493             :                          * them here too
     494             :                          */
     495       15331 :                         for (el_idx=0; el_idx < req_msg->num_elements; el_idx++) {
     496       14037 :                                 if (LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_DELETE
     497       12971 :                                     || ((LDB_FLAG_MOD_TYPE(req_msg->elements[el_idx].flags) == LDB_FLAG_MOD_REPLACE) &&
     498        9168 :                                         req_msg->elements[el_idx].num_values == 0)) {
     499        1066 :                                         if (ldb_msg_find_element(modify_msg,
     500         962 :                                                                  req_msg->elements[el_idx].name) != NULL) {
     501           0 :                                                 continue;
     502             :                                         }
     503        1170 :                                         pret = ldb_msg_add_empty(
     504             :                                                 modify_msg,
     505        1066 :                                                 req_msg->elements[el_idx].name,
     506             :                                                 LDB_FLAG_MOD_REPLACE,
     507             :                                                 NULL);
     508        1066 :                                         if (pret != LDB_SUCCESS) {
     509           0 :                                                 return pret;
     510             :                                         }
     511             :                                 }
     512             :                         }
     513             :                 }
     514             : 
     515        1294 :                 pret = dsdb_module_modify(data->partitions[i]->module,
     516             :                                           modify_msg,
     517             :                                           DSDB_FLAG_NEXT_MODULE,
     518             :                                           req);
     519             : 
     520        1294 :                 if (pret != LDB_SUCCESS) {
     521           0 :                         return pret;
     522             :                 }
     523             :         }
     524             : 
     525         272 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     526             : }
     527             : 
     528             : 
     529             : /*
     530             :  * @brief call back function for the ldb operations on special DN's.
     531             :  *
     532             :  * As the LDB operations are async, and we wish to use the result
     533             :  * the operations, a callback needs to be registered to process the results
     534             :  * of the LDB operations.
     535             :  *
     536             :  * @param req the ldb request
     537             :  * @param res the result of the operation
     538             :  *
     539             :  * @return the LDB_STATUS
     540             :  */
     541         274 : static int partition_copy_all_callback_handler(
     542             :         struct ldb_request *req,
     543             :         struct ldb_reply *ares)
     544             : {
     545         274 :         struct partition_copy_context *ac = NULL;
     546             : 
     547         274 :         ac = talloc_get_type(
     548             :                 req->context,
     549             :                 struct partition_copy_context);
     550             : 
     551         274 :         if (!ares) {
     552           0 :                 return ldb_module_done(
     553             :                         ac->request,
     554             :                         NULL,
     555             :                         NULL,
     556             :                         LDB_ERR_OPERATIONS_ERROR);
     557             :         }
     558             : 
     559             :         /* pass on to the callback */
     560         274 :         switch (ares->type) {
     561           0 :         case LDB_REPLY_ENTRY:
     562           0 :                 return ldb_module_send_entry(
     563             :                         ac->request,
     564             :                         ares->message,
     565             :                         ares->controls);
     566             : 
     567           0 :         case LDB_REPLY_REFERRAL:
     568           0 :                 return ldb_module_send_referral(
     569             :                         ac->request,
     570             :                         ares->referral);
     571             : 
     572         274 :         case LDB_REPLY_DONE: {
     573         274 :                 int error = ares->error;
     574         274 :                 if (error == LDB_SUCCESS) {
     575         272 :                         error = partition_copy_all_callback_action(
     576             :                                 ac->module,
     577             :                                 ac->partition_context,
     578             :                                 ac->request,
     579             :                                 ac->dn);
     580             :                 }
     581         274 :                 return ldb_module_done(
     582             :                         ac->request,
     583             :                         ares->controls,
     584             :                         ares->response,
     585             :                         error);
     586             :         }
     587             : 
     588           0 :         default:
     589             :                 /* Can't happen */
     590           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     591             :         }
     592             : }
     593             : 
     594             : /**
     595             :  * send an operation to the top partition, then copy the resulting
     596             :  * object to all other partitions.
     597             :  */
     598         274 : static int partition_copy_all(
     599             :         struct ldb_module *module,
     600             :         struct partition_context *partition_context,
     601             :         struct ldb_request *req,
     602             :         struct ldb_dn *dn)
     603             : {
     604         274 :         struct ldb_request *new_req = NULL;
     605         274 :         struct ldb_context *ldb = NULL;
     606         274 :         struct partition_copy_context *context = NULL;
     607             : 
     608          32 :         int ret;
     609             : 
     610         274 :         ldb = ldb_module_get_ctx(module);
     611             : 
     612         274 :         context = talloc_zero(req, struct partition_copy_context);
     613         274 :         if (context == NULL) {
     614           0 :                 return ldb_oom(ldb);
     615             :         }
     616         274 :         context->module = module;
     617         274 :         context->request = req;
     618         274 :         context->dn = dn;
     619         274 :         context->partition_context = partition_context;
     620             : 
     621         274 :         switch (req->operation) {
     622           0 :         case LDB_ADD:
     623           0 :                 ret = ldb_build_add_req(
     624             :                         &new_req,
     625             :                         ldb,
     626             :                         req,
     627             :                         req->op.add.message,
     628             :                         req->controls,
     629             :                         context,
     630             :                         partition_copy_all_callback_handler,
     631             :                         req);
     632           0 :                 break;
     633         274 :         case LDB_MODIFY:
     634         274 :                 ret = ldb_build_mod_req(
     635             :                         &new_req,
     636             :                         ldb,
     637             :                         req,
     638             :                         req->op.mod.message,
     639             :                         req->controls,
     640             :                         context,
     641             :                         partition_copy_all_callback_handler,
     642             :                         req);
     643         274 :                 break;
     644           0 :         case LDB_DELETE:
     645           0 :                 ret = ldb_build_del_req(
     646             :                         &new_req,
     647             :                         ldb,
     648             :                         req,
     649             :                         req->op.del.dn,
     650             :                         req->controls,
     651             :                         context,
     652             :                         partition_copy_all_callback_handler,
     653             :                         req);
     654           0 :                 break;
     655           0 :         case LDB_RENAME:
     656           0 :                 ret = ldb_build_rename_req(
     657             :                         &new_req,
     658             :                         ldb,
     659             :                         req,
     660             :                         req->op.rename.olddn,
     661             :                         req->op.rename.newdn,
     662             :                         req->controls,
     663             :                         context,
     664             :                         partition_copy_all_callback_handler,
     665             :                         req);
     666           0 :                 break;
     667           0 :         default:
     668             :                 /*
     669             :                  * Shouldn't happen.
     670             :                  */
     671           0 :                 ldb_debug(
     672             :                         ldb,
     673             :                         LDB_DEBUG_ERROR,
     674           0 :                         "Unexpected operation type (%d)\n", req->operation);
     675           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
     676           0 :                 break;
     677             :         }
     678         274 :         if (ret != LDB_SUCCESS) {
     679           0 :                 return ret;
     680             :         }
     681         274 :         return ldb_next_request(module, new_req);
     682             : }
     683             : /**
     684             :  * Figure out which backend a request needs to be aimed at.  Some
     685             :  * requests must be replicated to all backends
     686             :  */
     687     2286712 : static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn) 
     688             : {
     689      114582 :         struct partition_context *ac;
     690      114582 :         unsigned int i;
     691      114582 :         int ret;
     692      114582 :         struct dsdb_partition *partition;
     693     2286712 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
     694             :                                                               struct partition_private_data);
     695             : 
     696             :         /* if we aren't initialised yet go further */
     697     2286712 :         if (!data || !data->partitions) {
     698         458 :                 return ldb_next_request(module, req);
     699             :         }
     700             : 
     701     2286254 :         if (ldb_dn_is_special(dn)) {
     702             :                 /* Is this a special DN, we need to replicate to every backend? */
     703      914830 :                 for (i=0; data->replicate && data->replicate[i]; i++) {
     704      686212 :                         if (ldb_dn_compare(data->replicate[i], 
     705             :                                            dn) == 0) {
     706             :                                 
     707         274 :                                 ac = partition_init_ctx(module, req);
     708         274 :                                 if (!ac) {
     709           0 :                                         return ldb_operr(ldb_module_get_ctx(module));
     710             :                                 }
     711             :                                 
     712         274 :                                 return partition_copy_all(module, ac, req, dn);
     713             :                         }
     714             :                 }
     715             :         }
     716             : 
     717             :         /* Otherwise, we need to find the partition to fire it to */
     718             : 
     719             :         /* Find partition */
     720     2285980 :         partition = find_partition(data, dn, req);
     721     2285980 :         if (!partition) {
     722             :                 /*
     723             :                  * if we haven't found a matching partition
     724             :                  * pass the request to the main ldb
     725             :                  *
     726             :                  * TODO: we should maybe return an error here
     727             :                  *       if it's not a special dn
     728             :                  */
     729             : 
     730         528 :                 return ldb_next_request(module, req);
     731             :         }
     732             : 
     733     2285452 :         ac = partition_init_ctx(module, req);
     734     2285452 :         if (!ac) {
     735           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     736             :         }
     737             : 
     738             :         /* we need to add a control but we never touch the original request */
     739     2285452 :         ret = partition_prep_request(ac, partition);
     740     2285452 :         if (ret != LDB_SUCCESS) {
     741           0 :                 return ret;
     742             :         }
     743             : 
     744             :         /* fire the first one */
     745     2285452 :         return partition_call_first(ac);
     746             : }
     747             : 
     748             : /* search */
     749    55328437 : static int partition_search(struct ldb_module *module, struct ldb_request *req)
     750             : {
     751             :         /* Find backend */
     752    55328437 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
     753             :                                                               struct partition_private_data);
     754     2389688 :         struct partition_context *ac;
     755     2389688 :         struct ldb_context *ldb;
     756     2389688 :         struct loadparm_context *lp_ctx;
     757             : 
     758    55328437 :         struct ldb_control *search_control = ldb_request_get_control(req, LDB_CONTROL_SEARCH_OPTIONS_OID);
     759    55328437 :         struct ldb_control *domain_scope_control = ldb_request_get_control(req, LDB_CONTROL_DOMAIN_SCOPE_OID);
     760    55328437 :         struct ldb_control *no_gc_control = ldb_request_get_control(req, DSDB_CONTROL_NO_GLOBAL_CATALOG);
     761             :         
     762    55328437 :         struct ldb_search_options_control *search_options = NULL;
     763     2389688 :         struct dsdb_partition *p;
     764     2389688 :         unsigned int i, j;
     765     2389688 :         int ret;
     766    55328437 :         bool domain_scope = false, phantom_root = false;
     767             : 
     768    55328437 :         p = find_partition(data, NULL, req);
     769    55328437 :         if (p != NULL) {
     770             :                 /* the caller specified what partition they want the
     771             :                  * search - just pass it on
     772             :                  */
     773       57089 :                 return ldb_next_request(p->module, req);
     774             :         }
     775             : 
     776             :         /* Get back the search options from the search control, and mark it as
     777             :          * non-critical (to make backends and also dcpromo happy).
     778             :          */
     779    55271348 :         if (search_control) {
     780    19620337 :                 search_options = talloc_get_type(search_control->data, struct ldb_search_options_control);
     781    19620337 :                 search_control->critical = 0;
     782             : 
     783             :         }
     784             : 
     785             :         /* if we aren't initialised yet go further */
     786    55271348 :         if (!data || !data->partitions) {
     787      187176 :                 return ldb_next_request(module, req);
     788             :         }
     789             : 
     790             :         /* Special DNs without specified partition should go further */
     791    55084172 :         if (ldb_dn_is_special(req->op.search.base)) {
     792     1633839 :                 return ldb_next_request(module, req);
     793             :         }
     794             : 
     795             :         /* Locate the options */
     796    55790832 :         domain_scope = (search_options
     797    19620337 :                 && (search_options->search_options & LDB_SEARCH_OPTION_DOMAIN_SCOPE))
     798    73070670 :                 || domain_scope_control;
     799    55790832 :         phantom_root = search_options
     800    53450333 :                 && (search_options->search_options & LDB_SEARCH_OPTION_PHANTOM_ROOT);
     801             : 
     802             :         /* Remove handled options from the search control flag */
     803    53450333 :         if (search_options) {
     804    19620337 :                 search_options->search_options = search_options->search_options
     805             :                         & ~LDB_SEARCH_OPTION_DOMAIN_SCOPE
     806    19620337 :                         & ~LDB_SEARCH_OPTION_PHANTOM_ROOT;
     807             :         }
     808             : 
     809    53450333 :         ac = partition_init_ctx(module, req);
     810    53450333 :         if (!ac) {
     811           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     812             :         }
     813             : 
     814    53450333 :         ldb = ldb_module_get_ctx(ac->module);
     815    53450333 :         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
     816             :                                                 struct loadparm_context);
     817             : 
     818             :         /* Search from the base DN */
     819    53450333 :         if (ldb_dn_is_null(req->op.search.base)) {
     820    19592257 :                 if (!phantom_root) {
     821           0 :                         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, "empty base DN");
     822             :                 }
     823    19592257 :                 return partition_send_all(module, ac, req);
     824             :         }
     825             : 
     826   103949168 :         for (i=0; data->partitions[i]; i++) {
     827   103948637 :                 bool match = false, stop = false;
     828             : 
     829   103948637 :                 if (data->partitions[i]->partial_replica && no_gc_control != NULL) {
     830           0 :                         if (ldb_dn_compare_base(data->partitions[i]->ctrl->dn,
     831             :                                                 req->op.search.base) == 0) {
     832             :                                 /* base DN is in a partial replica
     833             :                                    with the NO_GLOBAL_CATALOG
     834             :                                    control. This partition is invisible */
     835             :                                 /* DEBUG(0,("DENYING NON-GC OP: %s\n", ldb_module_call_chain(req, req))); */
     836           0 :                                 continue;
     837             :                         }
     838             :                 }
     839             : 
     840   103948637 :                 if (phantom_root) {
     841             :                         /* Phantom root: Find all partitions under the
     842             :                          * search base. We match if:
     843             :                          *
     844             :                          * 1) the DN we are looking for exactly matches a
     845             :                          *    certain partition and always stop
     846             :                          * 2) the DN we are looking for is a parent of certain
     847             :                          *    partitions and it isn't a scope base search
     848             :                          * 3) the DN we are looking for is a child of a certain
     849             :                          *    partition and always stop
     850             :                          *    - we don't need to go any further up in the
     851             :                          *    hierarchy!
     852             :                          */
     853      118571 :                         if (ldb_dn_compare(data->partitions[i]->ctrl->dn,
     854             :                                            req->op.search.base) == 0) {
     855       27780 :                                 match = true;
     856       27780 :                                 stop = true;
     857             :                         }
     858      209362 :                         if (!match &&
     859       90791 :                             (ldb_dn_compare_base(req->op.search.base,
     860       90791 :                                                  data->partitions[i]->ctrl->dn) == 0 &&
     861       90741 :                              req->op.search.scope != LDB_SCOPE_BASE)) {
     862       90543 :                                 match = true;
     863             :                         }
     864      118423 :                         if (!match &&
     865          50 :                             ldb_dn_compare_base(data->partitions[i]->ctrl->dn,
     866             :                                                 req->op.search.base) == 0) {
     867          16 :                                 match = true;
     868          16 :                                 stop = true; /* note that this relies on partition ordering */
     869             :                         }
     870             :                 } else {
     871             :                         /* Domain scope: Find all partitions under the search
     872             :                          * base.
     873             :                          *
     874             :                          * We generate referral candidates if we haven't
     875             :                          * specified the domain scope control, haven't a base
     876             :                          * search* scope and the DN we are looking for is a real
     877             :                          * predecessor of certain partitions. When a new
     878             :                          * referral candidate is nearer to the DN than an
     879             :                          * existing one delete the latter (we want to have only
     880             :                          * the closest ones). When we checked this for all
     881             :                          * candidates we have the final referrals.
     882             :                          *
     883             :                          * We match if the DN we are looking for is a child of
     884             :                          * a certain partition or the partition
     885             :                          * DN itself - we don't need to go any further
     886             :                          * up in the hierarchy!
     887             :                          */
     888   103830066 :                         if ((!domain_scope) &&
     889   117420626 :                             (req->op.search.scope != LDB_SCOPE_BASE) &&
     890    13594151 :                             (ldb_dn_compare_base(req->op.search.base,
     891    21824889 :                                                  data->partitions[i]->ctrl->dn) == 0) &&
     892     8230738 :                             (ldb_dn_compare(req->op.search.base,
     893     8230738 :                                             data->partitions[i]->ctrl->dn) != 0)) {
     894     5615833 :                                 const char *scheme = ldb_get_opaque(
     895             :                                     ldb, LDAP_REFERRAL_SCHEME_OPAQUE);
     896    11200406 :                                 char *ref = talloc_asprintf(
     897             :                                         ac,
     898             :                                         "%s://%s/%s%s",
     899             :                                         scheme == NULL ? "ldap" : scheme,
     900             :                                         lpcfg_dnsdomain(lp_ctx),
     901             :                                         ldb_dn_get_linearized(
     902     5615833 :                                             data->partitions[i]->ctrl->dn),
     903     5615833 :                                         req->op.search.scope ==
     904             :                                             LDB_SCOPE_ONELEVEL ? "??base" : "");
     905             : 
     906     5615833 :                                 if (ref == NULL) {
     907           0 :                                         return ldb_oom(ldb);
     908             :                                 }
     909             : 
     910             :                                 /* Initialise the referrals list */
     911     5615833 :                                 if (ac->referrals == NULL) {
     912     1944978 :                                         char **l = str_list_make_empty(ac);
     913     1944978 :                                         ac->referrals = discard_const_p(const char *, l);
     914     1944978 :                                         if (ac->referrals == NULL) {
     915           0 :                                                 return ldb_oom(ldb);
     916             :                                         }
     917             :                                 }
     918             : 
     919             :                                 /* Check if the new referral candidate is
     920             :                                  * closer to the base DN than already
     921             :                                  * saved ones and delete the latters */
     922     5487203 :                                 j = 0;
     923    10409617 :                                 while (ac->referrals[j] != NULL) {
     924     4793784 :                                         if (strstr(ac->referrals[j],
     925     4793784 :                                                    ldb_dn_get_linearized(data->partitions[i]->ctrl->dn)) != NULL) {
     926     1424997 :                                                 str_list_remove(ac->referrals,
     927     1389146 :                                                                 ac->referrals[j]);
     928             :                                         } else {
     929     3368787 :                                                 ++j;
     930             :                                         }
     931             :                                 }
     932             : 
     933             :                                 /* Add our new candidate */
     934     5615833 :                                 ac->referrals = str_list_add(ac->referrals, ref);
     935             : 
     936     5615833 :                                 talloc_free(ref);
     937             : 
     938     5615833 :                                 if (ac->referrals == NULL) {
     939           0 :                                         return ldb_oom(ldb);
     940             :                                 }
     941             :                         }
     942   103830066 :                         if (ldb_dn_compare_base(data->partitions[i]->ctrl->dn, req->op.search.base) == 0) {
     943    31955397 :                                 match = true;
     944    31955397 :                                 stop = true; /* note that this relies on partition ordering */
     945             :                         }
     946             :                 }
     947             : 
     948    99987872 :                 if (match) {
     949    33948286 :                         ret = partition_prep_request(ac, data->partitions[i]);
     950    33948286 :                         if (ret != LDB_SUCCESS) {
     951           0 :                                 return ret;
     952             :                         }
     953             :                 }
     954             : 
     955   103948637 :                 if (stop) break;
     956             :         }
     957             : 
     958             :         /* Perhaps we didn't match any partitions. Try the main partition */
     959    33858076 :         if (ac->num_requests == 0) {
     960         531 :                 talloc_free(ac);
     961         531 :                 return ldb_next_request(module, req);
     962             :         }
     963             : 
     964             :         /* fire the first one */
     965    33857545 :         return partition_call_first(ac);
     966             : }
     967             : 
     968             : /* add */
     969      924135 : static int partition_add(struct ldb_module *module, struct ldb_request *req)
     970             : {
     971      924135 :         return partition_replicate(module, req, req->op.add.message->dn);
     972             : }
     973             : 
     974             : /* modify */
     975     1281744 : static int partition_modify(struct ldb_module *module, struct ldb_request *req)
     976             : {
     977     1281744 :         return partition_replicate(module, req, req->op.mod.message->dn);
     978             : }
     979             : 
     980             : /* delete */
     981          35 : static int partition_delete(struct ldb_module *module, struct ldb_request *req)
     982             : {
     983          35 :         return partition_replicate(module, req, req->op.del.dn);
     984             : }
     985             : 
     986             : /* rename */
     987       80800 : static int partition_rename(struct ldb_module *module, struct ldb_request *req)
     988             : {
     989             :         /* Find backend */
     990         158 :         struct dsdb_partition *backend, *backend2;
     991             :         
     992       80800 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
     993             :                                                               struct partition_private_data);
     994             : 
     995             :         /* Skip the lot if 'data' isn't here yet (initialisation) */
     996       80800 :         if (!data) {
     997           0 :                 return ldb_operr(ldb_module_get_ctx(module));
     998             :         }
     999             : 
    1000       80800 :         backend = find_partition(data, req->op.rename.olddn, req);
    1001       80800 :         backend2 = find_partition(data, req->op.rename.newdn, req);
    1002             : 
    1003       80800 :         if ((backend && !backend2) || (!backend && backend2)) {
    1004           0 :                 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
    1005             :         }
    1006             : 
    1007       80800 :         if (backend != backend2) {
    1008           6 :                 ldb_asprintf_errstring(ldb_module_get_ctx(module), 
    1009             :                                        "Cannot rename from %s in %s to %s in %s: %s",
    1010             :                                        ldb_dn_get_linearized(req->op.rename.olddn),
    1011           2 :                                        ldb_dn_get_linearized(backend->ctrl->dn),
    1012             :                                        ldb_dn_get_linearized(req->op.rename.newdn),
    1013           2 :                                        ldb_dn_get_linearized(backend2->ctrl->dn),
    1014             :                                        ldb_strerror(LDB_ERR_AFFECTS_MULTIPLE_DSAS));
    1015           2 :                 return LDB_ERR_AFFECTS_MULTIPLE_DSAS;
    1016             :         }
    1017             : 
    1018       80798 :         return partition_replicate(module, req, req->op.rename.olddn);
    1019             : }
    1020             : 
    1021             : /* start a transaction */
    1022      349765 : int partition_start_trans(struct ldb_module *module)
    1023             : {
    1024      349765 :         int i = 0;
    1025      349765 :         int ret = 0;
    1026      349765 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1027             :                                                               struct partition_private_data);
    1028             :         /* Look at base DN */
    1029             :         /* Figure out which partition it is under */
    1030             :         /* Skip the lot if 'data' isn't here yet (initialization) */
    1031      349765 :         if (ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING) {
    1032           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> (metadata partition)");
    1033             :         }
    1034             : 
    1035             :         /*
    1036             :          * We start a transaction on metadata.tdb first and end it last in
    1037             :          * end_trans. This makes locking semantics follow TDB rather than MDB,
    1038             :          * and effectively locks all partitions at once.
    1039             :          * Detail:
    1040             :          * Samba AD is special in that the partitions module (this file)
    1041             :          * combines multiple independently locked databases into one overall
    1042             :          * transaction. Changes across multiple partition DBs in a single
    1043             :          * transaction must ALL be either visible or invisible.
    1044             :          * The way this is achieved is by taking out a write lock on
    1045             :          * metadata.tdb at the start of prepare_commit, while unlocking it at
    1046             :          * the end of end_trans. This is matched by read_lock, ensuring it
    1047             :          * can't progress until that write lock is released.
    1048             :          *
    1049             :          * metadata.tdb needs to be a TDB file because MDB uses independent
    1050             :          * locks, which means a read lock and a write lock can be held at the
    1051             :          * same time, whereas in TDB, the two locks block each other. The TDB
    1052             :          * behaviour is required to implement the functionality described
    1053             :          * above.
    1054             :          *
    1055             :          * An important additional detail here is that if prepare_commit is
    1056             :          * called on a TDB without any changes being made, no write lock is
    1057             :          * taken. We address this by storing a sequence number in metadata.tdb
    1058             :          * which is updated every time a replicated attribute is modified.
    1059             :          * The possibility of a few unreplicated attributes being out of date
    1060             :          * turns out not to be a problem.
    1061             :          * For this reason, a lock on sam.ldb (which is a TDB) won't achieve
    1062             :          * the same end as locking metadata.tdb, unless we made a modification
    1063             :          * to the @ records found there before every prepare_commit.
    1064             :          */
    1065      349765 :         ret = partition_metadata_start_trans(module);
    1066      349765 :         if (ret != LDB_SUCCESS) {
    1067           0 :                 return ret;
    1068             :         }
    1069             : 
    1070      349765 :         ret = ldb_next_start_trans(module);
    1071      349765 :         if (ret != LDB_SUCCESS) {
    1072           0 :                 partition_metadata_del_trans(module);
    1073           0 :                 return ret;
    1074             :         }
    1075             : 
    1076      349765 :         ret = partition_reload_if_required(module, data, NULL);
    1077      349765 :         if (ret != LDB_SUCCESS) {
    1078           0 :                 ldb_next_del_trans(module);
    1079           0 :                 partition_metadata_del_trans(module);
    1080           0 :                 return ret;
    1081             :         }
    1082             : 
    1083             :         /*
    1084             :          * The following per partition locks are required mostly because TDB
    1085             :          * and MDB require locks before read and write ops are permitted.
    1086             :          */
    1087     2021630 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
    1088     1671865 :                 if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) {
    1089           0 :                         ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_start_trans() -> %s",
    1090           0 :                                   ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
    1091             :                 }
    1092     1671865 :                 ret = ldb_next_start_trans(data->partitions[i]->module);
    1093     1671865 :                 if (ret != LDB_SUCCESS) {
    1094             :                         /* Back it out, if it fails on one */
    1095           0 :                         for (i--; i >= 0; i--) {
    1096           0 :                                 ldb_next_del_trans(data->partitions[i]->module);
    1097             :                         }
    1098           0 :                         ldb_next_del_trans(module);
    1099           0 :                         partition_metadata_del_trans(module);
    1100           0 :                         return ret;
    1101             :                 }
    1102             :         }
    1103             : 
    1104      349765 :         data->in_transaction++;
    1105             : 
    1106      349765 :         return LDB_SUCCESS;
    1107             : }
    1108             : 
    1109             : /* prepare for a commit */
    1110      303837 : int partition_prepare_commit(struct ldb_module *module)
    1111             : {
    1112        2204 :         unsigned int i;
    1113      303837 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1114             :                                                               struct partition_private_data);
    1115        2204 :         int ret;
    1116             : 
    1117             :         /*
    1118             :          * Order of prepare_commit calls must match that in
    1119             :          * partition_start_trans. See comment in that function for detail.
    1120             :          */
    1121      303837 :         ret = partition_metadata_prepare_commit(module);
    1122      303837 :         if (ret != LDB_SUCCESS) {
    1123           0 :                 return ret;
    1124             :         }
    1125             : 
    1126      303837 :         ret = ldb_next_prepare_commit(module);
    1127      303837 :         if (ret != LDB_SUCCESS) {
    1128           0 :                 return ret;
    1129             :         }
    1130             : 
    1131     1762317 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
    1132     1458480 :                 if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) {
    1133           0 :                         ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_prepare_commit() -> %s",
    1134           0 :                                   ldb_dn_get_linearized(data->partitions[i]->ctrl->dn));
    1135             :                 }
    1136     1458480 :                 ret = ldb_next_prepare_commit(data->partitions[i]->module);
    1137     1458480 :                 if (ret != LDB_SUCCESS) {
    1138           0 :                         ldb_asprintf_errstring(ldb_module_get_ctx(module), "prepare_commit error on %s: %s",
    1139           0 :                                                ldb_dn_get_linearized(data->partitions[i]->ctrl->dn),
    1140             :                                                ldb_errstring(ldb_module_get_ctx(module)));
    1141           0 :                         return ret;
    1142             :                 }
    1143             :         }
    1144             : 
    1145      303837 :         if ((module && ldb_module_flags(ldb_module_get_ctx(module)) & LDB_FLG_ENABLE_TRACING)) {
    1146           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_prepare_commit() -> (metadata partition)");
    1147             :         }
    1148             : 
    1149      301633 :         return LDB_SUCCESS;
    1150             : }
    1151             : 
    1152             : 
    1153             : /* end a transaction */
    1154      304270 : int partition_end_trans(struct ldb_module *module)
    1155             : {
    1156        2204 :         int ret, ret2;
    1157        2204 :         int i;
    1158      304270 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1159      304270 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1160             :                                                               struct partition_private_data);
    1161      304270 :         bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING;
    1162             : 
    1163      304270 :         ret = LDB_SUCCESS;
    1164             : 
    1165      304270 :         if (data->in_transaction == 0) {
    1166           0 :                 DEBUG(0,("partition end transaction mismatch\n"));
    1167           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
    1168             :         } else {
    1169      304270 :                 data->in_transaction--;
    1170             :         }
    1171             : 
    1172             :         /*
    1173             :          * Order of end_trans calls must be the reverse of that in
    1174             :          * partition_start_trans. See comment in that function for detail.
    1175             :          */
    1176      304270 :         if (data && data->partitions) {
    1177             :                 /* Just counting the partitions */
    1178     1764505 :                 for (i=0; data->partitions[i]; i++) {}
    1179             : 
    1180             :                 /* now walk them backwards */
    1181     1764505 :                 for (i--; i>=0; i--) {
    1182     1460645 :                         struct dsdb_partition *p = data->partitions[i];
    1183     1460645 :                         if (trace) {
    1184           0 :                                 ldb_debug(ldb,
    1185             :                                           LDB_DEBUG_TRACE,
    1186             :                                           "partition_end_trans() -> %s",
    1187           0 :                                           ldb_dn_get_linearized(p->ctrl->dn));
    1188             :                         }
    1189     1460645 :                         ret2 = ldb_next_end_trans(p->module);
    1190     1460645 :                         if (ret2 != LDB_SUCCESS) {
    1191           0 :                                 ldb_asprintf_errstring(ldb,
    1192             :                                         "end_trans error on %s: %s",
    1193           0 :                                         ldb_dn_get_linearized(p->ctrl->dn),
    1194             :                                         ldb_errstring(ldb));
    1195           0 :                                 ret = ret2;
    1196             :                         }
    1197             :                 }
    1198             :         }
    1199             : 
    1200      304270 :         if (trace) {
    1201           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_end_trans() -> (metadata partition)");
    1202             :         }
    1203      304270 :         ret2 = ldb_next_end_trans(module);
    1204      304270 :         if (ret2 != LDB_SUCCESS) {
    1205           0 :                 ret = ret2;
    1206             :         }
    1207             : 
    1208      304270 :         ret2 = partition_metadata_end_trans(module);
    1209      304270 :         if (ret2 != LDB_SUCCESS) {
    1210           0 :                 ret = ret2;
    1211             :         }
    1212             : 
    1213      304270 :         return ret;
    1214             : }
    1215             : 
    1216             : /* delete a transaction */
    1217       45493 : int partition_del_trans(struct ldb_module *module)
    1218             : {
    1219       45493 :         int ret, final_ret = LDB_SUCCESS;
    1220           4 :         int i;
    1221       45493 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1222       45493 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1223             :                                                               struct partition_private_data);
    1224       45493 :         bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING;
    1225             : 
    1226       45493 :         if (data == NULL) {
    1227           0 :                 DEBUG(0,("partition delete transaction with no private data\n"));
    1228           0 :                 return ldb_operr(ldb);
    1229             :         }
    1230             : 
    1231             :         /*
    1232             :          * Order of del_trans calls must be the reverse of that in
    1233             :          * partition_start_trans. See comment in that function for detail.
    1234             :          */
    1235       45493 :         if (data->partitions) {
    1236             :                 /* Just counting the partitions */
    1237      257682 :                 for (i=0; data->partitions[i]; i++) {}
    1238             : 
    1239             :                 /* now walk them backwards */
    1240      257682 :                 for (i--; i>=0; i--) {
    1241      212189 :                         struct dsdb_partition *p = data->partitions[i];
    1242      212189 :                         if (trace) {
    1243           0 :                                 ldb_debug(ldb,
    1244             :                                           LDB_DEBUG_TRACE,
    1245             :                                           "partition_del_trans() -> %s",
    1246           0 :                                           ldb_dn_get_linearized(p->ctrl->dn));
    1247             :                         }
    1248      212189 :                         ret = ldb_next_del_trans(p->module);
    1249      212189 :                         if (ret != LDB_SUCCESS) {
    1250           0 :                                 ldb_asprintf_errstring(ldb,
    1251             :                                         "del_trans error on %s: %s",
    1252           0 :                                         ldb_dn_get_linearized(p->ctrl->dn),
    1253             :                                         ldb_errstring(ldb));
    1254           0 :                                 final_ret = ret;
    1255             :                         }
    1256             :                 }
    1257             :         }
    1258             : 
    1259       45493 :         if (trace) {
    1260           0 :                 ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_TRACE, "partition_del_trans() -> (metadata partition)");
    1261             :         }
    1262       45493 :         ret = ldb_next_del_trans(module);
    1263       45493 :         if (ret != LDB_SUCCESS) {
    1264           0 :                 final_ret = ret;
    1265             :         }
    1266             : 
    1267       45493 :         ret = partition_metadata_del_trans(module);
    1268       45493 :         if (ret != LDB_SUCCESS) {
    1269           0 :                 final_ret = ret;
    1270             :         }
    1271             : 
    1272       45493 :         if (data->in_transaction == 0) {
    1273           0 :                 DEBUG(0,("partition del transaction mismatch\n"));
    1274           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    1275             :         }
    1276       45493 :         data->in_transaction--;
    1277             : 
    1278       45493 :         return final_ret;
    1279             : }
    1280             : 
    1281    19379278 : int partition_primary_sequence_number(struct ldb_module *module, TALLOC_CTX *mem_ctx, 
    1282             :                                       uint64_t *seq_number,
    1283             :                                       struct ldb_request *parent)
    1284             : {
    1285     1123789 :         int ret;
    1286     1123789 :         struct ldb_result *res;
    1287     1123789 :         struct ldb_seqnum_request *tseq;
    1288     1123789 :         struct ldb_seqnum_result *seqr;
    1289             : 
    1290    19379278 :         tseq = talloc_zero(mem_ctx, struct ldb_seqnum_request);
    1291    19379278 :         if (tseq == NULL) {
    1292           0 :                 return ldb_oom(ldb_module_get_ctx(module));
    1293             :         }
    1294    19379278 :         tseq->type = LDB_SEQ_HIGHEST_SEQ;
    1295             :         
    1296    19379278 :         ret = dsdb_module_extended(module, tseq, &res,
    1297             :                                    LDB_EXTENDED_SEQUENCE_NUMBER,
    1298             :                                    tseq,
    1299             :                                    DSDB_FLAG_NEXT_MODULE,
    1300             :                                    parent);
    1301    19379278 :         if (ret != LDB_SUCCESS) {
    1302           0 :                 talloc_free(tseq);
    1303           0 :                 return ret;
    1304             :         }
    1305             :         
    1306    19379278 :         seqr = talloc_get_type_abort(res->extended->data,
    1307             :                                      struct ldb_seqnum_result);
    1308    19379278 :         if (seqr->flags & LDB_SEQ_TIMESTAMP_SEQUENCE) {
    1309           0 :                 talloc_free(res);
    1310           0 :                 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
    1311             :                         "Primary backend in partition module returned a timestamp based seq");
    1312             :         }
    1313             : 
    1314    19379278 :         *seq_number = seqr->seq_num;
    1315    19379278 :         talloc_free(tseq);
    1316    19379278 :         return LDB_SUCCESS;
    1317             : }
    1318             : 
    1319             : 
    1320             : /*
    1321             :  * Older version of sequence number as sum of sequence numbers for each partition
    1322             :  */
    1323         213 : int partition_sequence_number_from_partitions(struct ldb_module *module,
    1324             :                                               uint64_t *seqr)
    1325             : {
    1326          29 :         int ret;
    1327          29 :         unsigned int i;
    1328         213 :         uint64_t seq_number = 0;
    1329         213 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1330             :                                                               struct partition_private_data);
    1331             : 
    1332         213 :         ret = partition_primary_sequence_number(module, data, &seq_number, NULL);
    1333         213 :         if (ret != LDB_SUCCESS) {
    1334           0 :                 return ret;
    1335             :         }
    1336             :         
    1337             :         /* Skip the lot if 'data' isn't here yet (initialisation) */
    1338         237 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
    1339          15 :                 struct ldb_seqnum_request *tseq;
    1340          15 :                 struct ldb_seqnum_result *tseqr;
    1341          15 :                 struct ldb_request *treq;
    1342          24 :                 struct ldb_result *res = talloc_zero(data, struct ldb_result);
    1343          24 :                 if (res == NULL) {
    1344           0 :                         return ldb_oom(ldb_module_get_ctx(module));
    1345             :                 }
    1346          24 :                 tseq = talloc_zero(res, struct ldb_seqnum_request);
    1347          24 :                 if (tseq == NULL) {
    1348           0 :                         talloc_free(res);
    1349           0 :                         return ldb_oom(ldb_module_get_ctx(module));
    1350             :                 }
    1351          24 :                 tseq->type = LDB_SEQ_HIGHEST_SEQ;
    1352             :                 
    1353          24 :                 ret = ldb_build_extended_req(&treq, ldb_module_get_ctx(module), res,
    1354             :                                              LDB_EXTENDED_SEQUENCE_NUMBER,
    1355             :                                              tseq,
    1356             :                                              NULL,
    1357             :                                              res,
    1358             :                                              ldb_extended_default_callback,
    1359             :                                              NULL);
    1360          24 :                 LDB_REQ_SET_LOCATION(treq);
    1361          24 :                 if (ret != LDB_SUCCESS) {
    1362           0 :                         talloc_free(res);
    1363           0 :                         return ret;
    1364             :                 }
    1365             :                 
    1366          24 :                 ret = partition_request(data->partitions[i]->module, treq);
    1367          24 :                 if (ret != LDB_SUCCESS) {
    1368           0 :                         talloc_free(res);
    1369           0 :                         return ret;
    1370             :                 }
    1371          24 :                 ret = ldb_wait(treq->handle, LDB_WAIT_ALL);
    1372          24 :                 if (ret != LDB_SUCCESS) {
    1373           0 :                         talloc_free(res);
    1374           0 :                         return ret;
    1375             :                 }
    1376          24 :                 tseqr = talloc_get_type(res->extended->data,
    1377             :                                         struct ldb_seqnum_result);
    1378          24 :                 seq_number += tseqr->seq_num;
    1379          24 :                 talloc_free(res);
    1380             :         }
    1381             : 
    1382         213 :         *seqr = seq_number;
    1383         213 :         return LDB_SUCCESS;
    1384             : }
    1385             : 
    1386             : 
    1387             : /*
    1388             :  * Newer version of sequence number using metadata tdb
    1389             :  */
    1390     1276083 : static int partition_sequence_number(struct ldb_module *module, struct ldb_request *req)
    1391             : {
    1392       95491 :         struct ldb_extended *ext;
    1393       95491 :         struct ldb_seqnum_request *seq;
    1394       95491 :         struct ldb_seqnum_result *seqr;
    1395       95491 :         uint64_t seq_number;
    1396       95491 :         int ret;
    1397             : 
    1398     1276083 :         seq = talloc_get_type_abort(req->op.extended.data, struct ldb_seqnum_request);
    1399     1276083 :         switch (seq->type) {
    1400     1253269 :         case LDB_SEQ_NEXT:
    1401     1253269 :                 ret = partition_metadata_sequence_number_increment(module, &seq_number);
    1402     1253269 :                 if (ret != LDB_SUCCESS) {
    1403           0 :                         return ret;
    1404             :                 }
    1405     1157804 :                 break;
    1406             : 
    1407       22814 :         case LDB_SEQ_HIGHEST_SEQ:
    1408       22814 :                 ret = partition_metadata_sequence_number(module, &seq_number);
    1409       22814 :                 if (ret != LDB_SUCCESS) {
    1410           0 :                         return ret;
    1411             :                 }
    1412       22788 :                 break;
    1413             : 
    1414           0 :         case LDB_SEQ_HIGHEST_TIMESTAMP:
    1415           0 :                 return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
    1416             :                                         "LDB_SEQ_HIGHEST_TIMESTAMP not supported");
    1417             :         }
    1418             : 
    1419     1276083 :         ext = talloc_zero(req, struct ldb_extended);
    1420     1276083 :         if (!ext) {
    1421           0 :                 return ldb_module_oom(module);
    1422             :         }
    1423     1276083 :         seqr = talloc_zero(ext, struct ldb_seqnum_result);
    1424     1276083 :         if (seqr == NULL) {
    1425           0 :                 talloc_free(ext);
    1426           0 :                 return ldb_module_oom(module);
    1427             :         }
    1428     1276083 :         ext->oid = LDB_EXTENDED_SEQUENCE_NUMBER;
    1429     1276083 :         ext->data = seqr;
    1430             : 
    1431     1276083 :         seqr->seq_num = seq_number;
    1432     1276083 :         seqr->flags |= LDB_SEQ_GLOBAL_SEQUENCE;
    1433             : 
    1434             :         /* send request done */
    1435     1276083 :         return ldb_module_done(req, NULL, ext, LDB_SUCCESS);
    1436             : }
    1437             : 
    1438             : /* lock all the backends */
    1439    18846306 : int partition_read_lock(struct ldb_module *module)
    1440             : {
    1441    18846306 :         int i = 0;
    1442    18846306 :         int ret = 0;
    1443    18846306 :         int ret2 = 0;
    1444    18846306 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1445     1115416 :         struct partition_private_data *data = \
    1446    18846306 :                 talloc_get_type(ldb_module_get_private(module),
    1447             :                                 struct partition_private_data);
    1448             : 
    1449    18846306 :         if (ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING) {
    1450           0 :                 ldb_debug(ldb, LDB_DEBUG_TRACE,
    1451             :                           "partition_read_lock() -> (metadata partition)");
    1452             :         }
    1453             : 
    1454             :         /*
    1455             :          * It is important to only do this for LOCK because:
    1456             :          * - we don't want to unlock what we did not lock
    1457             :          *
    1458             :          * - we don't want to make a new lock on the sam.ldb
    1459             :          *   (triggered inside this routine due to the seq num check)
    1460             :          *   during an unlock phase as that will violate the lock
    1461             :          *   ordering
    1462             :          */
    1463             : 
    1464    18846306 :         if (data == NULL) {
    1465      182015 :                 TALLOC_CTX *mem_ctx = talloc_new(module);
    1466             : 
    1467      182015 :                 data = talloc_zero(mem_ctx, struct partition_private_data);
    1468      182015 :                 if (data == NULL) {
    1469           0 :                         talloc_free(mem_ctx);
    1470           0 :                         return ldb_operr(ldb);
    1471             :                 }
    1472             : 
    1473             :                 /*
    1474             :                  * When used from Samba4, this message is set by the
    1475             :                  * samba4 module, as a fixed value not read from the
    1476             :                  * DB.  This avoids listing modules in the DB
    1477             :                  */
    1478      182015 :                 data->forced_module_msg = talloc_get_type(
    1479             :                         ldb_get_opaque(ldb,
    1480             :                                        DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME),
    1481             :                         struct ldb_message);
    1482             : 
    1483      182015 :                 ldb_module_set_private(module, talloc_steal(module,
    1484             :                                                             data));
    1485      182015 :                 talloc_free(mem_ctx);
    1486             :         }
    1487             : 
    1488             :         /*
    1489             :          * This will lock sam.ldb and will also call event loops,
    1490             :          * so we do it before we get the whole db lock.
    1491             :          */
    1492    18846306 :         ret = partition_reload_if_required(module, data, NULL);
    1493    18846306 :         if (ret != LDB_SUCCESS) {
    1494           0 :                 return ret;
    1495             :         }
    1496             : 
    1497             :         /*
    1498             :          * Order of read_lock calls must match that in partition_start_trans.
    1499             :          * See comment in that function for detail.
    1500             :          */
    1501    18846306 :         ret = partition_metadata_read_lock(module);
    1502    18846306 :         if (ret != LDB_SUCCESS) {
    1503           0 :                 goto failed;
    1504             :         }
    1505             : 
    1506             :         /*
    1507             :          * The top level DB (sam.ldb) lock is not enough to block another
    1508             :          * process in prepare_commit(), because if nothing was changed in the
    1509             :          * specific backend, then prepare_commit() is a no-op. Therefore the
    1510             :          * metadata.tdb lock is taken out above, as it is the best we can do
    1511             :          * right now.
    1512             :          */
    1513    18846306 :         ret = ldb_next_read_lock(module);
    1514    18846306 :         if (ret != LDB_SUCCESS) {
    1515           0 :                 ldb_debug_set(ldb,
    1516             :                               LDB_DEBUG_FATAL,
    1517             :                               "Failed to lock db: %s / %s for metadata partition",
    1518             :                               ldb_errstring(ldb),
    1519             :                               ldb_strerror(ret));
    1520             : 
    1521           0 :                 return ret;
    1522             :         }
    1523             : 
    1524             :         /*
    1525             :          * The following per partition locks are required mostly because TDB
    1526             :          * and MDB require locks before reads are permitted.
    1527             :          */
    1528   105848941 :         for (i=0; data && data->partitions && data->partitions[i]; i++) {
    1529    87002635 :                 if ((module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING)) {
    1530           0 :                         ldb_debug(ldb, LDB_DEBUG_TRACE,
    1531             :                                   "partition_read_lock() -> %s",
    1532             :                                   ldb_dn_get_linearized(
    1533           0 :                                           data->partitions[i]->ctrl->dn));
    1534             :                 }
    1535    87002635 :                 ret = ldb_next_read_lock(data->partitions[i]->module);
    1536    87002635 :                 if (ret == LDB_SUCCESS) {
    1537    87002635 :                         continue;
    1538             :                 }
    1539             : 
    1540           0 :                 ldb_debug_set(ldb,
    1541             :                               LDB_DEBUG_FATAL,
    1542             :                               "Failed to lock db: %s / %s for %s",
    1543             :                               ldb_errstring(ldb),
    1544             :                               ldb_strerror(ret),
    1545             :                               ldb_dn_get_linearized(
    1546           0 :                                       data->partitions[i]->ctrl->dn));
    1547             : 
    1548           0 :                 goto failed;
    1549             :         }
    1550             : 
    1551    17730890 :         return LDB_SUCCESS;
    1552             : 
    1553           0 : failed:
    1554             :         /* Back it out, if it fails on one */
    1555           0 :         for (i--; i >= 0; i--) {
    1556           0 :                 ret2 = ldb_next_read_unlock(data->partitions[i]->module);
    1557           0 :                 if (ret2 != LDB_SUCCESS) {
    1558           0 :                         ldb_debug(ldb,
    1559             :                                   LDB_DEBUG_FATAL,
    1560             :                                   "Failed to unlock db: %s / %s",
    1561             :                                   ldb_errstring(ldb),
    1562             :                                   ldb_strerror(ret2));
    1563             :                 }
    1564             :         }
    1565           0 :         ret2 = ldb_next_read_unlock(module);
    1566           0 :         if (ret2 != LDB_SUCCESS) {
    1567           0 :                 ldb_debug(ldb,
    1568             :                           LDB_DEBUG_FATAL,
    1569             :                           "Failed to unlock db: %s / %s",
    1570             :                           ldb_errstring(ldb),
    1571             :                           ldb_strerror(ret2));
    1572             :         }
    1573           0 :         return ret;
    1574             : }
    1575             : 
    1576             : /* unlock all the backends */
    1577    18846306 : int partition_read_unlock(struct ldb_module *module)
    1578             : {
    1579     1115416 :         int i;
    1580    18846306 :         int ret = LDB_SUCCESS;
    1581     1115416 :         int ret2;
    1582    18846306 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    1583     1115416 :         struct partition_private_data *data = \
    1584    18846306 :                 talloc_get_type(ldb_module_get_private(module),
    1585             :                                 struct partition_private_data);
    1586    18846306 :         bool trace = module && ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING;
    1587             : 
    1588             :         /*
    1589             :          * Order of read_unlock calls must be the reverse of that in
    1590             :          * partition_start_trans. See comment in that function for detail.
    1591             :          */
    1592    18846306 :         if (data && data->partitions) {
    1593             :                 /* Just counting the partitions */
    1594   105665176 :                 for (i=0; data->partitions[i]; i++) {}
    1595             : 
    1596             :                 /* now walk them backwards */
    1597   105665176 :                 for (i--; i>=0; i--) {
    1598    87002635 :                         struct dsdb_partition *p = data->partitions[i];
    1599    87002635 :                         if (trace) {
    1600           0 :                                 ldb_debug(ldb, LDB_DEBUG_TRACE,
    1601             :                                           "partition_read_unlock() -> %s",
    1602           0 :                                           ldb_dn_get_linearized(p->ctrl->dn));
    1603             :                         }
    1604    87002635 :                         ret2 = ldb_next_read_unlock(p->module);
    1605    87002635 :                         if (ret2 != LDB_SUCCESS) {
    1606           0 :                                 ldb_debug_set(ldb,
    1607             :                                            LDB_DEBUG_FATAL,
    1608             :                                            "Failed to lock db: %s / %s for %s",
    1609             :                                            ldb_errstring(ldb),
    1610             :                                            ldb_strerror(ret2),
    1611           0 :                                            ldb_dn_get_linearized(p->ctrl->dn));
    1612             : 
    1613             :                                 /*
    1614             :                                  * Don't overwrite the original failure code
    1615             :                                  * if there was one
    1616             :                                  */
    1617           0 :                                 if (ret == LDB_SUCCESS) {
    1618           0 :                                         ret = ret2;
    1619             :                                 }
    1620             :                         }
    1621             :                 }
    1622             :         }
    1623             : 
    1624    18846306 :         if (trace) {
    1625           0 :                 ldb_debug(ldb, LDB_DEBUG_TRACE,
    1626             :                           "partition_read_unlock() -> (metadata partition)");
    1627             :         }
    1628             : 
    1629    18846306 :         ret2 = ldb_next_read_unlock(module);
    1630    18846306 :         if (ret2 != LDB_SUCCESS) {
    1631           0 :                 ldb_debug_set(ldb,
    1632             :                               LDB_DEBUG_FATAL,
    1633             :                               "Failed to unlock db: %s / %s for metadata partition",
    1634             :                               ldb_errstring(ldb),
    1635             :                               ldb_strerror(ret2));
    1636             : 
    1637             :                 /*
    1638             :                  * Don't overwrite the original failure code
    1639             :                  * if there was one
    1640             :                  */
    1641           0 :                 if (ret == LDB_SUCCESS) {
    1642           0 :                         ret = ret2;
    1643             :                 }
    1644             :         }
    1645             : 
    1646    18846306 :         ret2 = partition_metadata_read_unlock(module);
    1647             : 
    1648             :         /*
    1649             :          * Don't overwrite the original failure code
    1650             :          * if there was one
    1651             :          */
    1652    18846306 :         if (ret == LDB_SUCCESS) {
    1653    18846306 :                 ret = ret2;
    1654             :         }
    1655             : 
    1656    18846306 :         return ret;
    1657             : }
    1658             : 
    1659             : /* extended */
    1660     1279807 : static int partition_extended(struct ldb_module *module, struct ldb_request *req)
    1661             : {
    1662     1279807 :         struct partition_private_data *data = talloc_get_type(ldb_module_get_private(module),
    1663             :                                                               struct partition_private_data);
    1664       95646 :         struct partition_context *ac;
    1665       95646 :         int ret;
    1666             : 
    1667             :         /* if we aren't initialised yet go further */
    1668     1279807 :         if (!data) {
    1669           0 :                 return ldb_next_request(module, req);
    1670             :         }
    1671             : 
    1672     1279807 :         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID) == 0) {
    1673             :                 /* Update the metadata.tdb to increment the schema version if needed*/
    1674        2745 :                 DEBUG(10, ("Incrementing the sequence_number after schema_update_now\n"));
    1675        2745 :                 ret = partition_metadata_inc_schema_sequence(module);
    1676        2745 :                 return ldb_module_done(req, NULL, NULL, ret);
    1677             :         }
    1678             :         
    1679     1277062 :         if (strcmp(req->op.extended.oid, LDB_EXTENDED_SEQUENCE_NUMBER) == 0) {
    1680     1276083 :                 return partition_sequence_number(module, req);
    1681             :         }
    1682             : 
    1683         979 :         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_PARTITION_OID) == 0) {
    1684         979 :                 return partition_create(module, req);
    1685             :         }
    1686             : 
    1687             :         /* 
    1688             :          * as the extended operation has no dn
    1689             :          * we need to send it to all partitions
    1690             :          */
    1691             : 
    1692           0 :         ac = partition_init_ctx(module, req);
    1693           0 :         if (!ac) {
    1694           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    1695             :         }
    1696             : 
    1697           0 :         return partition_send_all(module, ac, req);
    1698             : }
    1699             : 
    1700             : static const struct ldb_module_ops ldb_partition_module_ops = {
    1701             :         .name              = "partition",
    1702             :         .init_context      = partition_init,
    1703             :         .search            = partition_search,
    1704             :         .add               = partition_add,
    1705             :         .modify            = partition_modify,
    1706             :         .del               = partition_delete,
    1707             :         .rename            = partition_rename,
    1708             :         .extended          = partition_extended,
    1709             :         .start_transaction = partition_start_trans,
    1710             :         .prepare_commit    = partition_prepare_commit,
    1711             :         .end_transaction   = partition_end_trans,
    1712             :         .del_transaction   = partition_del_trans,
    1713             :         .read_lock         = partition_read_lock,
    1714             :         .read_unlock       = partition_read_unlock
    1715             : };
    1716             : 
    1717        6040 : int ldb_partition_module_init(const char *version)
    1718             : {
    1719        6040 :         LDB_MODULE_CHECK_VERSION(version);
    1720        6040 :         return ldb_register_module(&ldb_partition_module_ops);
    1721             : }

Generated by: LCOV version 1.14