s4:samdb: Make sure value is initialized with 0
[samba.git] / source4 / dsdb / samdb / ldb_modules / partition_metadata.c
index 76b78dd13fa0edb543854a5f3de5c6422eb6352a..cf44c5d1218e61d77cf857d639c6f912a6497f7d 100644 (file)
@@ -18,6 +18,7 @@
 */
 
 #include "dsdb/samdb/ldb_modules/partition.h"
+#include "lib/ldb-samba/ldb_wrap.h"
 #include "system/filesys.h"
 
 #define LDB_METADATA_SEQ_NUM   "SEQ_NUM"
@@ -35,6 +36,7 @@ static int partition_metadata_get_uint64(struct ldb_module *module,
        TDB_DATA tdb_key, tdb_data;
        char *value_str;
        TALLOC_CTX *tmp_ctx;
+       int error = 0;
 
        data = talloc_get_type_abort(ldb_module_get_private(module),
                                     struct partition_private_data);
@@ -54,14 +56,14 @@ static int partition_metadata_get_uint64(struct ldb_module *module,
        tdb_key.dptr = (uint8_t *)discard_const_p(char, key);
        tdb_key.dsize = strlen(key);
 
-       tdb_data = tdb_fetch_compat(tdb, tdb_key);
+       tdb_data = tdb_fetch(tdb, tdb_key);
        if (!tdb_data.dptr) {
                if (tdb_error(tdb) == TDB_ERR_NOEXIST) {
                        *value = default_value;
                        return LDB_SUCCESS;
                } else {
                        return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                               tdb_errorstr_compat(tdb));
+                                               tdb_errorstr(tdb));
                }
        }
 
@@ -72,7 +74,11 @@ static int partition_metadata_get_uint64(struct ldb_module *module,
                return ldb_module_oom(module);
        }
 
-       *value = strtoull(value_str, NULL, 10);
+       *value = strtoull_err(value_str, NULL, 10, &error);
+       if (error != 0) {
+               return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+                                       "partition_metadata: converision failed");
+       }
 
        SAFE_FREE(tdb_data.dptr);
        talloc_free(tmp_ctx);
@@ -129,9 +135,13 @@ static int partition_metadata_set_uint64(struct ldb_module *module,
        }
 
        if (tdb_store(tdb, tdb_key, tdb_data, tdb_flag) != 0) {
+               int ret;
+               char *error_string = talloc_asprintf(tmp_ctx, "%s: tdb_store of key %s failed: %s",
+                                                    tdb_name(tdb), key, tdb_errorstr(tdb));
+               ret = ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+                                      error_string);
                talloc_free(tmp_ctx);
-               return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                       tdb_errorstr_compat(tdb));
+               return ret;
        }
 
        talloc_free(tmp_ctx);
@@ -139,6 +149,38 @@ static int partition_metadata_set_uint64(struct ldb_module *module,
        return LDB_SUCCESS;
 }
 
+int partition_metadata_inc_schema_sequence(struct ldb_module *module)
+{
+       struct partition_private_data *data;
+       int ret;
+       uint64_t value = 0;
+
+       data = talloc_get_type_abort(ldb_module_get_private(module),
+                                   struct partition_private_data);
+       if (!data || !data->metadata) {
+               return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+                                       "partition_metadata: metadata not initialized");
+       }
+
+       if (data->metadata->in_transaction == 0) {
+               return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
+                                       "partition_metadata: increment sequence number without transaction");
+       }
+       ret = partition_metadata_get_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, &value, 0);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       value++;
+       ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, false);
+       if (ret == LDB_ERR_OPERATIONS_ERROR) {
+               /* Modify failed, let's try the add */
+               ret = partition_metadata_set_uint64(module, DSDB_METADATA_SCHEMA_SEQ_NUM, value, true);
+       }
+       return ret;
+}
+
+
 
 /*
  * Open sam.ldb.d/metadata.tdb.
@@ -149,9 +191,8 @@ static int partition_metadata_open(struct ldb_module *module, bool create)
        TALLOC_CTX *tmp_ctx;
        struct partition_private_data *data;
        struct loadparm_context *lp_ctx;
-       const char *sam_name;
        char *filename, *dirname;
-       int open_flags;
+       int open_flags, tdb_flags, ldb_flags;
        struct stat statbuf;
 
        data = talloc_get_type_abort(ldb_module_get_private(module),
@@ -166,15 +207,10 @@ static int partition_metadata_open(struct ldb_module *module, bool create)
                return ldb_module_oom(module);
        }
 
-       sam_name = (const char *)ldb_get_opaque(ldb, "ldb_url");
-       if (strncmp("tdb://", sam_name, 6) == 0) {
-               sam_name += 6;
-       }
-       if (!sam_name) {
-               talloc_free(tmp_ctx);
-               return ldb_operr(ldb);
-       }
-       filename = talloc_asprintf(tmp_ctx, "%s.d/metadata.tdb", sam_name);
+       filename = ldb_relative_path(ldb,
+                                    tmp_ctx,
+                                    "sam.ldb.d/metadata.tdb");
+
        if (!filename) {
                talloc_free(tmp_ctx);
                return ldb_oom(ldb);
@@ -186,7 +222,9 @@ static int partition_metadata_open(struct ldb_module *module, bool create)
 
                /* While provisioning, sam.ldb.d directory may not exist,
                 * so create it. Ignore errors, if it already exists. */
