lib/tdb: maintain reference hashes with the hash function that's used at create time
authorStefan Metzmacher <metze@samba.org>
Thu, 9 Sep 2010 13:45:51 +0000 (15:45 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Apr 2011 15:59:20 +0000 (17:59 +0200)
If the hashes are available and the current hash function can't verify
them, we reject the open.

metze

lib/tdb/common/open.c
lib/tdb/common/tdb_private.h

index 49b8e85f1264f00c57e874916972350712b8a437..ff0fd376017b5c3db6764b4d2ade71d65814f384 100644 (file)
@@ -52,6 +52,7 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size)
        size_t size;
        int ret = -1;
        ssize_t written;
+       TDB_DATA hash_key;
 
        /* We make it up in memory, then write it out if not internal */
        size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t);
@@ -61,6 +62,15 @@ static int tdb_new_database(struct tdb_context *tdb, int hash_size)
        /* Fill in the header */
        newdb->version = TDB_VERSION;
        newdb->hash_size = hash_size;
+
+       hash_key.dptr = discard_const_p(uint8_t, TDB_MAGIC_FOOD);
+       hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
+       newdb->magic_food_hash = tdb->hash_fn(&hash_key);
+
+       hash_key.dptr = discard_const_p(uint8_t, TDB_MAGIC_HASH_VERIFY_KEY);
+       hash_key.dsize = sizeof(TDB_MAGIC_HASH_VERIFY_KEY);
+       newdb->verify_key_hash = tdb->hash_fn(&hash_key);
+
        if (tdb->flags & TDB_INTERNAL) {
                tdb->map_size = size;
                tdb->map_ptr = (char *)newdb;
@@ -153,6 +163,10 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
        unsigned char *vp;
        uint32_t vertest;
        unsigned v;
+       TDB_DATA hash_key;
+       uint32_t magic_food_hash;
+       uint32_t verify_key_hash;
+       const char *hash_alg;
 
        if (!(tdb = (struct tdb_context *)calloc(1, sizeof *tdb))) {
                /* Can't log this */
@@ -171,7 +185,14 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                tdb->log.log_fn = null_log_fn;
                tdb->log.log_private = NULL;
        }
-       tdb->hash_fn = hash_fn ? hash_fn : default_tdb_hash;
+
+       if (hash_fn) {
+               tdb->hash_fn = hash_fn;
+               hash_alg = "user_defined";
+       } else {
+               tdb->hash_fn = default_tdb_hash;
+               hash_alg = "default";
+       }
 
        /* cache the page size */
        tdb->page_size = getpagesize();
@@ -270,6 +291,35 @@ struct tdb_context *tdb_open_ex(const char *name, int hash_size, int tdb_flags,
                goto fail;
        }
 
+       hash_key.dptr = discard_const_p(uint8_t, TDB_MAGIC_FOOD);
+       hash_key.dsize = sizeof(TDB_MAGIC_FOOD);
+       magic_food_hash = tdb->hash_fn(&hash_key);
+
+       hash_key.dptr = discard_const_p(uint8_t, TDB_MAGIC_HASH_VERIFY_KEY);
+       hash_key.dsize = sizeof(TDB_MAGIC_HASH_VERIFY_KEY);
+       verify_key_hash = tdb->hash_fn(&hash_key);
+
+       if ((tdb->header.magic_food_hash == 0) &&
+           (tdb->header.verify_key_hash == 0)) {
+               /* older TDB without magic hash references */
+       } else if ((tdb->header.magic_food_hash != magic_food_hash) ||
+                  (tdb->header.verify_key_hash != verify_key_hash)) {
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_open_ex: %s "
+                        "was created with a different hash function current[%s]"
+                        "magic_food_hash[0x%08X %s 0x%08X] "
+                        "verify_key_hash[0x%08X %s 0x%08X]\n",
+                        name,
+                        hash_alg,
+                        tdb->header.magic_food_hash,
+                        (tdb->header.magic_food_hash == magic_food_hash)?"==":"!=",
+                        magic_food_hash,
+                        tdb->header.verify_key_hash,
+                        (tdb->header.verify_key_hash == verify_key_hash)?"==":"!=",
+                        verify_key_hash));
+               errno = EINVAL;
+               goto fail;
+       }
+
        /* Is it already in the open list?  If so, fail. */
        if (tdb_already_open(st.st_dev, st.st_ino)) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_open_ex: "
index 562b813ff115c4002a16c771ca6ed1172322b074..226ace279c50fca9282a2e9fe246c7021b1acd97 100644 (file)
@@ -48,6 +48,7 @@ typedef uint32_t tdb_off_t;
 #define TDB_FREE_MAGIC (~TDB_MAGIC)
 #define TDB_DEAD_MAGIC (0xFEE1DEAD)
 #define TDB_RECOVERY_MAGIC (0xf53bc0e7U)
+#define TDB_MAGIC_HASH_VERIFY_KEY "!TDB_MAGIC_HASH_VERIFY_KEY!"
 #define TDB_ALIGNMENT 4
 #define DEFAULT_HASH_SIZE 131
 #define FREELIST_TOP (sizeof(struct tdb_header))
@@ -114,7 +115,9 @@ struct tdb_header {
        tdb_off_t rwlocks; /* obsolete - kept to detect old formats */
        tdb_off_t recovery_start; /* offset of transaction recovery region */
        tdb_off_t sequence_number; /* used when TDB_SEQNUM is set */
-       tdb_off_t reserved[29];
+       uint32_t magic_food_hash;
+       uint32_t verify_key_hash;
+       tdb_off_t reserved[27];
 };
 
 struct tdb_lock_type {