ldb: baseinfo pack format check on init
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Fri, 10 May 2019 06:10:51 +0000 (18:10 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 22 May 2019 04:42:28 +0000 (04:42 +0000)
We will be adding a new packing format in forthcoming commits and there
may be more versions in the future. We need to make sure the database
contains records in a format we know how to read and write.
Done by fetching the @BASEINFO record and reading the first 4
bytes which contain the packing format version.

NOTE: Configure with --abi-check-disable to build this commit. This
patch is part of a set of LDB ABI changes, and the version update is
done on the last commit.

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
lib/ldb/common/ldb_pack.c
lib/ldb/include/ldb_module.h
lib/ldb/ldb_key_value/ldb_kv.c
lib/ldb/ldb_key_value/ldb_kv.h
lib/ldb/ldb_key_value/ldb_kv_cache.c

index 5360a36ccccfa5c50b29a9016f75d87e4848406a..e59c542fc5b3429927f1ce17cec3afc8f9d29af3 100644 (file)
 
 #include "ldb_private.h"
 
-/* change this if the data format ever changes */
-#define LDB_PACKING_FORMAT 0x26011967
-
-/* old packing formats */
-#define LDB_PACKING_FORMAT_NODN 0x26011966
-
 /* use a portable integer format */
 static void put_uint32(uint8_t *p, int ofs, unsigned int val)
 {
@@ -195,7 +189,7 @@ int ldb_unpack_data_flags(struct ldb_context *ldb,
        size_t remaining;
        size_t dn_len;
        unsigned int i, j;
-       unsigned format;
+       uint32_t format;
        unsigned int nelem = 0;
        size_t len;
        struct ldb_val *ldb_val_single_array = NULL;
@@ -208,7 +202,10 @@ int ldb_unpack_data_flags(struct ldb_context *ldb,
                goto failed;
        }
 
-       format = pull_uint32(p, 0);
+       if (ldb_unpack_get_format(data, &format) != LDB_SUCCESS) {
+               errno = EIO;
+               goto failed;
+       }
        message->num_elements = pull_uint32(p, 4);
        p += 8;
 
@@ -402,6 +399,16 @@ failed:
        return -1;
 }
 
+int ldb_unpack_get_format(const struct ldb_val *data,
+                         uint32_t *pack_format_version)
+{
+       if (data->length < 4) {
+               return LDB_ERR_OPERATIONS_ERROR;
+       }
+       *pack_format_version = pull_uint32(data->data, 0);
+       return LDB_SUCCESS;
+}
+
 /*
  * Unpack a ldb message from a linear buffer in ldb_val
  *
index 759a54a3169f91de091df2cf89b6da5a3a501901..d9114e99e3435a976fff44549ce934fcd7d605e7 100644 (file)
@@ -544,12 +544,21 @@ int ldb_unpack_data_flags(struct ldb_context *ldb,
                          struct ldb_message *message,
                          unsigned int flags);
 
+int ldb_unpack_get_format(const struct ldb_val *data,
+                         uint32_t *pack_format_version);
+
 /* currently unused (was NO_DATA_ALLOC)      0x0001 */
 #define LDB_UNPACK_DATA_FLAG_NO_DN           0x0002
 #define LDB_UNPACK_DATA_FLAG_NO_VALUES_ALLOC 0x0004
 #define LDB_UNPACK_DATA_FLAG_NO_ATTRS        0x0008
 #define LDB_UNPACK_DATA_FLAG_READ_LOCKED     0x0010
 
+/* In-use packing formats */
+#define LDB_PACKING_FORMAT 0x26011967
+
+/* Old packing formats */
+#define LDB_PACKING_FORMAT_NODN 0x26011966
+
 /**
  Forces a specific ldb handle to use the global event context.
 
index 53c326d36b2e28f74ad042b25e86bd16e5a669a9..81a77462c8307d4e5bc68bc482d18ee3b93debfa 100644 (file)
@@ -1894,6 +1894,8 @@ int ldb_kv_init_store(struct ldb_kv_private *ldb_kv,
 
        ldb_kv->sequence_number = 0;
 
+       ldb_kv->pack_format_version = LDB_PACKING_FORMAT;
+
        ldb_kv->pid = getpid();
 
        ldb_kv->module = ldb_module_new(ldb, ldb, name, &ldb_kv_ops);
index 97bdcf0987503dd7ea0b8b7a00677655edbbbfb0..c9e55321d0d612961a82cdc283171f67afaf72d0 100644 (file)
@@ -63,6 +63,7 @@ struct ldb_kv_private {
        unsigned int connect_flags;
 
        unsigned long long sequence_number;
+       uint32_t pack_format_version;
 
        /* the low level tdb seqnum - used to avoid loading BASEINFO when
           possible */
index b14697c2a5e1dee82cec25a19c6ba5d46d414edf..c5f661113fd543fac0e22eb5b2f466226a82895b 100644 (file)
@@ -395,6 +395,13 @@ int ldb_kv_cache_reload(struct ldb_module *module)
        ldb_kv_cache_free(module);
        return ldb_kv_cache_load(module);
 }
+static int get_pack_format_version(struct ldb_val key,
+                                  struct ldb_val data,
+                                  void *private_data)
+{
+       uint32_t *v = (uint32_t *) private_data;
+       return ldb_unpack_get_format(&data, v);
+}
 
 /*
   load the cache records
@@ -411,6 +418,8 @@ int ldb_kv_cache_load(struct ldb_module *module)
        const struct ldb_schema_attribute *a;
        bool have_write_txn = false;
        int r;
+       uint32_t pack_format_version;
+       struct ldb_val key;
 
        ldb = ldb_module_get_ctx(module);
 
@@ -435,6 +444,34 @@ int ldb_kv_cache_load(struct ldb_module *module)
        if (r != LDB_SUCCESS) {
                goto failed;
        }
+
+       key = ldb_kv_key_dn(module, baseinfo, baseinfo_dn);
+       if (!key.data) {
+               goto failed_and_unlock;
+       }
+
+       /* Read packing format from first 4 bytes of @BASEINFO record */
+       r = ldb_kv->kv_ops->fetch_and_parse(ldb_kv, key,
+                                           get_pack_format_version,
+                                           &pack_format_version);
+
+       if (r != LDB_ERR_NO_SUCH_OBJECT) {
+               if (r != LDB_SUCCESS) {
+                       goto failed_and_unlock;
+               }
+
+               /* Make sure the database has the right format */
+               if (pack_format_version != ldb_kv->pack_format_version) {
+                       ldb_debug(ldb, LDB_DEBUG_ERROR,
+                                 "Unexpected packing format. "
+                                 "Expected: %#010x, Got: %#010x",
+                                 pack_format_version,
+                                 ldb_kv->pack_format_version);
+                       goto failed_and_unlock;
+               }
+       }
+
+       /* Now fetch the whole @BASEINFO record */
        r = ldb_kv_search_dn1(module, baseinfo_dn, baseinfo, 0);
        if (r != LDB_SUCCESS && r != LDB_ERR_NO_SUCH_OBJECT) {
                goto failed_and_unlock;