s3:registry: create the empty list of subkeys of the new key in regdb_create_subkey
[metze/samba/wip.git] / source3 / registry / reg_backend_db.c
index 4aed6e73e17b35d670f0d571219f80c64ccf7c7b..34c25d83576f619056a4a2bb3d670a29767fd751 100644 (file)
@@ -28,7 +28,9 @@
 #include "reg_backend_db.h"
 #include "reg_objects.h"
 #include "nt_printing.h"
+#include "util_tdb.h"
 #include "dbwrap.h"
+#include "../libcli/security/secdesc.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_REGISTRY
@@ -47,6 +49,8 @@ static int regdb_fetch_values_internal(struct db_context *db, const char* key,
 static bool regdb_store_values_internal(struct db_context *db, const char *key,
                                        struct regval_ctr *values);
 
+static NTSTATUS create_sorted_subkeys(const char *key);
+
 /* List the deepest path into the registry.  All part components will be created.*/
 
 /* If you want to have a part of the path controlled by the tdb and part by
@@ -478,7 +482,7 @@ static WERROR regdb_upgrade_v1_to_v2(void)
 
        talloc_destroy(mem_ctx);
 
-       if (rc == -1) {
+       if (rc < 0) {
                return WERR_REG_IO_FAILURE;
        }
 
@@ -708,6 +712,13 @@ static WERROR regdb_delete_subkeylist(struct db_context *db, const char *keyname
        return regdb_delete_key_with_prefix(db, keyname, NULL);
 }
 
+static WERROR regdb_delete_sorted_subkeys(struct db_context *db,
+                                         const char *keyname)
+{
+       return regdb_delete_key_with_prefix(db, keyname, REG_SORTED_SUBKEYS_PREFIX);
+}
+
+
 static WERROR regdb_delete_key_lists(struct db_context *db, const char *keyname)
 {
        WERROR werr;
@@ -726,6 +737,14 @@ static WERROR regdb_delete_key_lists(struct db_context *db, const char *keyname)
                goto done;
        }
 
+       werr = regdb_delete_sorted_subkeys(db, keyname);
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(1, (__location__ " Deleting %s\\%s failed: %s\n",
+                         REG_SORTED_SUBKEYS_PREFIX, keyname,
+                         win_errstr(werr)));
+               goto done;
+       }
+
        werr = regdb_delete_subkeylist(db, keyname);
        if (!W_ERROR_IS_OK(werr)) {
                DEBUG(1, (__location__ " Deleting %s failed: %s\n",
@@ -828,29 +847,57 @@ static WERROR regdb_store_keys_internal2(struct db_context *db,
        dbuf.dsize = len;
        werr = ntstatus_to_werror(dbwrap_store_bystring(db, keyname, dbuf,
                                                        TDB_REPLACE));
-       W_ERROR_NOT_OK_GOTO_DONE(werr);
 
-       /*
-        * Delete a sorted subkey cache for regdb_key_exists, will be
-        * recreated automatically
-        */
-       keyname = talloc_asprintf(ctx, "%s\\%s", REG_SORTED_SUBKEYS_PREFIX,
-                                 keyname);
-       if (keyname == NULL) {
+done:
+       TALLOC_FREE(ctx);
+       SAFE_FREE(buffer);
+       return werr;
+}
+
+/**
+ * Utility function to store a new empty list of
+ * subkeys of given key specified as parent and subkey name
+ * (thereby creating the key).
+ * If the subkey list does already exist, it is not modified.
+ *
+ * Must be called from within a transaction.
+ */
+static WERROR regdb_store_subkey_list(struct db_context *db, const char *parent,
+                                     const char *key)
+{
+       WERROR werr;
+       char *path = NULL;
+       struct regsubkey_ctr *subkeys = NULL;
+       TALLOC_CTX *frame = talloc_stackframe();
+
+       path = talloc_asprintf(frame, "%s\\%s", parent, key);
+       if (!path) {
                werr = WERR_NOMEM;
                goto done;
        }
 
-       werr = ntstatus_to_werror(dbwrap_delete_bystring(db, keyname));
+       werr = regsubkey_ctr_init(frame, &subkeys);
+       W_ERROR_NOT_OK_GOTO_DONE(werr);
 
-       /* don't treat WERR_NOT_FOUND as an error here */
-       if (W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) {
-               werr = WERR_OK;
+       werr = regdb_fetch_keys_internal(db, path, subkeys);
+       if (W_ERROR_IS_OK(werr)) {
+               /* subkey list exists already - don't modify */
+               goto done;
+       }
+
+       werr = regsubkey_ctr_reinit(subkeys);
+       W_ERROR_NOT_OK_GOTO_DONE(werr);
+
+       /* create a record with 0 subkeys */
+       werr = regdb_store_keys_internal2(db, path, subkeys);
+       if (!W_ERROR_IS_OK(werr)) {
+               DEBUG(0, ("regdb_store_keys: Failed to store new record for "
+                         "key [%s]: %s\n", path, win_errstr(werr)));
+               goto done;
        }
 
 done:
-       TALLOC_FREE(ctx);
-       SAFE_FREE(buffer);
+       talloc_free(frame);
        return werr;
 }
 
@@ -871,7 +918,7 @@ static NTSTATUS regdb_store_keys_action(struct db_context *db,
        WERROR werr;
        int num_subkeys, i;
        char *path = NULL;
-       struct regsubkey_ctr *subkeys = NULL, *old_subkeys = NULL;
+       struct regsubkey_ctr *old_subkeys = NULL;
        char *oldkeyname = NULL;
        TALLOC_CTX *mem_ctx = talloc_stackframe();
 
@@ -954,44 +1001,13 @@ static NTSTATUS regdb_store_keys_action(struct db_context *db,
 
        num_subkeys = regsubkey_ctr_numkeys(store_ctx->ctr);
 
-       if (num_subkeys == 0) {
-               werr = regsubkey_ctr_init(mem_ctx, &subkeys);
-               W_ERROR_NOT_OK_GOTO_DONE(werr);
-
-               werr = regdb_store_keys_internal2(db, store_ctx->key, subkeys);
-               if (!W_ERROR_IS_OK(werr)) {
-                       DEBUG(0,("regdb_store_keys: Failed to store "
-                                "new record for key [%s]: %s\n",
-                                store_ctx->key, win_errstr(werr)));
-                       goto done;
-               }
-               TALLOC_FREE(subkeys);
-       }
-
        for (i=0; i<num_subkeys; i++) {
-               path = talloc_asprintf(mem_ctx, "%s\\%s", store_ctx->key,
-                               regsubkey_ctr_specific_key(store_ctx->ctr, i));
-               if (!path) {
-                       werr = WERR_NOMEM;
-                       goto done;
-               }
-               werr = regsubkey_ctr_init(mem_ctx, &subkeys);
-               W_ERROR_NOT_OK_GOTO_DONE(werr);
+               const char *subkey;
 
-               werr = regdb_fetch_keys_internal(db, path, subkeys);
-               if (!W_ERROR_IS_OK(werr)) {
-                       /* create a record with 0 subkeys */
-                       werr = regdb_store_keys_internal2(db, path, subkeys);
-                       if (!W_ERROR_IS_OK(werr)) {
-                               DEBUG(0,("regdb_store_keys: Failed to store "
-                                        "new record for key [%s]: %s\n", path,
-                                        win_errstr(werr)));
-                               goto done;
-                       }
-               }
+               subkey = regsubkey_ctr_specific_key(store_ctx->ctr, i);
 
-               TALLOC_FREE(subkeys);
-               TALLOC_FREE(path);
+               werr = regdb_store_subkey_list(db, store_ctx->key, subkey);
+               W_ERROR_NOT_OK_GOTO_DONE(werr);
        }
 
        werr = WERR_OK;
@@ -1011,7 +1027,7 @@ static bool regdb_store_keys_internal(struct db_context *db, const char *key,
        bool ret = false;
        struct regdb_store_keys_context store_ctx;
 
-       if (!regdb_key_is_base_key(key) && !regdb_key_exists(db, key)) {
+       if (!regdb_key_exists(db, key)) {
                goto done;
        }
 
@@ -1114,6 +1130,8 @@ static NTSTATUS regdb_create_subkey_action(struct db_context *db,
                         win_errstr(werr)));
        }
 
+       werr = regdb_store_subkey_list(db, create_ctx->key, create_ctx->subkey);
+
 done:
        talloc_free(mem_ctx);
        return werror_to_ntstatus(werr);
@@ -1126,7 +1144,7 @@ static WERROR regdb_create_subkey(const char *key, const char *subkey)
        TALLOC_CTX *mem_ctx = talloc_stackframe();
        struct regdb_create_subkey_context create_ctx;
 
-       if (!regdb_key_is_base_key(key) && !regdb_key_exists(regdb, key)) {
+       if (!regdb_key_exists(regdb, key)) {
                werr = WERR_NOT_FOUND;
                goto done;
        }
@@ -1207,7 +1225,7 @@ static WERROR regdb_delete_subkey(const char *key, const char *subkey)
        struct regdb_delete_subkey_context delete_ctx;
        TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-       if (!regdb_key_is_base_key(key) && !regdb_key_exists(regdb, key)) {
+       if (!regdb_key_exists(regdb, key)) {
                werr = WERR_NOT_FOUND;
                goto done;
        }
@@ -1310,7 +1328,7 @@ done:
 
 static int cmp_keynames(char **p1, char **p2)
 {
-       return StrCaseCmp(*p1, *p2);
+       return strcasecmp_m(*p1, *p2);
 }
 
 struct create_sorted_subkeys_context {
@@ -1407,7 +1425,8 @@ done:
        return status;
 }
 
-static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
+static NTSTATUS create_sorted_subkeys_internal(const char *key,
+                                              const char *sorted_keyname)
 {
        NTSTATUS status;
        struct create_sorted_subkeys_context sorted_ctx;
@@ -1419,7 +1438,26 @@ static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
                                 create_sorted_subkeys_action,
                                 &sorted_ctx);
 
-       return NT_STATUS_IS_OK(status);
+       return status;
+}
+
+static NTSTATUS create_sorted_subkeys(const char *key)
+{
+       char *sorted_subkeys_keyname;
+       NTSTATUS status;
+
+       sorted_subkeys_keyname = talloc_asprintf(talloc_tos(), "%s\\%s",
+                                                REG_SORTED_SUBKEYS_PREFIX,
+                                                key);
+       if (sorted_subkeys_keyname == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto done;
+       }
+
+       status = create_sorted_subkeys_internal(key, sorted_subkeys_keyname);
+
+done:
+       return status;
 }
 
 struct scan_subkey_state {
@@ -1499,13 +1537,21 @@ static bool scan_parent_subkeys(struct db_context *db, const char *parent,
        if (state.scanned) {
                result = state.found;
        } else {
+               NTSTATUS status;
+
                res = db->transaction_start(db);
                if (res != 0) {
-                       DEBUG(0, ("error starting transacion\n"));
+                       DEBUG(0, ("error starting transaction\n"));
                        goto fail;
                }
 
-               if (!create_sorted_subkeys(path, key)) {
+               DEBUG(2, (__location__ " WARNING: recreating the sorted "
+                         "subkeys cache for key '%s' from scan_parent_subkeys "
+                         "this should not happen (too frequently)...\n",
+                         path));
+
+               status = create_sorted_subkeys_internal(path, key);
+               if (!NT_STATUS_IS_OK(status)) {
                        res = db->transaction_cancel(db);
                        if (res != 0) {
                                smb_panic("Failed to cancel transaction.");
@@ -1596,8 +1642,6 @@ static WERROR regdb_fetch_keys_internal(struct db_context *db, const char *key,
 
        DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL"));
 
-       frame = talloc_stackframe();
-
        if (!regdb_key_exists(db, key)) {
                DEBUG(10, ("key [%s] not found\n", key));
                werr = WERR_NOT_FOUND;
@@ -1803,7 +1847,7 @@ static bool regdb_store_values_internal(struct db_context *db, const char *key,
                goto done;
        }
 
-       data.dptr = TALLOC_ARRAY(ctx, uint8, len);
+       data.dptr = talloc_array(ctx, uint8, len);
        data.dsize = len;
 
        len = regdb_pack_values(values, data.dptr, data.dsize);