s3-registry: fix bug #8401 - registry/reg_format.c must include includes.h.
[kai/samba.git] / source3 / registry / reg_backend_db.c
index 387089f621b63ee75e401a7aaad2bc38d628ca9f..4e10bf652a5adf7e77950cfac74b4019770fffd1 100644 (file)
@@ -2,7 +2,8 @@
  *  Unix SMB/CIFS implementation.
  *  Virtual Windows Registry Layer
  *  Copyright (C) Gerald Carter                     2002-2005
- *  Copyright (C) Michael Adam                      2007-2009
+ *  Copyright (C) Michael Adam                      2007-2011
+ *  Copyright (C) Gregor Beck                       2011
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,7 +30,8 @@
 #include "reg_objects.h"
 #include "nt_printing.h"
 #include "util_tdb.h"
-#include "dbwrap.h"
+#include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_open.h"
 #include "../libcli/security/secdesc.h"
 
 #undef DBGC_CLASS
@@ -39,7 +41,6 @@ static struct db_context *regdb = NULL;
 static int regdb_refcount;
 
 static bool regdb_key_exists(struct db_context *db, const char *key);
-static bool regdb_key_is_base_key(const char *key);
 static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
                                        struct regsubkey_ctr *ctr);
 static bool regdb_store_keys_internal(struct db_context *db, const char *key,
@@ -1286,6 +1287,7 @@ struct regdb_delete_subkey_context {
        const char *key;
        const char *subkey;
        const char *path;
+       bool lazy;
 };
 
 static NTSTATUS regdb_delete_subkey_action(struct db_context *db,
@@ -1301,6 +1303,10 @@ static NTSTATUS regdb_delete_subkey_action(struct db_context *db,
        werr = regdb_delete_key_lists(db, delete_ctx->path);
        W_ERROR_NOT_OK_GOTO_DONE(werr);
 
+       if (delete_ctx->lazy) {
+               goto done;
+       }
+
        werr = regsubkey_ctr_init(mem_ctx, &subkeys);
        W_ERROR_NOT_OK_GOTO_DONE(werr);
 
@@ -1322,7 +1328,7 @@ done:
        return werror_to_ntstatus(werr);
 }
 
-static WERROR regdb_delete_subkey(const char *key, const char *subkey)
+static WERROR regdb_delete_subkey(const char *key, const char *subkey, bool lazy)
 {
        WERROR werr;
        char *path;
@@ -1348,6 +1354,7 @@ static WERROR regdb_delete_subkey(const char *key, const char *subkey)
        delete_ctx.key = key;
        delete_ctx.subkey = subkey;
        delete_ctx.path = path;
+       delete_ctx.lazy = lazy;
 
        werr = ntstatus_to_werror(dbwrap_trans_do(regdb,
                                                  regdb_delete_subkey_action,
@@ -1377,14 +1384,27 @@ static TDB_DATA regdb_fetch_key_internal(struct db_context *db,
 
 
 /**
- * check whether a given key name represents a base key,
- * i.e one without a subkey separator ('\').
+ * Check for the existence of a key.
+ *
+ * Existence of a key is authoritatively defined by
+ * the existence of the record that contains the list
+ * of its subkeys.
+ *
+ * Return false, if the record does not match the correct
+ * structure of an initial 4-byte counter and then a
+ * list of the corresponding number of zero-terminated
+ * strings.
  */
-static bool regdb_key_is_base_key(const char *key)
+static bool regdb_key_exists(struct db_context *db, const char *key)
 {
        TALLOC_CTX *mem_ctx = talloc_stackframe();
+       TDB_DATA value;
        bool ret = false;
        char *path;
+       uint32_t buflen;
+       const char *buf;
+       uint32_t num_items, i;
+       int32_t len;
 
        if (key == NULL) {
                goto done;
@@ -1400,43 +1420,70 @@ static bool regdb_key_is_base_key(const char *key)
                goto done;
        }
 
-       ret = (strrchr(path, '\\') == NULL);
-
-done:
-       TALLOC_FREE(mem_ctx);
-       return ret;
-}
+       value = regdb_fetch_key_internal(db, mem_ctx, path);
+       if (value.dptr == NULL) {
+               goto done;
+       }
 
-/**
- * Check for the existence of a key.
- *
- * Existence of a key is authoritatively defined by
- * the existence of the record that contains the list
- * of its subkeys.
- */
-static bool regdb_key_exists(struct db_context *db, const char *key)
-{
-       TALLOC_CTX *mem_ctx = talloc_stackframe();
-       TDB_DATA value;
-       bool ret = false;
-       char *path;
+       if (value.dsize == 0) {
+               DEBUG(10, ("regdb_key_exists: subkeylist-record for key "
+                         "[%s] is empty: Could be a deleted record in a "
+                         "clustered (ctdb) environment?\n",
+                         path));
+               goto done;
+       }
 
-       if (key == NULL) {
+       len = tdb_unpack(value.dptr, value.dsize, "d", &num_items);
+       if (len == (int32_t)-1) {
+               DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
+                         "[%s] is invalid: Could not parse initial 4-byte "
+                         "counter. record data length is %u.\n",
+                         path, (unsigned int)value.dsize));
                goto done;
        }
 
-       path = normalize_reg_path(mem_ctx, key);
-       if (path == NULL) {
-               DEBUG(0, ("out of memory! (talloc failed)\n"));
+       /*
+        * Note: the tdb_unpack check above implies that len <= value.dsize
+        */
+       buflen = value.dsize - len;
+       buf = (const char *)value.dptr + len;
+
+       len = 0;
+
+       for (i = 0; i < num_items; i++) {
+               if (buflen == 0) {
+                       break;
+               }
+               len = strnlen(buf, buflen) + 1;
+               if (buflen < len) {
+                       DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record "
+                                 "for key [%s] is corrupt: %u items expected, "
+                                 "item number %u is not zero terminated.\n",
+                                 path, num_items, i+1));
+                       goto done;
+               }
+
+               buf += len;
+               buflen -= len;
+       }
+
+       if (buflen > 0) {
+               DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
+                         "[%s] is corrupt: %u items expected and found, but "
+                         "the record contains additional %u bytes\n",
+                         path, num_items, buflen));
                goto done;
        }
 
-       if (*path == '\0') {
+       if (i < num_items) {
+               DEBUG(1, ("regdb_key_exists: ERROR: subkeylist-record for key "
+                         "[%s] is corrupt: %u items expected, but only %u "
+                         "items found.\n",
+                         path, num_items, i+1));
                goto done;
        }
 
-       value = regdb_fetch_key_internal(db, mem_ctx, path);
-       ret = (value.dptr != NULL);
+       ret = true;
 
 done:
        TALLOC_FREE(mem_ctx);
@@ -1469,6 +1516,9 @@ static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
                goto done;
        }
 
+       werr = regsubkey_ctr_reinit(ctr);
+       W_ERROR_NOT_OK_GOTO_DONE(werr);
+
        werr = regsubkey_ctr_set_seqnum(ctr, db->get_seqnum(db));
        W_ERROR_NOT_OK_GOTO_DONE(werr);
 
@@ -1488,9 +1538,6 @@ static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
                goto done;
        }
 
-       werr = regsubkey_ctr_reinit(ctr);
-       W_ERROR_NOT_OK_GOTO_DONE(werr);
-
        for (i=0; i<num_items; i++) {
                len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
                werr = regsubkey_ctr_addkey(ctr, subkeyname);