LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - partition_init.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 270 417 64.7 %
Date: 2021-09-23 10:06:22 Functions: 15 15 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             : #include "lib/util/tsort.h"
      34             : #include "lib/ldb-samba/ldb_wrap.h"
      35             : #include "system/filesys.h"
      36             : 
      37     2074575 : static int partition_sort_compare(const void *v1, const void *v2)
      38             : {
      39             :         const struct dsdb_partition *p1;
      40             :         const struct dsdb_partition *p2;
      41             : 
      42     2093300 :         p1 = *((struct dsdb_partition * const*)v1);
      43     2093300 :         p2 = *((struct dsdb_partition * const*)v2);
      44             : 
      45     2093300 :         return ldb_dn_compare(p1->ctrl->dn, p2->ctrl->dn);
      46             : }
      47             : 
      48             : /* Load the list of DNs that we must replicate to all partitions */
      49      134604 : static int partition_load_replicate_dns(struct ldb_context *ldb,
      50             :                                         struct partition_private_data *data,
      51             :                                         struct ldb_message *msg)
      52             : {
      53      134604 :         struct ldb_message_element *replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
      54             : 
      55      134604 :         talloc_free(data->replicate);
      56      134604 :         if (!replicate_attributes) {
      57           0 :                 data->replicate = NULL;
      58             :         } else {
      59             :                 unsigned int i;
      60      134604 :                 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
      61      134604 :                 if (!data->replicate) {
      62           0 :                         return ldb_oom(ldb);
      63             :                 }
      64             : 
      65      533441 :                 for (i=0; i < replicate_attributes->num_values; i++) {
      66      403796 :                         data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb, &replicate_attributes->values[i]);
      67      403796 :                         if (!ldb_dn_validate(data->replicate[i])) {
      68           0 :                                 ldb_asprintf_errstring(ldb,
      69             :                                                         "partition_init: "
      70             :                                                         "invalid DN in partition replicate record: %s", 
      71           0 :                                                         replicate_attributes->values[i].data);
      72           0 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
      73             :                         }
      74             :                 }
      75      134604 :                 data->replicate[i] = NULL;
      76             :         }
      77      129645 :         return LDB_SUCCESS;
      78             : }
      79             : 
      80             : /* Load the list of modules for the partitions */
      81      134604 : static int partition_load_modules(struct ldb_context *ldb, 
      82             :                                   struct partition_private_data *data, struct ldb_message *msg) 
      83             : {
      84             :         unsigned int i;
      85      134604 :         struct ldb_message_element *modules_attributes = ldb_msg_find_element(msg, "modules");
      86      134604 :         talloc_free(data->modules);
      87      134604 :         if (!modules_attributes) {
      88           0 :                 return LDB_SUCCESS;
      89             :         }
      90             :         
      91      134604 :         data->modules = talloc_array(data, struct partition_module *, modules_attributes->num_values + 1);
      92      134604 :         if (!data->modules) {
      93           0 :                 return ldb_oom(ldb);
      94             :         }
      95             :         
      96      681592 :         for (i=0; i < modules_attributes->num_values; i++) {
      97             :                 char *p;
      98             :                 DATA_BLOB dn_blob;
      99      269192 :                 data->modules[i] = talloc(data->modules, struct partition_module);
     100      269192 :                 if (!data->modules[i]) {
     101           0 :                         return ldb_oom(ldb);
     102             :                 }
     103             : 
     104      269192 :                 dn_blob = modules_attributes->values[i];
     105             : 
     106      269192 :                 p = strchr((const char *)dn_blob.data, ':');
     107      269192 :                 if (!p) {
     108           0 :                         ldb_asprintf_errstring(ldb, 
     109             :                                                "partition_load_modules: "
     110           0 :                                                "invalid form for partition module record (missing ':'): %s", (const char *)dn_blob.data);
     111           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     112             :                 }
     113             :                 /* Now trim off the filename */
     114      269192 :                 dn_blob.length = ((uint8_t *)p - dn_blob.data);
     115             : 
     116      269192 :                 p++;
     117      269192 :                 data->modules[i]->modules = ldb_modules_list_from_string(ldb, data->modules[i],
     118             :                                                                          p);
     119             :                 
     120      269192 :                 if (dn_blob.length == 1 && dn_blob.data[0] == '*') {
     121      134604 :                         data->modules[i]->dn = NULL;
     122             :                 } else {
     123      134588 :                         data->modules[i]->dn = ldb_dn_from_ldb_val(data->modules[i], ldb, &dn_blob);
     124      134588 :                         if (!data->modules[i]->dn || !ldb_dn_validate(data->modules[i]->dn)) {
     125           0 :                                 return ldb_operr(ldb);
     126             :                         }
     127             :                 }
     128             :         }
     129      134604 :         data->modules[i] = NULL;
     130      134604 :         return LDB_SUCCESS;
     131             : }
     132             : 
     133      134604 : static int partition_reload_metadata(struct ldb_module *module, struct partition_private_data *data,
     134             :                                      TALLOC_CTX *mem_ctx, struct ldb_message **_msg,
     135             :                                      struct ldb_request *parent)
     136             : {
     137             :         int ret;
     138             :         struct ldb_message *msg, *module_msg;
     139             :         struct ldb_result *res;
     140      134604 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     141      134604 :         const char *attrs[] = { "partition", "replicateEntries", "modules",
     142             :                                 "partialReplica", "backendStore", NULL };
     143             :         /* perform search for @PARTITION, looking for module, replicateEntries and ldapBackend */
     144      134604 :         ret = dsdb_module_search_dn(module, mem_ctx, &res, 
     145             :                                     ldb_dn_new(mem_ctx, ldb, DSDB_PARTITION_DN),
     146             :                                     attrs,
     147             :                                     DSDB_FLAG_NEXT_MODULE, parent);
     148      134604 :         if (ret != LDB_SUCCESS) {
     149           0 :                 return ret;
     150             :         }
     151             : 
     152      134604 :         msg = res->msgs[0];
     153             : 
     154      134604 :         ret = partition_load_replicate_dns(ldb, data, msg);
     155      134604 :         if (ret != LDB_SUCCESS) {
     156           0 :                 return ret;
     157             :         }
     158             : 
     159             :         /* When used from Samba4, this message is set by the samba4
     160             :          * module, as a fixed value not read from the DB.  This avoids
     161             :          * listing modules in the DB */
     162      134604 :         if (data->forced_module_msg) {
     163      134588 :                 module_msg = data->forced_module_msg;
     164             :         } else {
     165           0 :                 module_msg = msg;
     166             :         }
     167             : 
     168      134604 :         ret = partition_load_modules(ldb, data, module_msg);
     169      134604 :         if (ret != LDB_SUCCESS) {
     170           0 :                 return ret;
     171             :         }
     172             : 
     173      134604 :         if (_msg) {
     174      134604 :                 *_msg = msg;
     175             :         } else {
     176           0 :                 talloc_free(msg);
     177             :         }
     178             : 
     179      129645 :         return LDB_SUCCESS;
     180             : }
     181             : 
     182      635063 : static const char **find_modules_for_dn(struct partition_private_data *data, struct ldb_dn *dn) 
     183             : {
     184             :         unsigned int i;
     185      635063 :         struct partition_module *default_mod = NULL;
     186     1640265 :         for (i=0; data->modules && data->modules[i]; i++) {
     187     1137653 :                 if (!data->modules[i]->dn) {
     188      483876 :                         default_mod = data->modules[i];
     189      635041 :                 } else if (ldb_dn_compare(dn, data->modules[i]->dn) == 0) {
     190      132451 :                         return data->modules[i]->modules;
     191             :                 }
     192             :         }
     193      502612 :         if (default_mod) {
     194      502612 :                 return default_mod->modules;
     195             :         } else {
     196           0 :                 return NULL;
     197             :         }
     198             : }
     199             : 
     200      635063 : static int new_partition_from_dn(struct ldb_context *ldb, struct partition_private_data *data, 
     201             :                                  TALLOC_CTX *mem_ctx, 
     202             :                                  struct ldb_dn *dn, const char *filename,
     203             :                                  const char *backend_db_store,
     204             :                                  struct dsdb_partition **partition) {
     205             :         struct dsdb_control_current_partition *ctrl;
     206             :         struct ldb_module *backend_module;
     207             :         char *backend_path;
     208             :         struct ldb_module *module_chain;
     209             :         const char **modules;
     210      635063 :         const char **options = NULL;
     211             :         int ret;
     212             : 
     213      635063 :         (*partition) = talloc_zero(mem_ctx, struct dsdb_partition);
     214      635063 :         if (!*partition) {
     215           0 :                 return ldb_oom(ldb);
     216             :         }
     217             : 
     218      635063 :         (*partition)->ctrl = ctrl = talloc((*partition), struct dsdb_control_current_partition);
     219      635063 :         if (!ctrl) {
     220           0 :                 talloc_free(*partition);
     221           0 :                 return ldb_oom(ldb);
     222             :         }
     223             : 
     224             :         /* the backend LDB is the DN (base64 encoded if not 'plain') followed by .ldb */
     225      635063 :         backend_path = ldb_relative_path(ldb,
     226             :                                          *partition,
     227             :                                          filename);
     228      635063 :         if (!backend_path) {
     229           0 :                 ldb_asprintf_errstring(ldb,
     230             :                                        "partition_init: unable to determine an relative path for partition: %s",
     231             :                                        filename);
     232           0 :                 talloc_free(*partition);
     233           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     234             :         }
     235      635063 :         (*partition)->backend_url = talloc_asprintf(*partition, "%s://%s",
     236             :                                                     backend_db_store,
     237             :                                                     backend_path);
     238             : 
     239      635063 :         if (!(ldb_module_flags(ldb) & LDB_FLG_RDONLY)) {
     240             :                 char *p;
     241             :                 char *backend_dir;
     242             : 
     243      635033 :                 p = strrchr(backend_path, '/');
     244      635033 :                 if (p) {
     245      635033 :                         p[0] = '\0';
     246             :                 }
     247      635033 :                 backend_dir = backend_path;
     248             : 
     249             :                 /* Failure is quite reasonable, it might alredy exist */
     250      635033 :                 mkdir(backend_dir, 0700);
     251             :         }
     252             : 
     253      635063 :         ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
     254      635063 :         ctrl->dn = talloc_steal(ctrl, dn);
     255             :         
     256      635063 :         options = ldb_options_get(ldb);
     257      635063 :         ret = ldb_module_connect_backend(
     258      635063 :             ldb, (*partition)->backend_url, options, &backend_module);
     259      635063 :         if (ret != LDB_SUCCESS) {
     260           0 :                 return ret;
     261             :         }
     262      635063 :         talloc_steal((*partition), backend_module);
     263             : 
     264      635063 :         modules = find_modules_for_dn(data, dn);
     265             : 
     266      635063 :         if (!modules) {
     267           0 :                 DEBUG(0, ("Unable to load partition modules for new DN %s, perhaps you need to reprovision?  See partition-upgrade.txt for instructions\n", ldb_dn_get_linearized(dn)));
     268           0 :                 talloc_free(*partition);
     269           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     270             :         }
     271      635063 :         ret = ldb_module_load_list(ldb, modules, backend_module, &module_chain);
     272      635063 :         if (ret != LDB_SUCCESS) {
     273           0 :                 ldb_asprintf_errstring(ldb, 
     274             :                                        "partition_init: "
     275             :                                        "loading backend for %s failed: %s", 
     276             :                                        ldb_dn_get_linearized(dn), ldb_errstring(ldb));
     277           0 :                 talloc_free(*partition);
     278           0 :                 return ret;
     279             :         }
     280      635063 :         ret = ldb_module_init_chain(ldb, module_chain);
     281      635063 :         if (ret != LDB_SUCCESS) {
     282           0 :                 ldb_asprintf_errstring(ldb,
     283             :                                        "partition_init: "
     284             :                                        "initialising backend for %s failed: %s", 
     285             :                                        ldb_dn_get_linearized(dn), ldb_errstring(ldb));
     286           0 :                 talloc_free(*partition);
     287           0 :                 return ret;
     288             :         }
     289             : 
     290             :         /* This weirdness allows us to use ldb_next_request() in partition.c */
     291      635063 :         (*partition)->module = ldb_module_new(*partition, ldb, "partition_next", NULL);
     292      635063 :         if (!(*partition)->module) {
     293           0 :                 talloc_free(*partition);
     294           0 :                 return ldb_oom(ldb);
     295             :         }
     296      635063 :         ldb_module_set_next((*partition)->module, talloc_steal((*partition)->module, module_chain));
     297             : 
     298             :         /* if we were in a transaction then we need to start a
     299             :            transaction on this new partition, otherwise we'll get a
     300             :            transaction mismatch when we end the transaction */
     301      635063 :         if (data->in_transaction) {
     302         919 :                 if (ldb_module_flags(ldb) & LDB_FLG_ENABLE_TRACING) {
     303           0 :                         ldb_debug(ldb, LDB_DEBUG_TRACE, "partition_start_trans() -> %s (new partition)", 
     304           0 :                                   ldb_dn_get_linearized((*partition)->ctrl->dn));
     305             :                 }
     306         919 :                 ret = ldb_next_start_trans((*partition)->module);
     307             :         }
     308             : 
     309      611587 :         return ret;
     310             : }
     311             : 
     312             : /* Tell the rootDSE about the new partition */
     313      635063 : static int partition_register(struct ldb_context *ldb, struct dsdb_control_current_partition *ctrl) 
     314             : {
     315             :         struct ldb_request *req;
     316             :         int ret;
     317             : 
     318      635063 :         req = talloc_zero(NULL, struct ldb_request);
     319      635063 :         if (req == NULL) {
     320           0 :                 return ldb_oom(ldb);
     321             :         }
     322             :                 
     323      635063 :         req->operation = LDB_REQ_REGISTER_PARTITION;
     324      635063 :         req->op.reg_partition.dn = ctrl->dn;
     325      635063 :         req->callback = ldb_op_default_callback;
     326             : 
     327      635063 :         ldb_set_timeout(ldb, req, 0);
     328             :         
     329      635063 :         req->handle = ldb_handle_new(req, ldb);
     330      635063 :         if (req->handle == NULL) {
     331           0 :                 talloc_free(req);
     332           0 :                 return ldb_operr(ldb);
     333             :         }
     334             :         
     335      635063 :         ret = ldb_request(ldb, req);
     336      635063 :         if (ret == LDB_SUCCESS) {
     337      635063 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     338             :         }
     339      635063 :         if (ret != LDB_SUCCESS) {
     340           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR, "partition: Unable to register partition with rootdse!\n");
     341           0 :                 talloc_free(req);
     342           0 :                 return LDB_ERR_OTHER;
     343             :         }
     344      635063 :         talloc_free(req);
     345             : 
     346      611587 :         return LDB_SUCCESS;
     347             : }
     348             : 
     349             : /* Add a newly found partition to the global data */
     350      635063 : static int add_partition_to_data(struct ldb_context *ldb, struct partition_private_data *data,
     351             :                                  struct dsdb_partition *partition)
     352             : {
     353             :         unsigned int i;
     354             :         int ret;
     355             : 
     356             :         /* Count the partitions */
     357      991673 :         for (i=0; data->partitions && data->partitions[i]; i++) { /* noop */};
     358             :         
     359             :         /* Add partition to list of partitions */
     360      635063 :         data->partitions = talloc_realloc(data, data->partitions, struct dsdb_partition *, i + 2);
     361      635063 :         if (!data->partitions) {
     362           0 :                 return ldb_oom(ldb);
     363             :         }
     364      635063 :         data->partitions[i] = talloc_steal(data->partitions, partition);
     365      635063 :         data->partitions[i+1] = NULL;
     366             :         
     367             :         /* Sort again (should use binary insert) */
     368      635063 :         TYPESAFE_QSORT(data->partitions, i+1, partition_sort_compare);
     369             :         
     370      635063 :         ret = partition_register(ldb, partition->ctrl);
     371      635063 :         if (ret != LDB_SUCCESS) {
     372           0 :                 return ret;
     373             :         }
     374      635063 :         return LDB_SUCCESS;
     375             : }
     376             : 
     377    13931396 : int partition_reload_if_required(struct ldb_module *module, 
     378             :                                  struct partition_private_data *data,
     379             :                                  struct ldb_request *parent)
     380             : {
     381             :         uint64_t seq;
     382             :         int ret;
     383             :         unsigned int i;
     384    13931396 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     385             :         struct ldb_message *msg;
     386             :         struct ldb_message_element *partition_attributes;
     387             :         struct ldb_message_element *partial_replicas;
     388             :         TALLOC_CTX *mem_ctx;
     389             : 
     390    13931396 :         if (!data) {
     391             :                 /* Not initialised yet */
     392           0 :                 return LDB_SUCCESS;
     393             :         }
     394             : 
     395    13931396 :         mem_ctx = talloc_new(data);
     396    13931396 :         if (!mem_ctx) {
     397           0 :                 return ldb_oom(ldb);
     398             :         }
     399             : 
     400    13931396 :         ret = partition_primary_sequence_number(module, mem_ctx, &seq, parent);
     401    13931396 :         if (ret != LDB_SUCCESS) {
     402           0 :                 talloc_free(mem_ctx);
     403           0 :                 return ret;
     404             :         }
     405    13931396 :         if (seq == data->metadata_seq) {
     406    13796792 :                 talloc_free(mem_ctx);
     407    13796792 :                 return LDB_SUCCESS;
     408             :         }
     409             : 
     410             :         /* This loads metadata tdb. If it's missing, creates it */
     411      134604 :         ret = partition_metadata_init(module);
     412      134604 :         if (ret != LDB_SUCCESS) {
     413           0 :                 return ret;
     414             :         }
     415             : 
     416      134604 :         ret = partition_reload_metadata(module, data, mem_ctx, &msg, parent);
     417      134604 :         if (ret != LDB_SUCCESS) {
     418           0 :                 talloc_free(mem_ctx);
     419           0 :                 return ret;
     420             :         }
     421             : 
     422      134604 :         data->metadata_seq = seq;
     423             : 
     424      134604 :         partition_attributes = ldb_msg_find_element(msg, "partition");
     425      134604 :         partial_replicas     = ldb_msg_find_element(msg, "partialReplica");
     426             :         data->backend_db_store
     427      134604 :                 = talloc_strdup(data, ldb_msg_find_attr_as_string(msg, "backendStore", "tdb"));
     428             : 
     429      134604 :         if (data->backend_db_store == NULL) {
     430           0 :                 talloc_free(mem_ctx);
     431           0 :                 return ldb_module_oom(module);
     432             :         }
     433             : 
     434      770384 :         for (i=0; partition_attributes && i < partition_attributes->num_values; i++) {
     435             :                 unsigned int j;
     436      640739 :                 bool new_partition = true;
     437      640739 :                 const char *filename = NULL;
     438             :                 DATA_BLOB dn_blob;
     439             :                 struct ldb_dn *dn;
     440             :                 struct dsdb_partition *partition;
     441             :                 struct ldb_result *dn_res;
     442      640739 :                 const char *no_attrs[] = { NULL };
     443             : 
     444     1879244 :                 for (j=0; data->partitions && data->partitions[j]; j++) {
     445     1245100 :                         if (data_blob_cmp(&data->partitions[j]->orig_record, &partition_attributes->values[i]) == 0) {
     446        6007 :                                 new_partition = false;
     447        6007 :                                 break;
     448             :                         }
     449             :                 }
     450      640739 :                 if (new_partition == false) {
     451       12278 :                         continue;
     452             :                 }
     453             : 
     454      634144 :                 dn_blob = partition_attributes->values[i];
     455             :                 
     456     1080766 :                 if (dn_blob.length > 4 && 
     457      634144 :                     (strncmp((const char *)&dn_blob.data[dn_blob.length-4], ".ldb", 4) == 0)) {
     458             : 
     459             :                         /* Look for DN:filename.ldb */
     460      634122 :                         char *p = strrchr((const char *)dn_blob.data, ':');
     461      634122 :                         if (!p) {
     462           0 :                                 ldb_asprintf_errstring(ldb, 
     463           0 :                                                        "partition_init: invalid DN in attempting to parse partition record: %s", (const char *)dn_blob.data);
     464           0 :                                 talloc_free(mem_ctx);
     465           0 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
     466             :                         }
     467      634122 :                         filename = p+1;
     468             :                         
     469             :                         /* Now trim off the filename */
     470      634122 :                         dn_blob.length = ((uint8_t *)p - dn_blob.data);
     471             :                 }
     472             : 
     473      634144 :                 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &dn_blob);
     474      634144 :                 if (!dn) {
     475           0 :                         ldb_asprintf_errstring(ldb, 
     476           0 :                                                "partition_init: invalid DN in partition record: %s", (const char *)dn_blob.data);
     477           0 :                         talloc_free(mem_ctx);
     478           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     479             :                 }
     480             :                 
     481             :                 /* Now do a slow check with the DN compare */
     482     1838257 :                 for (j=0; data->partitions && data->partitions[j]; j++) {
     483     1227486 :                         if (ldb_dn_compare(dn, data->partitions[j]->ctrl->dn) == 0) {
     484           0 :                                 new_partition = false;
     485           0 :                                 break;
     486             :                         }
     487             :                 }
     488      634144 :                 if (new_partition == false) {
     489           0 :                         continue;
     490             :                 }
     491             : 
     492      634144 :                 if (!filename) {
     493          22 :                         char *base64_dn = NULL;
     494             :                         const char *p;
     495         341 :                         for (p = ldb_dn_get_linearized(dn); *p; p++) {
     496             :                                 /* We have such a strict check because I don't want shell metacharacters in the file name, nor ../ */
     497         319 :                                 if (!(isalnum(*p) || *p == ' ' || *p == '=' || *p == ',')) {
     498           0 :                                         break;
     499             :                                 }
     500             :                         }
     501          22 :                         if (*p) {
     502           0 :                                 base64_dn = ldb_base64_encode(data, ldb_dn_get_linearized(dn), strlen(ldb_dn_get_linearized(dn)));
     503           0 :                                 filename = talloc_asprintf(mem_ctx, "%s.ldb", base64_dn);
     504             :                         } else {
     505          22 :                                 filename = talloc_asprintf(mem_ctx, "%s.ldb", ldb_dn_get_linearized(dn));
     506             :                         }
     507             :                 }
     508             :                         
     509             :                 /* We call ldb_dn_get_linearized() because the DN in
     510             :                  * partition_attributes is already casefolded
     511             :                  * correctly.  We don't want to mess that up as the
     512             :                  * schema isn't loaded yet */
     513      634144 :                 ret = new_partition_from_dn(ldb, data, data->partitions, dn, 
     514             :                                             filename, data->backend_db_store,
     515             :                                             &partition);
     516      634144 :                 if (ret != LDB_SUCCESS) {
     517           0 :                         talloc_free(mem_ctx);
     518           0 :                         return ret;
     519             :                 }
     520             : 
     521      634144 :                 talloc_steal(partition, partition_attributes->values[i].data);
     522      634144 :                 partition->orig_record = partition_attributes->values[i];
     523             : 
     524             :                 /* Get the 'correct' case of the partition DNs from the database */
     525      634144 :                 ret = dsdb_module_search_dn(partition->module, data, &dn_res, 
     526             :                                             dn, no_attrs,
     527             :                                             DSDB_FLAG_NEXT_MODULE, parent);
     528      634144 :                 if (ret == LDB_SUCCESS) {
     529      634122 :                         talloc_free(partition->ctrl->dn);
     530      634122 :                         partition->ctrl->dn = talloc_steal(partition->ctrl, dn_res->msgs[0]->dn);
     531      634122 :                         talloc_free(dn_res);
     532          22 :                 } else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
     533           0 :                         ldb_asprintf_errstring(ldb,
     534             :                                                "Failed to search for partition base %s in new partition at %s: %s", 
     535             :                                                ldb_dn_get_linearized(dn), 
     536           0 :                                                partition->backend_url, 
     537             :                                                ldb_errstring(ldb));
     538           0 :                         talloc_free(mem_ctx);
     539           0 :                         return ret;
     540             :                 }
     541             : 
     542             :                 /* see if it is a partial replica */
     543      610771 :                 for (j=0; partial_replicas && j<partial_replicas->num_values; j++) {
     544           0 :                         struct ldb_dn *pa_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &partial_replicas->values[j]);
     545           0 :                         if (pa_dn != NULL && ldb_dn_compare(pa_dn, partition->ctrl->dn) == 0) {
     546           0 :                                 partition->partial_replica = true;
     547             :                         }
     548           0 :                         talloc_free(pa_dn);
     549             :                 }
     550             : 
     551      634144 :                 ret = add_partition_to_data(ldb, data, partition);
     552      634144 :                 if (ret != LDB_SUCCESS) {
     553           0 :                         talloc_free(mem_ctx);
     554           0 :                         return ret;
     555             :                 }
     556             :         }
     557             : 
     558      134604 :         talloc_free(mem_ctx);
     559      134604 :         return LDB_SUCCESS;
     560             : }
     561             : 
     562             : /* Copy the metadata (@OPTIONS etc) for the new partition into the partition */
     563             : 
     564         919 : static int new_partition_set_replicated_metadata(struct ldb_context *ldb, 
     565             :                                                  struct ldb_module *module, struct ldb_request *last_req, 
     566             :                                                  struct partition_private_data *data, 
     567             :                                                  struct dsdb_partition *partition)
     568             : {
     569             :         unsigned int i;
     570             :         int ret;
     571             :         /* for each replicate, copy from main partition.  If we get an error, we report it up the chain */
     572        3676 :         for (i=0; data->replicate && data->replicate[i]; i++) {
     573             :                 struct ldb_result *replicate_res;
     574             :                 struct ldb_request *add_req;
     575        2757 :                 ret = dsdb_module_search_dn(module, last_req, &replicate_res, 
     576        2448 :                                             data->replicate[i],
     577             :                                             NULL,
     578             :                                             DSDB_FLAG_NEXT_MODULE, NULL);
     579        2757 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     580           0 :                         continue;
     581             :                 }
     582        2757 :                 if (ret != LDB_SUCCESS) {
     583           0 :                         ldb_asprintf_errstring(ldb,
     584             :                                                "Failed to search for %s from " DSDB_PARTITION_DN 
     585             :                                                " replicateEntries for new partition at %s on %s: %s", 
     586           0 :                                                ldb_dn_get_linearized(data->replicate[i]), 
     587             :                                                partition->backend_url,
     588           0 :                                                ldb_dn_get_linearized(partition->ctrl->dn), 
     589             :                                                ldb_errstring(ldb));
     590           0 :                         return ret;
     591             :                 }
     592             : 
     593             :                 /* Build add request */
     594        2757 :                 ret = ldb_build_add_req(&add_req, ldb, replicate_res, 
     595        2757 :                                         replicate_res->msgs[0], NULL, NULL, 
     596             :                                         ldb_op_default_callback, last_req);
     597        2757 :                 LDB_REQ_SET_LOCATION(add_req);
     598        2757 :                 last_req = add_req;
     599        2757 :                 if (ret != LDB_SUCCESS) {
     600             :                         /* return directly, this is a very unlikely error */
     601           0 :                         return ret;
     602             :                 }
     603             :                 /* do request */
     604        2757 :                 ret = ldb_next_request(partition->module, add_req);
     605             :                 /* wait */
     606        2757 :                 if (ret == LDB_SUCCESS) {
     607        2757 :                         ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
     608             :                 }
     609             :                 
     610        2757 :                 switch (ret) {
     611        2448 :                 case LDB_SUCCESS:
     612        2448 :                         break;
     613             : 
     614           0 :                 case LDB_ERR_ENTRY_ALREADY_EXISTS:
     615             :                         /* Handle this case specially - if the
     616             :                          * metadata already exists, replace it */
     617             :                 {
     618             :                         struct ldb_request *del_req;
     619             :                         
     620             :                         /* Don't leave a confusing string in the ldb_errstring() */
     621           0 :                         ldb_reset_err_string(ldb);
     622             :                         /* Build del request */
     623           0 :                         ret = ldb_build_del_req(&del_req, ldb, replicate_res, replicate_res->msgs[0]->dn, NULL, NULL, 
     624             :                                                 ldb_op_default_callback, last_req);
     625           0 :                         LDB_REQ_SET_LOCATION(del_req);
     626           0 :                         last_req = del_req;
     627           0 :                         if (ret != LDB_SUCCESS) {
     628             :                                 /* return directly, this is a very unlikely error */
     629           0 :                                 return ret;
     630             :                         }
     631             :                         /* do request */
     632           0 :                         ret = ldb_next_request(partition->module, del_req);
     633             :                         
     634             :                         /* wait */
     635           0 :                         if (ret == LDB_SUCCESS) {
     636           0 :                                 ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
     637             :                         }
     638           0 :                         if (ret != LDB_SUCCESS) {
     639           0 :                                 ldb_asprintf_errstring(ldb,
     640             :                                                        "Failed to delete  (for re-add) %s from " DSDB_PARTITION_DN 
     641             :                                                        " replicateEntries in new partition at %s on %s: %s", 
     642           0 :                                                        ldb_dn_get_linearized(data->replicate[i]), 
     643             :                                                        partition->backend_url,
     644           0 :                                                        ldb_dn_get_linearized(partition->ctrl->dn), 
     645             :                                                        ldb_errstring(ldb));
     646           0 :                                 return ret;
     647             :                         }
     648             :                         
     649             :                         /* Build add request */
     650           0 :                         ret = ldb_build_add_req(&add_req, ldb, replicate_res, replicate_res->msgs[0], NULL, NULL, 
     651             :                                                 ldb_op_default_callback, last_req);
     652           0 :                         LDB_REQ_SET_LOCATION(add_req);
     653           0 :                         last_req = add_req;
     654           0 :                         if (ret != LDB_SUCCESS) {
     655             :                                 /* return directly, this is a very unlikely error */
     656           0 :                                 return ret;
     657             :                         }
     658             :                         
     659             :                         /* do the add again */
     660           0 :                         ret = ldb_next_request(partition->module, add_req);
     661             :                         
     662             :                         /* wait */
     663           0 :                         if (ret == LDB_SUCCESS) {
     664           0 :                                 ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
     665             :                         }
     666             : 
     667           0 :                         if (ret != LDB_SUCCESS) {
     668           0 :                                 ldb_asprintf_errstring(ldb,
     669             :                                                        "Failed to add (after delete) %s from " DSDB_PARTITION_DN 
     670             :                                                        " replicateEntries to new partition at %s on %s: %s", 
     671           0 :                                                        ldb_dn_get_linearized(data->replicate[i]), 
     672             :                                                        partition->backend_url,
     673           0 :                                                        ldb_dn_get_linearized(partition->ctrl->dn), 
     674             :                                                        ldb_errstring(ldb));
     675           0 :                                 return ret;
     676             :                         }
     677           0 :                         break;
     678             :                 }
     679           0 :                 default: 
     680             :                 {
     681           0 :                         ldb_asprintf_errstring(ldb,
     682             :                                                "Failed to add %s from " DSDB_PARTITION_DN 
     683             :                                                " replicateEntries to new partition at %s on %s: %s", 
     684           0 :                                                ldb_dn_get_linearized(data->replicate[i]), 
     685             :                                                partition->backend_url,
     686           0 :                                                ldb_dn_get_linearized(partition->ctrl->dn), 
     687             :                                                ldb_errstring(ldb));
     688           0 :                         return ret;
     689             :                 }
     690             :                 }
     691             : 
     692             :                 /* And around again, for the next thing we must merge */
     693             :         }
     694         816 :         return LDB_SUCCESS;
     695             : }
     696             : 
     697             : /* Extended operation to create a new partition, called when
     698             :  * 'new_partition' detects that one is being added based on it's
     699             :  * instanceType */
     700         919 : int partition_create(struct ldb_module *module, struct ldb_request *req)
     701             : {
     702             :         unsigned int i;
     703             :         int ret;
     704         919 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     705         919 :         struct ldb_request *mod_req, *last_req = req;
     706             :         struct ldb_message *mod_msg;
     707             :         struct partition_private_data *data;
     708         919 :         struct dsdb_partition *partition = NULL;
     709             :         const char *casefold_dn;
     710         919 :         bool new_partition = false;
     711             : 
     712             :         /* Check if this is already a partition */
     713             : 
     714         919 :         struct dsdb_create_partition_exop *ex_op = talloc_get_type(req->op.extended.data, struct dsdb_create_partition_exop);
     715         919 :         struct ldb_dn *dn = ex_op->new_dn;
     716             : 
     717         919 :         data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data);
     718         919 :         if (!data) {
     719             :                 /* We are not going to create a partition before we are even set up */
     720           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     721             :         }
     722             : 
     723             :         /* see if we are still up-to-date */
     724         919 :         ret = partition_reload_if_required(module, data, req);
     725         919 :         if (ret != LDB_SUCCESS) {
     726           0 :                 return ret;
     727             :         }
     728             : 
     729        2600 :         for (i=0; data->partitions && data->partitions[i]; i++) {
     730        1784 :                 if (ldb_dn_compare(data->partitions[i]->ctrl->dn, dn) == 0) {
     731           0 :                         partition = data->partitions[i];
     732             :                 }
     733             :         }
     734             : 
     735         919 :         if (!partition) {
     736             :                 char *filename;
     737             :                 char *partition_record;
     738         919 :                 new_partition = true;
     739         919 :                 mod_msg = ldb_msg_new(req);
     740         919 :                 if (!mod_msg) {
     741           0 :                         return ldb_oom(ldb);
     742             :                 }
     743             :                 
     744         919 :                 mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN);
     745         919 :                 ret = ldb_msg_add_empty(mod_msg, DSDB_PARTITION_ATTR, LDB_FLAG_MOD_ADD, NULL);
     746         919 :                 if (ret != LDB_SUCCESS) {
     747           0 :                         return ret;
     748             :                 }
     749             :                 
     750         919 :                 casefold_dn = ldb_dn_get_casefold(dn);
     751             :                 
     752             :                 {
     753             :                         char *escaped;
     754             :                         const char *p, *sam_name;
     755         919 :                         sam_name = strrchr((const char *)ldb_get_opaque(ldb, "ldb_url"), '/');
     756         919 :                         if (!sam_name) {
     757           0 :                                 return ldb_operr(ldb);
     758             :                         }
     759         919 :                         sam_name++;
     760             : 
     761       42557 :                         for (p = casefold_dn; *p; p++) {
     762             :                                 /* We have such a strict check because
     763             :                                  * I don't want shell metacharacters
     764             :                                  * in the file name, nor ../, but I do
     765             :                                  * want it to be easily typed if SAFE
     766             :                                  * to do so */
     767       41675 :                                 if (!(isalnum(*p) || *p == ' ' || *p == '=' || *p == ',')) {
     768          37 :                                         break;
     769             :                                 }
     770             :                         }
     771         919 :                         if (*p) {
     772          37 :                                 escaped = rfc1738_escape_part(mod_msg, casefold_dn);
     773          37 :                                 if (!escaped) {
     774           0 :                                         return ldb_oom(ldb);
     775             :                                 }
     776          37 :                                 filename = talloc_asprintf(mod_msg, "%s.d/%s.ldb", sam_name, escaped);
     777          37 :                                 talloc_free(escaped);
     778             :                         } else {
     779         882 :                                 filename = talloc_asprintf(mod_msg, "%s.d/%s.ldb", sam_name, casefold_dn);
     780             :                         }
     781             : 
     782         919 :                         if (!filename) {
     783           0 :                                 return ldb_oom(ldb);
     784             :                         }
     785             :                 }
     786         919 :                 partition_record = talloc_asprintf(mod_msg, "%s:%s", casefold_dn, filename);
     787             : 
     788         919 :                 ret = ldb_msg_add_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record);
     789         919 :                 if (ret != LDB_SUCCESS) {
     790           0 :                         return ret;
     791             :                 }
     792             : 
     793         919 :                 if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
     794             :                         /* this new partition is a partial replica */
     795           0 :                         ret = ldb_msg_add_empty(mod_msg, "partialReplica", LDB_FLAG_MOD_ADD, NULL);
     796           0 :                         if (ret != LDB_SUCCESS) {
     797           0 :                                 return ret;
     798             :                         }
     799           0 :                         ret = ldb_msg_add_fmt(mod_msg, "partialReplica", "%s", ldb_dn_get_linearized(dn));
     800           0 :                         if (ret != LDB_SUCCESS) {
     801           0 :                                 return ret;
     802             :                         }
     803             :                 }
     804             :                 
     805             :                 /* Perform modify on @PARTITION record */
     806         919 :                 ret = ldb_build_mod_req(&mod_req, ldb, req, mod_msg, NULL, NULL, 
     807             :                                         ldb_op_default_callback, req);
     808         919 :                 LDB_REQ_SET_LOCATION(mod_req);
     809         919 :                 if (ret != LDB_SUCCESS) {
     810           0 :                         return ret;
     811             :                 }
     812             :                 
     813         919 :                 last_req = mod_req;
     814             : 
     815         919 :                 ret = ldb_next_request(module, mod_req);
     816         919 :                 if (ret == LDB_SUCCESS) {
     817         919 :                         ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
     818             :                 }
     819             :                 
     820         919 :                 if (ret != LDB_SUCCESS) {
     821           0 :                         return ret;
     822             :                 }
     823             :                 
     824             :                 /* Make a partition structure for this new partition, so we can copy in the template structure */ 
     825         919 :                 ret = new_partition_from_dn(ldb, data, req, ldb_dn_copy(req, dn),
     826             :                                             filename, data->backend_db_store,
     827             :                                             &partition);
     828         919 :                 if (ret != LDB_SUCCESS) {
     829           0 :                         return ret;
     830             :                 }
     831         919 :                 talloc_steal(partition, partition_record);
     832         919 :                 partition->orig_record = data_blob_string_const(partition_record);
     833             :         }
     834             :         
     835         919 :         ret = new_partition_set_replicated_metadata(ldb, module, last_req, data, partition);
     836         919 :         if (ret != LDB_SUCCESS) {
     837           0 :                 return ret;
     838             :         }
     839             :         
     840         919 :         if (new_partition) {
     841         919 :                 ret = add_partition_to_data(ldb, data, partition);
     842         919 :                 if (ret != LDB_SUCCESS) {
     843           0 :                         return ret;
     844             :                 }
     845             :         }
     846             : 
     847             :         /* send request done */
     848         919 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     849             : }
     850             : 
     851             : 
     852      132464 : int partition_init(struct ldb_module *module)
     853             : {
     854             :         int ret;
     855      132464 :         TALLOC_CTX *mem_ctx = talloc_new(module);
     856      132464 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     857             :         struct partition_private_data *data;
     858             : 
     859      132464 :         if (!mem_ctx) {
     860           0 :                 return ldb_operr(ldb);
     861             :         }
     862             : 
     863             :         /* We actually got this during the read_lock call */
     864      132464 :         data = talloc_get_type_abort(ldb_module_get_private(module),
     865             :                                      struct partition_private_data);
     866             : 
     867             :         /* This loads the partitions */
     868      132464 :         ret = partition_reload_if_required(module, data, NULL);
     869      132464 :         if (ret != LDB_SUCCESS) {
     870           0 :                 return ret;
     871             :         }
     872             : 
     873      132464 :         ldb_module_set_private(module, talloc_steal(module, data));
     874      132464 :         talloc_free(mem_ctx);
     875             : 
     876      132464 :         ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
     877      132464 :         if (ret != LDB_SUCCESS) {
     878           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     879             :                         "partition: Unable to register control with rootdse!\n");
     880           0 :                 return ldb_operr(ldb);
     881             :         }
     882             : 
     883      132464 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
     884      132464 :         if (ret != LDB_SUCCESS) {
     885           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     886             :                         "partition: Unable to register control with rootdse!\n");
     887           0 :                 return ldb_operr(ldb);
     888             :         }
     889             : 
     890      132464 :         return ldb_next_init(module);
     891             : }

Generated by: LCOV version 1.13