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 master 2b515b7d Lines: 319 463 68.9 %
Date: 2024-02-28 12:06:22 Functions: 12 12 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     2166243 : static int partition_sort_compare(const void *v1, const void *v2)
      38             : {
      39       76796 :         const struct dsdb_partition *p1;
      40       76796 :         const struct dsdb_partition *p2;
      41             : 
      42     2166243 :         p1 = *((struct dsdb_partition * const*)v1);
      43     2166243 :         p2 = *((struct dsdb_partition * const*)v2);
      44             : 
      45     2166243 :         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      181894 : static int partition_load_replicate_dns(struct ldb_context *ldb,
      50             :                                         struct partition_private_data *data,
      51             :                                         struct ldb_message *msg)
      52             : {
      53      181894 :         struct ldb_message_element *replicate_attributes = ldb_msg_find_element(msg, "replicateEntries");
      54             : 
      55      181894 :         talloc_free(data->replicate);
      56      181894 :         if (!replicate_attributes) {
      57           0 :                 data->replicate = NULL;
      58             :         } else {
      59        6222 :                 unsigned int i;
      60      181894 :                 data->replicate = talloc_array(data, struct ldb_dn *, replicate_attributes->num_values + 1);
      61      181894 :                 if (!data->replicate) {
      62           0 :                         return ldb_oom(ldb);
      63             :                 }
      64             : 
      65      727560 :                 for (i=0; i < replicate_attributes->num_values; i++) {
      66      545666 :                         data->replicate[i] = ldb_dn_from_ldb_val(data->replicate, ldb, &replicate_attributes->values[i]);
      67      545666 :                         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      181894 :                 data->replicate[i] = NULL;
      76             :         }
      77      175672 :         return LDB_SUCCESS;
      78             : }
      79             : 
      80             : /* Load the list of modules for the partitions */
      81      181894 : static int partition_load_modules(struct ldb_context *ldb, 
      82             :                                   struct partition_private_data *data, struct ldb_message *msg) 
      83             : {
      84        6222 :         unsigned int i;
      85      181894 :         struct ldb_message_element *modules_attributes = ldb_msg_find_element(msg, "modules");
      86      181894 :         talloc_free(data->modules);
      87      181894 :         if (!modules_attributes) {
      88           0 :                 return LDB_SUCCESS;
      89             :         }
      90             :         
      91      181894 :         data->modules = talloc_array(data, struct partition_module *, modules_attributes->num_values + 1);
      92      181894 :         if (!data->modules) {
      93           0 :                 return ldb_oom(ldb);
      94             :         }
      95             :         
      96      545666 :         for (i=0; i < modules_attributes->num_values; i++) {
      97       12428 :                 char *p;
      98       12428 :                 DATA_BLOB dn_blob;
      99      363772 :                 data->modules[i] = talloc(data->modules, struct partition_module);
     100      363772 :                 if (!data->modules[i]) {
     101           0 :                         return ldb_oom(ldb);
     102             :                 }
     103             : 
     104      363772 :                 dn_blob = modules_attributes->values[i];
     105             : 
     106      363772 :                 p = strchr((const char *)dn_blob.data, ':');
     107      363772 :                 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      363772 :                 dn_blob.length = ((uint8_t *)p - dn_blob.data);
     115             : 
     116      363772 :                 p++;
     117      363772 :                 data->modules[i]->modules = ldb_modules_list_from_string(ldb, data->modules[i],
     118             :                                                                          p);
     119             :                 
     120      363772 :                 if (dn_blob.length == 1 && dn_blob.data[0] == '*') {
     121      181894 :                         data->modules[i]->dn = NULL;
     122             :                 } else {
     123      181878 :                         data->modules[i]->dn = ldb_dn_from_ldb_val(data->modules[i], ldb, &dn_blob);
     124      181878 :                         if (!data->modules[i]->dn || !ldb_dn_validate(data->modules[i]->dn)) {
     125           0 :                                 return ldb_operr(ldb);
     126             :                         }
     127             :                 }
     128             :         }
     129      181894 :         data->modules[i] = NULL;
     130      181894 :         return LDB_SUCCESS;
     131             : }
     132             : 
     133      181894 : 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        6222 :         int ret;
     138        6222 :         struct ldb_message *msg, *module_msg;
     139        6222 :         struct ldb_result *res;
     140      181894 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     141      181894 :         const char *attrs[] = { "partition", "replicateEntries", "modules",
     142             :                                 "partialReplica", "backendStore", NULL };
     143             :         /* perform search for @PARTITION, looking for module, replicateEntries and ldapBackend */
     144      181894 :         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      181894 :         if (ret != LDB_SUCCESS) {
     149           0 :                 return ret;
     150             :         }
     151             : 
     152      181894 :         msg = res->msgs[0];
     153             : 
     154      181894 :         ret = partition_load_replicate_dns(ldb, data, msg);
     155      181894 :         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      181894 :         if (data->forced_module_msg) {
     163      181878 :                 module_msg = data->forced_module_msg;
     164             :         } else {
     165           0 :                 module_msg = msg;
     166             :         }
     167             : 
     168      181894 :         ret = partition_load_modules(ldb, data, module_msg);
     169      181894 :         if (ret != LDB_SUCCESS) {
     170           0 :                 return ret;
     171             :         }
     172             : 
     173      181894 :         if (_msg) {
     174      181894 :                 *_msg = msg;
     175             :         } else {
     176           0 :                 talloc_free(msg);
     177             :         }
     178             : 
     179      175672 :         return LDB_SUCCESS;
     180             : }
     181             : 
     182      862834 : static const char **find_modules_for_dn(struct partition_private_data *data, struct ldb_dn *dn) 
     183             : {
     184       29736 :         unsigned int i;
     185      862834 :         struct partition_module *default_mod = NULL;
     186     2229228 :         for (i=0; data->modules && data->modules[i]; i++) {
     187     1546020 :                 if (!data->modules[i]->dn) {
     188      659464 :                         default_mod = data->modules[i];
     189      862812 :                 } else if (ldb_dn_compare(dn, data->modules[i]->dn) == 0) {
     190      179626 :                         return data->modules[i]->modules;
     191             :                 }
     192             :         }
     193      683208 :         if (default_mod) {
     194      683208 :                 return default_mod->modules;
     195             :         } else {
     196           0 :                 return NULL;
     197             :         }
     198             : }
     199             : 
     200      862834 : 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       29736 :         struct dsdb_control_current_partition *ctrl;
     206       29736 :         struct ldb_module *backend_module;
     207       29736 :         char *backend_path;
     208       29736 :         struct ldb_module *module_chain;
     209       29736 :         const char **modules;
     210      862834 :         const char **options = NULL;
     211       29736 :         int ret;
     212             : 
     213      862834 :         (*partition) = talloc_zero(mem_ctx, struct dsdb_partition);
     214      862834 :         if (!*partition) {
     215           0 :                 return ldb_oom(ldb);
     216             :         }
     217             : 
     218      862834 :         (*partition)->ctrl = ctrl = talloc((*partition), struct dsdb_control_current_partition);
     219      862834 :         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      862834 :         backend_path = ldb_relative_path(ldb,
     226             :                                          *partition,
     227             :                                          filename);
     228      862834 :         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      862834 :         (*partition)->backend_url = talloc_asprintf(*partition, "%s://%s",
     236             :                                                     backend_db_store,
     237             :                                                     backend_path);
     238             : 
     239      862834 :         if (!(ldb_module_flags(ldb) & LDB_FLG_RDONLY)) {
     240       29736 :                 char *p;
     241       29736 :                 char *backend_dir;
     242             : 
     243      862804 :                 p = strrchr(backend_path, '/');
     244      862804 :                 if (p) {
     245      862804 :                         p[0] = '\0';
     246             :                 }
     247      862804 :                 backend_dir = backend_path;
     248             : 
     249             :                 /* Failure is quite reasonable, it might already exist */
     250      862804 :                 mkdir(backend_dir, 0700);
     251             :         }
     252             : 
     253      862834 :         ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
     254      862834 :         ctrl->dn = talloc_steal(ctrl, dn);
     255             :         
     256      862834 :         options = ldb_options_get(ldb);
     257      892570 :         ret = ldb_module_connect_backend(
     258      862834 :             ldb, (*partition)->backend_url, options, &backend_module);
     259      862834 :         if (ret != LDB_SUCCESS) {
     260           0 :                 return ret;
     261             :         }
     262      862834 :         talloc_steal((*partition), backend_module);
     263             : 
     264      862834 :         modules = find_modules_for_dn(data, dn);
     265             : 
     266      862834 :         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      862834 :         ret = ldb_module_load_list(ldb, modules, backend_module, &module_chain);
     272      862834 :         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      862834 :         ret = ldb_module_init_chain(ldb, module_chain);
     281      862834 :         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      862834 :         (*partition)->module = ldb_module_new(*partition, ldb, "partition_next", NULL);
     292      862834 :         if (!(*partition)->module) {
     293           0 :                 talloc_free(*partition);
     294           0 :                 return ldb_oom(ldb);
     295             :         }
     296      862834 :         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      862834 :         if (data->in_transaction) {
     302         979 :                 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         979 :                 ret = ldb_next_start_trans((*partition)->module);
     307             :         }
     308             : 
     309      833098 :         return ret;
     310             : }
     311             : 
     312             : /* Tell the rootDSE about the new partition */
     313      862834 : static int partition_register(struct ldb_context *ldb, struct dsdb_control_current_partition *ctrl) 
     314             : {
     315       29736 :         struct ldb_request *req;
     316       29736 :         int ret;
     317             : 
     318      862834 :         req = talloc_zero(NULL, struct ldb_request);
     319      862834 :         if (req == NULL) {
     320           0 :                 return ldb_oom(ldb);
     321             :         }
     322             :                 
     323      862834 :         req->operation = LDB_REQ_REGISTER_PARTITION;
     324      862834 :         req->op.reg_partition.dn = ctrl->dn;
     325      862834 :         req->callback = ldb_op_default_callback;
     326             : 
     327      862834 :         ldb_set_timeout(ldb, req, 0);
     328             :         
     329      862834 :         req->handle = ldb_handle_new(req, ldb);
     330      862834 :         if (req->handle == NULL) {
     331           0 :                 talloc_free(req);
     332           0 :                 return ldb_operr(ldb);
     333             :         }
     334             :         
     335      862834 :         ret = ldb_request(ldb, req);
     336      862834 :         if (ret == LDB_SUCCESS) {
     337      862834 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     338             :         }
     339      862834 :         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      862834 :         talloc_free(req);
     345             : 
     346      862834 :         return LDB_SUCCESS;
     347             : }
     348             : 
     349             : /* Add a newly found partition to the global data */
     350      862834 : static int add_partition_to_data(struct ldb_context *ldb, struct partition_private_data *data,
     351             :                                  struct dsdb_partition *partition)
     352             : {
     353       29736 :         unsigned int i;
     354       29736 :         int ret;
     355             : 
     356             :         /* Count the partitions */
     357     2535490 :         for (i=0; data->partitions && data->partitions[i]; i++) { /* noop */};
     358             :         
     359             :         /* Add partition to list of partitions */
     360      862834 :         data->partitions = talloc_realloc(data, data->partitions, struct dsdb_partition *, i + 2);
     361      862834 :         if (!data->partitions) {
     362           0 :                 return ldb_oom(ldb);
     363             :         }
     364      862834 :         data->partitions[i] = talloc_steal(data->partitions, partition);
     365      862834 :         data->partitions[i+1] = NULL;
     366             :         
     367             :         /* Sort again (should use binary insert) */
     368      862834 :         TYPESAFE_QSORT(data->partitions, i+1, partition_sort_compare);
     369             :         
     370      862834 :         ret = partition_register(ldb, partition->ctrl);
     371      862834 :         if (ret != LDB_SUCCESS) {
     372           0 :                 return ret;
     373             :         }
     374      833098 :         return LDB_SUCCESS;
     375             : }
     376             : 
     377    19272679 : int partition_reload_if_required(struct ldb_module *module, 
     378             :                                  struct partition_private_data *data,
     379             :                                  struct ldb_request *parent)
     380             : {
     381     1128823 :         uint64_t seq;
     382     1128823 :         int ret;
     383     1128823 :         unsigned int i;
     384    19272679 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     385     1128823 :         struct ldb_message *msg;
     386     1128823 :         struct ldb_message_element *partition_attributes;
     387     1128823 :         struct ldb_message_element *partial_replicas;
     388     1128823 :         TALLOC_CTX *mem_ctx;
     389             : 
     390    19272679 :         if (!data) {
     391             :                 /* Not initialised yet */
     392           0 :                 return LDB_SUCCESS;
     393             :         }
     394             : 
     395    19272679 :         mem_ctx = talloc_new(data);
     396    19272679 :         if (!mem_ctx) {
     397           0 :                 return ldb_oom(ldb);
     398             :         }
     399             : 
     400    19272679 :         ret = partition_primary_sequence_number(module, mem_ctx, &seq, parent);
     401    19272679 :         if (ret != LDB_SUCCESS) {
     402           0 :                 talloc_free(mem_ctx);
     403           0 :                 return ret;
     404             :         }
     405    19272679 :         if (seq == data->metadata_seq) {
     406    19090785 :                 talloc_free(mem_ctx);
     407    19090785 :                 return LDB_SUCCESS;
     408             :         }
     409             : 
     410             :         /* This loads metadata tdb. If it's missing, creates it */
     411      181894 :         ret = partition_metadata_init(module);
     412      181894 :         if (ret != LDB_SUCCESS) {
     413           0 :                 return ret;
     414             :         }
     415             : 
     416      181894 :         ret = partition_reload_metadata(module, data, mem_ctx, &msg, parent);
     417      181894 :         if (ret != LDB_SUCCESS) {
     418           0 :                 talloc_free(mem_ctx);
     419           0 :                 return ret;
     420             :         }
     421             : 
     422      181894 :         data->metadata_seq = seq;
     423             : 
     424      181894 :         partition_attributes = ldb_msg_find_element(msg, "partition");
     425      181894 :         partial_replicas     = ldb_msg_find_element(msg, "partialReplica");
     426        6222 :         data->backend_db_store
     427      181894 :                 = talloc_strdup(data, ldb_msg_find_attr_as_string(msg, "backendStore", "tdb"));
     428             : 
     429      181894 :         if (data->backend_db_store == NULL) {
     430           0 :                 talloc_free(mem_ctx);
     431           0 :                 return ldb_module_oom(module);
     432             :         }
     433             : 
     434     1050537 :         for (i=0; partition_attributes && i < partition_attributes->num_values; i++) {
     435       30251 :                 unsigned int j;
     436      868643 :                 bool new_partition = true;
     437      868643 :                 const char *filename = NULL;
     438       30251 :                 DATA_BLOB dn_blob;
     439       30251 :                 struct ldb_dn *dn;
     440       30251 :                 struct dsdb_partition *partition;
     441       30251 :                 struct ldb_result *dn_res;
     442      868643 :                 const char *no_attrs[] = { NULL };
     443             : 
     444     2550692 :                 for (j=0; data->partitions && data->partitions[j]; j++) {
     445     1688837 :                         if (data_blob_cmp(&data->partitions[j]->orig_record, &partition_attributes->values[i]) == 0) {
     446        6165 :                                 new_partition = false;
     447        6165 :                                 break;
     448             :                         }
     449             :                 }
     450      868643 :                 if (new_partition == false) {
     451        6788 :                         continue;
     452             :                 }
     453             : 
     454      861855 :                 dn_blob = partition_attributes->values[i];
     455             :                 
     456      861855 :                 if (dn_blob.length > 4 && 
     457      861855 :                     (strncmp((const char *)&dn_blob.data[dn_blob.length-4], ".ldb", 4) == 0)) {
     458             : 
     459             :                         /* Look for DN:filename.ldb */
     460      861833 :                         char *p = strrchr((const char *)dn_blob.data, ':');
     461      861833 :                         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      861833 :                         filename = p+1;
     468             :                         
     469             :                         /* Now trim off the filename */
     470      861833 :                         dn_blob.length = ((uint8_t *)p - dn_blob.data);
     471             :                 }
     472             : 
     473      861855 :                 dn = ldb_dn_from_ldb_val(mem_ctx, ldb, &dn_blob);
     474      861855 :                 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     2532607 :                 for (j=0; data->partitions && data->partitions[j]; j++) {
     483     1670752 :                         if (ldb_dn_compare(dn, data->partitions[j]->ctrl->dn) == 0) {
     484           0 :                                 new_partition = false;
     485           0 :                                 break;
     486             :                         }
     487             :                 }
     488      861855 :                 if (new_partition == false) {
     489           0 :                         continue;
     490             :                 }
     491             : 
     492      861855 :                 if (!filename) {
     493          22 :                         char *base64_dn = NULL;
     494          22 :                         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      861855 :                 ret = new_partition_from_dn(ldb, data, data->partitions, dn, 
     514             :                                             filename, data->backend_db_store,
     515             :                                             &partition);
     516      861855 :                 if (ret != LDB_SUCCESS) {
     517           0 :                         talloc_free(mem_ctx);
     518           0 :                         return ret;
     519             :                 }
     520             : 
     521      861855 :                 talloc_steal(partition, partition_attributes->values[i].data);
     522      861855 :                 partition->orig_record = partition_attributes->values[i];
     523             : 
     524             :                 /* Get the 'correct' case of the partition DNs from the database */
     525      861855 :                 ret = dsdb_module_search_dn(partition->module, data, &dn_res, 
     526             :                                             dn, no_attrs,
     527             :                                             DSDB_FLAG_NEXT_MODULE, parent);
     528      861855 :                 if (ret == LDB_SUCCESS) {
     529      861833 :                         talloc_free(partition->ctrl->dn);
     530      861833 :                         partition->ctrl->dn = talloc_steal(partition->ctrl, dn_res->msgs[0]->dn);
     531      861833 :                         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      861855 :                 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      861855 :                 ret = add_partition_to_data(ldb, data, partition);
     552      861855 :                 if (ret != LDB_SUCCESS) {
     553           0 :                         talloc_free(mem_ctx);
     554           0 :                         return ret;
     555             :                 }
     556             :         }
     557             : 
     558      181894 :         talloc_free(mem_ctx);
     559      181894 :         return LDB_SUCCESS;
     560             : }
     561             : 
     562             : /* Copy the metadata (@OPTIONS etc) for the new partition into the partition */
     563             : 
     564         979 : 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         108 :         unsigned int i;
     570         108 :         int ret;
     571             :         /* for each replicate, copy from main partition.  If we get an error, we report it up the chain */
     572        3916 :         for (i=0; data->replicate && data->replicate[i]; i++) {
     573         324 :                 struct ldb_result *replicate_res;
     574         324 :                 struct ldb_request *add_req;
     575        2937 :                 ret = dsdb_module_search_dn(module, last_req, &replicate_res, 
     576        2613 :                                             data->replicate[i],
     577             :                                             NULL,
     578             :                                             DSDB_FLAG_NEXT_MODULE, NULL);
     579        2937 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     580           0 :                         continue;
     581             :                 }
     582        2937 :                 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        3261 :                 ret = ldb_build_add_req(&add_req, ldb, replicate_res, 
     595        2937 :                                         replicate_res->msgs[0], NULL, NULL, 
     596             :                                         ldb_op_default_callback, last_req);
     597        2937 :                 LDB_REQ_SET_LOCATION(add_req);
     598        2937 :                 last_req = add_req;
     599        2937 :                 if (ret != LDB_SUCCESS) {
     600             :                         /* return directly, this is a very unlikely error */
     601           0 :                         return ret;
     602             :                 }
     603             :                 /* do request */
     604        2937 :                 ret = ldb_next_request(partition->module, add_req);
     605             :                 /* wait */
     606        2937 :                 if (ret == LDB_SUCCESS) {
     607        2937 :                         ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
     608             :                 }
     609             :                 
     610        2937 :                 switch (ret) {
     611        2613 :                 case LDB_SUCCESS:
     612        2613 :                         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           0 :                         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         871 :         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         979 : int partition_create(struct ldb_module *module, struct ldb_request *req)
     701             : {
     702         108 :         unsigned int i;
     703         108 :         int ret;
     704         979 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     705         979 :         struct ldb_request *mod_req, *last_req = req;
     706         108 :         struct ldb_message *mod_msg;
     707         108 :         struct partition_private_data *data;
     708         979 :         struct dsdb_partition *partition = NULL;
     709         108 :         const char *casefold_dn;
     710         979 :         bool new_partition = false;
     711             : 
     712             :         /* Check if this is already a partition */
     713             : 
     714         979 :         struct dsdb_create_partition_exop *ex_op = talloc_get_type(req->op.extended.data, struct dsdb_create_partition_exop);
     715         979 :         struct ldb_dn *dn = ex_op->new_dn;
     716             : 
     717         979 :         data = talloc_get_type(ldb_module_get_private(module), struct partition_private_data);
     718         979 :         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         979 :         ret = partition_reload_if_required(module, data, req);
     725         979 :         if (ret != LDB_SUCCESS) {
     726           0 :                 return ret;
     727             :         }
     728             : 
     729        2883 :         for (i=0; data->partitions && data->partitions[i]; i++) {
     730        1904 :                 if (ldb_dn_compare(data->partitions[i]->ctrl->dn, dn) == 0) {
     731           0 :                         partition = data->partitions[i];
     732             :                 }
     733             :         }
     734             : 
     735         979 :         if (!partition) {
     736         108 :                 char *filename;
     737         108 :                 char *partition_record;
     738         979 :                 new_partition = true;
     739         979 :                 mod_msg = ldb_msg_new(req);
     740         979 :                 if (!mod_msg) {
     741           0 :                         return ldb_oom(ldb);
     742             :                 }
     743             :                 
     744         979 :                 mod_msg->dn = ldb_dn_new(mod_msg, ldb, DSDB_PARTITION_DN);
     745             :                 
     746         979 :                 casefold_dn = ldb_dn_get_casefold(dn);
     747             :                 
     748             :                 {
     749         108 :                         char *escaped;
     750         108 :                         const char *p, *sam_name;
     751         979 :                         sam_name = strrchr((const char *)ldb_get_opaque(ldb, "ldb_url"), '/');
     752         979 :                         if (!sam_name) {
     753           0 :                                 return ldb_operr(ldb);
     754             :                         }
     755         979 :                         sam_name++;
     756             : 
     757       45167 :                         for (p = casefold_dn; *p; p++) {
     758             :                                 /* We have such a strict check because
     759             :                                  * I don't want shell metacharacters
     760             :                                  * in the file name, nor ../, but I do
     761             :                                  * want it to be easily typed if SAFE
     762             :                                  * to do so */
     763       44225 :                                 if (!(isalnum(*p) || *p == ' ' || *p == '=' || *p == ',')) {
     764          37 :                                         break;
     765             :                                 }
     766             :                         }
     767         979 :                         if (*p) {
     768          37 :                                 escaped = rfc1738_escape_part(mod_msg, casefold_dn);
     769          37 :                                 if (!escaped) {
     770           0 :                                         return ldb_oom(ldb);
     771             :                                 }
     772          37 :                                 filename = talloc_asprintf(mod_msg, "%s.d/%s.ldb", sam_name, escaped);
     773          37 :                                 talloc_free(escaped);
     774             :                         } else {
     775         942 :                                 filename = talloc_asprintf(mod_msg, "%s.d/%s.ldb", sam_name, casefold_dn);
     776             :                         }
     777             : 
     778         979 :                         if (!filename) {
     779           0 :                                 return ldb_oom(ldb);
     780             :                         }
     781             :                 }
     782         979 :                 partition_record = talloc_asprintf(mod_msg, "%s:%s", casefold_dn, filename);
     783             : 
     784         979 :                 ret = ldb_msg_append_steal_string(mod_msg, DSDB_PARTITION_ATTR, partition_record,
     785             :                                                   LDB_FLAG_MOD_ADD);
     786         979 :                 if (ret != LDB_SUCCESS) {
     787           0 :                         return ret;
     788             :                 }
     789             : 
     790         979 :                 if (ldb_request_get_control(req, DSDB_CONTROL_PARTIAL_REPLICA)) {
     791             :                         /* this new partition is a partial replica */
     792           0 :                         ret = ldb_msg_append_fmt(mod_msg, LDB_FLAG_MOD_ADD,
     793             :                                                  "partialReplica", "%s", ldb_dn_get_linearized(dn));
     794           0 :                         if (ret != LDB_SUCCESS) {
     795           0 :                                 return ret;
     796             :                         }
     797             :                 }
     798             :                 
     799             :                 /* Perform modify on @PARTITION record */
     800         979 :                 ret = ldb_build_mod_req(&mod_req, ldb, req, mod_msg, NULL, NULL, 
     801             :                                         ldb_op_default_callback, req);
     802         979 :                 LDB_REQ_SET_LOCATION(mod_req);
     803         979 :                 if (ret != LDB_SUCCESS) {
     804           0 :                         return ret;
     805             :                 }
     806             :                 
     807         979 :                 last_req = mod_req;
     808             : 
     809         979 :                 ret = ldb_next_request(module, mod_req);
     810         979 :                 if (ret == LDB_SUCCESS) {
     811         979 :                         ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
     812             :                 }
     813             :                 
     814         979 :                 if (ret != LDB_SUCCESS) {
     815           0 :                         return ret;
     816             :                 }
     817             :                 
     818             :                 /* Make a partition structure for this new partition, so we can copy in the template structure */ 
     819         979 :                 ret = new_partition_from_dn(ldb, data, req, ldb_dn_copy(req, dn),
     820             :                                             filename, data->backend_db_store,
     821             :                                             &partition);
     822         979 :                 if (ret != LDB_SUCCESS) {
     823           0 :                         return ret;
     824             :                 }
     825         979 :                 talloc_steal(partition, partition_record);
     826         979 :                 partition->orig_record = data_blob_string_const(partition_record);
     827             :         }
     828             :         
     829         979 :         ret = new_partition_set_replicated_metadata(ldb, module, last_req, data, partition);
     830         979 :         if (ret != LDB_SUCCESS) {
     831           0 :                 return ret;
     832             :         }
     833             :         
     834         979 :         if (new_partition) {
     835         979 :                 ret = add_partition_to_data(ldb, data, partition);
     836         979 :                 if (ret != LDB_SUCCESS) {
     837           0 :                         return ret;
     838             :                 }
     839             :         }
     840             : 
     841             :         /* send request done */
     842         979 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
     843             : }
     844             : 
     845             : 
     846      179639 : int partition_init(struct ldb_module *module)
     847             : {
     848        6004 :         int ret;
     849      179639 :         TALLOC_CTX *mem_ctx = talloc_new(module);
     850      179639 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
     851        6004 :         struct partition_private_data *data;
     852             : 
     853      179639 :         if (!mem_ctx) {
     854           0 :                 return ldb_operr(ldb);
     855             :         }
     856             : 
     857             :         /* We actually got this during the read_lock call */
     858      179639 :         data = talloc_get_type_abort(ldb_module_get_private(module),
     859             :                                      struct partition_private_data);
     860             : 
     861             :         /* This loads the partitions */
     862      179639 :         ret = partition_reload_if_required(module, data, NULL);
     863      179639 :         if (ret != LDB_SUCCESS) {
     864           0 :                 return ret;
     865             :         }
     866             : 
     867      179639 :         ldb_module_set_private(module, talloc_steal(module, data));
     868      179639 :         talloc_free(mem_ctx);
     869             : 
     870      179639 :         ret = ldb_mod_register_control(module, LDB_CONTROL_DOMAIN_SCOPE_OID);
     871      179639 :         if (ret != LDB_SUCCESS) {
     872           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     873             :                         "partition: Unable to register control with rootdse!\n");
     874           0 :                 return ldb_operr(ldb);
     875             :         }
     876             : 
     877      179639 :         ret = ldb_mod_register_control(module, LDB_CONTROL_SEARCH_OPTIONS_OID);
     878      179639 :         if (ret != LDB_SUCCESS) {
     879           0 :                 ldb_debug(ldb, LDB_DEBUG_ERROR,
     880             :                         "partition: Unable to register control with rootdse!\n");
     881           0 :                 return ldb_operr(ldb);
     882             :         }
     883             : 
     884      179639 :         return ldb_next_init(module);
     885             : }

Generated by: LCOV version 1.14