s3:registry: update the seqnum in the subkey cache at the end of regval_store_keys
[ddiss/samba.git] / source3 / registry / reg_backend_db.c
index 9a0e632472c27af98401e529826aa2a0741b1b4b..e0fe7c121151b23f70293f155de2c6ba788b4aa5 100644 (file)
 /* Implementation of internal registry database functions. */
 
 #include "includes.h"
-
+#include "system/filesys.h"
 #include "registry.h"
 #include "reg_db.h"
 #include "reg_util_internal.h"
 #include "reg_backend_db.h"
 #include "reg_objects.h"
+#include "nt_printing.h"
+#include "util_tdb.h"
+#include "dbwrap.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_REGISTRY
@@ -45,6 +48,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
@@ -59,6 +64,9 @@ static const char *builtin_registry_paths[] = {
        KEY_PRINTING_2K,
        KEY_PRINTING_PORTS,
        KEY_PRINTING,
+       KEY_PRINTING "\\Forms",
+       KEY_PRINTING "\\Printers",
+       KEY_PRINTING "\\Environments\\Windows NT x86\\Print Processors\\winprint",
        KEY_SHARES,
        KEY_EVENTLOG,
        KEY_SMBCONF,
@@ -99,7 +107,7 @@ static struct builtin_regkey_value builtin_registry_values[] = {
        { KEY_PRINTING_2K,
                "DefaultSpoolDirectory", REG_SZ, { "C:\\Windows\\System32\\Spool\\Printers" } },
        { KEY_EVENTLOG,
-               "DisplayName", REG_SZ, { "Event Log" } }, 
+               "DisplayName", REG_SZ, { "Event Log" } },
        { KEY_EVENTLOG,
                "ErrorControl", REG_DWORD, { (char*)0x00000001 } },
        { NULL, NULL, 0, { NULL } }
@@ -312,7 +320,7 @@ static NTSTATUS init_registry_data_action(struct db_context *db,
 
                /* preserve existing values across restarts. Only add new ones */
 
-               if (!regval_ctr_key_exists(values,
+               if (!regval_ctr_value_exists(values,
                                        builtin_registry_values[i].valuename))
                {
                        regdb_ctr_add_value(values,
@@ -356,7 +364,7 @@ WERROR init_registry_data(void)
                regdb_fetch_values_internal(regdb,
                                            builtin_registry_values[i].path,
                                            values);
-               if (!regval_ctr_key_exists(values,
+               if (!regval_ctr_value_exists(values,
                                        builtin_registry_values[i].valuename))
                {
                        TALLOC_FREE(values);
@@ -412,10 +420,8 @@ static int regdb_normalize_keynames_fn(struct db_record *rec,
                          (const char *) rec->key.dptr,
                          keyname));
 
-               new_rec.value.dptr = rec->value.dptr;
-               new_rec.value.dsize = rec->value.dsize;
-               new_rec.key.dptr = (unsigned char *) keyname;
-               new_rec.key.dsize = strlen(keyname);
+               new_rec.value = rec->value;
+               new_rec.key = string_term_tdb_data(keyname);
                new_rec.private_data = rec->private_data;
 
                /* Delete the original record and store the normalized key */
@@ -439,10 +445,32 @@ static int regdb_normalize_keynames_fn(struct db_record *rec,
        return 0;
 }
 
-static WERROR regdb_upgrade_to_version_2(void)
+static WERROR regdb_store_regdb_version(uint32_t version)
+{
+       NTSTATUS status;
+       const char *version_keyname = "INFO/version";
+
+       if (!regdb) {
+               return WERR_CAN_NOT_COMPLETE;
+       }
+
+       status = dbwrap_trans_store_int32(regdb, version_keyname, version);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("regdb_store_regdb_version: error storing %s = %d: %s\n",
+                         version_keyname, version, nt_errstr(status)));
+               return ntstatus_to_werror(status);
+       } else {
+               DEBUG(10, ("regdb_store_regdb_version: stored %s = %d\n",
+                         version_keyname, version));
+               return WERR_OK;
+       }
+}
+
+static WERROR regdb_upgrade_v1_to_v2(void)
 {
        TALLOC_CTX *mem_ctx;
        int rc;
+       WERROR werr;
 
        mem_ctx = talloc_stackframe();
        if (mem_ctx == NULL) {
@@ -452,7 +480,13 @@ static WERROR regdb_upgrade_to_version_2(void)
        rc = regdb->traverse(regdb, regdb_normalize_keynames_fn, mem_ctx);
 
        talloc_destroy(mem_ctx);
-       return (rc == -1 ? WERR_REG_IO_FAILURE : WERR_OK);
+
+       if (rc == -1) {
+               return WERR_REG_IO_FAILURE;
+       }
+
+       werr = regdb_store_regdb_version(REGVER_V2);
+       return werr;
 }
 
 /***********************************************************************
@@ -466,8 +500,8 @@ WERROR regdb_init(void)
        WERROR werr;
 
        if (regdb) {
-               DEBUG(10, ("regdb_init: incrementing refcount (%d)\n",
-                         regdb_refcount));
+               DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n",
+                          regdb_refcount, regdb_refcount+1));
                regdb_refcount++;
                return WERR_OK;
        }
@@ -483,33 +517,24 @@ WERROR regdb_init(void)
                                state_path("registry.tdb"), strerror(errno) ));
                        return werr;
                }
-               
+
                DEBUG(10,("regdb_init: Successfully created registry tdb\n"));
        }
 
        regdb_refcount = 1;
+       DEBUG(10, ("regdb_init: registry db openend. refcount reset (%d)\n",
+                  regdb_refcount));
 
        expected_version = REGVER_V2;
 
        vers_id = dbwrap_fetch_int32(regdb, vstring);
        if (vers_id == -1) {
-               NTSTATUS status;
-
                DEBUG(10, ("regdb_init: registry version uninitialized "
                           "(got %d), initializing to version %d\n",
                           vers_id, expected_version));
 
-               status = dbwrap_trans_store_int32(regdb, vstring, REGVER_V2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(1, ("regdb_init: error storing %s = %d: %s\n",
-                                 vstring, expected_version, nt_errstr(status)));
-                       return ntstatus_to_werror(status);
-               } else {
-                       DEBUG(10, ("regdb_init: stored %s = %d\n",
-                                 vstring, expected_version));
-               }
-
-               return WERR_OK;
+               werr = regdb_store_regdb_version(expected_version);
+               return werr;
        }
 
        if (vers_id > expected_version || vers_id == 0) {
@@ -520,8 +545,6 @@ WERROR regdb_init(void)
        }
 
        if (vers_id == REGVER_V1) {
-               NTSTATUS status;
-
                DEBUG(10, ("regdb_init: got registry db version %d, upgrading "
                           "to version %d\n", REGVER_V1, REGVER_V2));
 
@@ -529,22 +552,12 @@ WERROR regdb_init(void)
                        return WERR_REG_IO_FAILURE;
                }
 
-               werr = regdb_upgrade_to_version_2();
+               werr = regdb_upgrade_v1_to_v2();
                if (!W_ERROR_IS_OK(werr)) {
                        regdb->transaction_cancel(regdb);
                        return werr;
                }
 
-               status = dbwrap_trans_store_int32(regdb, vstring, REGVER_V2);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(1, ("regdb_init: error storing %s = %d: %s\n",
-                                 vstring, REGVER_V2, nt_errstr(status)));
-                       regdb->transaction_cancel(regdb);
-                       return ntstatus_to_werror(status);
-               } else {
-                       DEBUG(10, ("regdb_init: stored %s = %d\n",
-                                 vstring, REGVER_V2));
-               }
                if (regdb->transaction_commit(regdb) != 0) {
                        return WERR_REG_IO_FAILURE;
                }
@@ -566,25 +579,27 @@ WERROR regdb_open( void )
        WERROR result = WERR_OK;
 
        if ( regdb ) {
-               DEBUG(10,("regdb_open: incrementing refcount (%d)\n", regdb_refcount));
+               DEBUG(10, ("regdb_open: incrementing refcount (%d->%d)\n",
+                          regdb_refcount, regdb_refcount+1));
                regdb_refcount++;
                return WERR_OK;
        }
-       
+
        become_root();
 
        regdb = db_open(NULL, state_path("registry.tdb"), 0,
                              REG_TDB_FLAGS, O_RDWR, 0600);
        if ( !regdb ) {
                result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
-               DEBUG(0,("regdb_open: Failed to open %s! (%s)\n", 
+               DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",
                        state_path("registry.tdb"), strerror(errno) ));
        }
 
        unbecome_root();
 
        regdb_refcount = 1;
-       DEBUG(10,("regdb_open: refcount reset (%d)\n", regdb_refcount));
+       DEBUG(10, ("regdb_open: registry db opened. refcount reset (%d)\n",
+                  regdb_refcount));
 
        return result;
 }
@@ -600,7 +615,8 @@ int regdb_close( void )
 
        regdb_refcount--;
 
-       DEBUG(10,("regdb_close: decrementing refcount (%d)\n", regdb_refcount));
+       DEBUG(10, ("regdb_close: decrementing refcount (%d->%d)\n",
+                  regdb_refcount+1, regdb_refcount));
 
        if ( regdb_refcount > 0 )
                return 0;
@@ -818,22 +834,9 @@ static WERROR regdb_store_keys_internal2(struct db_context *db,
        W_ERROR_NOT_OK_GOTO_DONE(werr);
 
        /*
-        * Delete a sorted subkey cache for regdb_key_exists, will be
-        * recreated automatically
+        * recreate the sorted subkey cache for regdb_key_exists()
         */
-       keyname = talloc_asprintf(ctx, "%s\\%s", REG_SORTED_SUBKEYS_PREFIX,
-                                 keyname);
-       if (keyname == NULL) {
-               werr = WERR_NOMEM;
-               goto done;
-       }
-
-       werr = ntstatus_to_werror(dbwrap_delete_bystring(db, keyname));
-
-       /* don't treat WERR_NOT_FOUND as an error here */
-       if (W_ERROR_EQUAL(werr, WERR_NOT_FOUND)) {
-               werr = WERR_OK;
-       }
+       werr = ntstatus_to_werror(create_sorted_subkeys(keyname));
 
 done:
        TALLOC_FREE(ctx);
@@ -981,7 +984,11 @@ static NTSTATUS regdb_store_keys_action(struct db_context *db,
                TALLOC_FREE(path);
        }
 
-       werr = WERR_OK;
+       /*
+        * Update the seqnum in the container to possibly
+        * prevent next read from going to disk
+        */
+       werr = regsubkey_ctr_set_seqnum(store_ctx->ctr, db->get_seqnum(db));
 
 done:
        talloc_free(mem_ctx);
@@ -1394,7 +1401,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;
@@ -1406,7 +1414,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 {
@@ -1486,13 +1513,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.");
@@ -1583,8 +1618,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;
@@ -1674,15 +1707,12 @@ static int regdb_unpack_values(struct regval_ctr *values, uint8 *buf, int buflen
                                  &size,
                                  &data_p);
 
-               /* add the new value. Paranoid protective code -- make sure data_p is valid */
-
-               if (size && data_p) {
-                       regval_ctr_addvalue(values, valuename, type,
-                                       (uint8_t *)data_p, size);
-               }
+               regval_ctr_addvalue(values, valuename, type,
+                               (uint8_t *)data_p, size);
                SAFE_FREE(data_p); /* 'B' option to tdb_unpack does a malloc() */
 
-               DEBUG(8,("specific: [%s], len: %d\n", valuename, size));
+               DEBUG(10, ("regdb_unpack_values: value[%d]: name[%s] len[%d]\n",
+                          i, valuename, size));
        }
 
        return len;
@@ -1736,7 +1766,7 @@ static int regdb_fetch_values_internal(struct db_context *db, const char* key,
        TDB_DATA value;
        WERROR werr;
 
-       DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key));
+       DEBUG(10,("regdb_fetch_values: Looking for values of key [%s]\n", key));
 
        if (!regdb_key_exists(db, key)) {
                goto done;
@@ -1779,8 +1809,9 @@ static bool regdb_store_values_internal(struct db_context *db, const char *key,
        int len;
        NTSTATUS status;
        bool result = false;
+       WERROR werr;
 
-       DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key));
+       DEBUG(10,("regdb_store_values: Looking for values of key [%s]\n", key));
 
        if (!regdb_key_exists(db, key)) {
                goto done;
@@ -1821,8 +1852,17 @@ static bool regdb_store_values_internal(struct db_context *db, const char *key,
        }
 
        status = dbwrap_trans_store_bystring(db, keystr, data, TDB_REPLACE);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("regdb_store_values_internal: error storing: %s\n", nt_errstr(status)));
+               goto done;
+       }
 
-       result = NT_STATUS_IS_OK(status);
+       /*
+        * update the seqnum in the cache to prevent the next read
+        * from going to disk
+        */
+       werr = regval_ctr_set_seqnum(values, db->get_seqnum(db));
+       result = W_ERROR_IS_OK(status);
 
 done:
        TALLOC_FREE(ctx);
@@ -1936,10 +1976,10 @@ bool regdb_values_need_update(struct regval_ctr *values)
        return (regdb_get_seqnum() != regval_ctr_get_seqnum(values));
 }
 
-/* 
+/*
  * Table of function pointers for default access
  */
+
 struct registry_ops regdb_ops = {
        .fetch_subkeys = regdb_fetch_keys,
        .fetch_values = regdb_fetch_values,