-               dirname = talloc_asprintf(tmp_ctx, "%s.d", sam_name);
+               dirname = ldb_relative_path(ldb,
+                                           tmp_ctx,
+                                           "sam.ldb.d");
                if (!dirname) {
                        talloc_free(tmp_ctx);
                        return ldb_oom(ldb);
@@ -204,15 +242,28 @@ static int partition_metadata_open(struct ldb_module *module, bool create)
        lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
                                       struct loadparm_context);
 
-       data->metadata->db = tdb_wrap_open(data->metadata, filename, 10,
-                                             TDB_DEFAULT, open_flags, 0660,
-                                             lp_ctx);
+       tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT|TDB_SEQNUM);
+
+       ldb_flags = ldb_module_flags(ldb);
+
+       if (ldb_flags & LDB_FLG_NOSYNC) {
+               tdb_flags |= TDB_NOSYNC;
+       }
+
+       data->metadata->db = tdb_wrap_open(
+               data->metadata, filename, 10,
+               tdb_flags, open_flags, 0660);
        if (data->metadata->db == NULL) {
                talloc_free(tmp_ctx);
                if (create) {
-                       ldb_debug(ldb, LDB_DEBUG_ERROR,
-                                 "partition_metadata: Unable to create %s",
-                                 filename);
+                       ldb_asprintf_errstring(ldb, "partition_metadata: Unable to create %s: %s",
+                                              filename, strerror(errno));
+               } else {
+                       ldb_asprintf_errstring(ldb, "partition_metadata: Unable to open %s: %s",
+                                              filename, strerror(errno));
+               }
+               if (errno == EACCES || errno == EPERM) {
+                       return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
                }
                return LDB_ERR_OPERATIONS_ERROR;
        }
@@ -228,69 +279,14 @@ static int partition_metadata_open(struct ldb_module *module, bool create)
  */
 static int partition_metadata_set_sequence_number(struct ldb_module *module)
 {
-       struct partition_private_data *data;
-       struct ldb_result *res;
-       struct ldb_request *req;
-       struct ldb_seqnum_request *seq;
-       struct ldb_seqnum_result *seqr;
-       struct ldb_extended *ext;
-       TALLOC_CTX *tmp_ctx;
        int ret;
        uint64_t seq_number;
 
-       data = talloc_get_type_abort(ldb_module_get_private(module),
-                                   struct partition_private_data);
-       if (!data || !data->metadata) {
-               return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                       "partition_metadata: metadata not initialized");
-       }
-
-       tmp_ctx = talloc_new(data->metadata);
-       if (tmp_ctx == NULL) {
-               return ldb_module_oom(module);
-       }
-
-       res = talloc_zero(tmp_ctx, struct ldb_result);
-       if (res == NULL) {
-               talloc_free(tmp_ctx);
-               return ldb_module_oom(module);
-       }
-
-       seq = talloc_zero(tmp_ctx, struct ldb_seqnum_request);
-       if (seq == NULL) {
-               talloc_free(tmp_ctx);
-               return ldb_module_oom(module);
-       }
-       seq->type = LDB_SEQ_HIGHEST_SEQ;
-
-       /* Build an extended request, so it can be passed to each partition in
-          partition_sequence_number_from_partitions() */
-       ret = ldb_build_extended_req(&req,
-                                    ldb_module_get_ctx(module),
-                                    tmp_ctx,
-                                    LDB_EXTENDED_SEQUENCE_NUMBER,
-                                    seq,
-                                    NULL,
-                                    res,
-                                    ldb_extended_default_callback,
-                                    NULL);
-       LDB_REQ_SET_LOCATION(req);
+       ret = partition_sequence_number_from_partitions(module, &seq_number);
        if (ret != LDB_SUCCESS) {
-               talloc_free(tmp_ctx);
-               return ret;
-       }
-
-       ret = partition_sequence_number_from_partitions(module, req, &ext);
-       if (ret != LDB_SUCCESS) {
-               talloc_free(tmp_ctx);
                return ret;
        }
 
-       seqr = talloc_get_type_abort(ext->data, struct ldb_seqnum_result);
-       seq_number = seqr->seq_num;
-
-       talloc_free(tmp_ctx);
-
        return partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, seq_number, true);
 }
 
@@ -314,25 +310,25 @@ int partition_metadata_init(struct ldb_module *module)
 
        ret = partition_metadata_open(module, false);
        if (ret == LDB_SUCCESS) {
-               goto end;
+               /* Great, we got the DB open */
+               return LDB_SUCCESS;
        }
 
        /* metadata.tdb does not exist, create it */
-       DEBUG(2, ("partition_metadata: Migrating partition metadata\n"));
+       DEBUG(2, ("partition_metadata: Migrating partition metadata: "
+                 "open of metadata.tdb gave: %s\n",
+                 ldb_errstring(ldb_module_get_ctx(module))));
        ret = partition_metadata_open(module, true);
        if (ret != LDB_SUCCESS) {
-               talloc_free(data->metadata);
-               data->metadata = NULL;
-               goto end;
-       }
-
-       ret = partition_metadata_set_sequence_number(module);
-       if (ret != LDB_SUCCESS) {
-               talloc_free(data->metadata);
-               data->metadata = NULL;
+               ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                      "partition_metadata: "
+                                      "Migrating partition metadata: "
+                                      "create of metadata.tdb gave: %s\n",
+                                      ldb_errstring(ldb_module_get_ctx(module)));
+               TALLOC_FREE(data->metadata);
+               return ret;
        }
 
-end:
        return ret;
 }
 
@@ -342,10 +338,35 @@ end:
  */
 int partition_metadata_sequence_number(struct ldb_module *module, uint64_t *value)
 {
-       return partition_metadata_get_uint64(module,
-                                            LDB_METADATA_SEQ_NUM,
-                                            value,
-                                            0);
+
+       /* We have to lock all the databases as otherwise we can
+        * return a sequence number that is higher than the DB values
+        * that we can see, as those transactions close after the
+        * metadata.tdb transaction closes */
+       int ret = partition_read_lock(module);
+       if (ret != LDB_SUCCESS) {
+               return ret;
+       }
+
+       /*
+        * This means we will give a 0 until the first write
+        * tranaction, which is actually pretty reasonable.
+        *
+        * All modern databases will have the metadata.tdb from
+        * the time of the first transaction in provision anyway.
+        */
+       ret = partition_metadata_get_uint64(module,
+                                           LDB_METADATA_SEQ_NUM,
+                                           value,
+                                           0);
+       if (ret == LDB_SUCCESS) {
+               ret = partition_read_unlock(module);
+       } else {
+               /* Don't overwrite the error code */
+               partition_read_unlock(module);
+       }
+       return ret;
+
 }
 
 
@@ -374,6 +395,26 @@ int partition_metadata_sequence_number_increment(struct ldb_module *module, uint
                return ret;
        }
 
+       if (*value == 0) {
+               /*
+                * We are in a transaction now, so we can get the
+                * sequence number from the partitions.
+                */
+               ret = partition_metadata_set_sequence_number(module);
+               if (ret != LDB_SUCCESS) {
+                       TALLOC_FREE(data->metadata);
+                       partition_del_trans(module);
+                       return ret;
+               }
+
+               ret = partition_metadata_get_uint64(module,
+                                                   LDB_METADATA_SEQ_NUM,
+                                                   value, 0);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
        (*value)++;
        ret = partition_metadata_set_uint64(module, LDB_METADATA_SEQ_NUM, *value, false);
        return ret;
@@ -398,7 +439,7 @@ int partition_metadata_start_trans(struct ldb_module *module)
 
        if (tdb_transaction_start(tdb) != 0) {
                return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                       tdb_errorstr_compat(tdb));
+                                       tdb_errorstr(tdb));
        }
 
        data->metadata->in_transaction++;
@@ -430,7 +471,7 @@ int partition_metadata_prepare_commit(struct ldb_module *module)
 
        if (tdb_transaction_prepare_commit(tdb) != 0) {
                return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                       tdb_errorstr_compat(tdb));
+                                       tdb_errorstr(tdb));
        }
 
        return LDB_SUCCESS;
@@ -462,7 +503,7 @@ int partition_metadata_end_trans(struct ldb_module *module)
 
        if (tdb_transaction_commit(tdb) != 0) {
                return ldb_module_error(module, LDB_ERR_OPERATIONS_ERROR,
-                                       tdb_errorstr_compat(tdb));
+                                       tdb_errorstr(tdb));
        }
 
        return LDB_SUCCESS;