static WERROR regdb_upgrade_v2_to_v3(struct db_context *db) { int rc; WERROR werr; TALLOC_CTX *frame = talloc_stackframe(); rc = regdb->traverse(db, regdb_upgrade_v2_to_v3_fn, frame); if (rc < 0) { werr = WERR_REG_IO_FAILURE; goto done; } werr = regdb_store_regdb_version(db, REGVER_V3); done: talloc_free(frame); return werr; }
static WERROR regdb_upgrade_v1_to_v2(struct db_context *db) { TALLOC_CTX *mem_ctx; int rc; WERROR werr; mem_ctx = talloc_stackframe(); rc = regdb->traverse(db, regdb_normalize_keynames_fn, mem_ctx); talloc_free(mem_ctx); if (rc < 0) { return WERR_REG_IO_FAILURE; } werr = regdb_store_regdb_version(db, REGVER_V2); return werr; }
static WERROR regdb_upgrade_v1_to_v2(struct db_context *db) { TALLOC_CTX *mem_ctx; NTSTATUS status; WERROR werr; mem_ctx = talloc_stackframe(); status = dbwrap_traverse(db, regdb_normalize_keynames_fn, db, NULL); if (!NT_STATUS_IS_OK(status)) { werr = WERR_REG_IO_FAILURE; goto done; } werr = regdb_store_regdb_version(db, REGDB_VERSION_V2); done: talloc_free(mem_ctx); return werr; }
static WERROR regdb_upgrade_v1_to_v2(void) { TALLOC_CTX *mem_ctx; int rc; WERROR werr; mem_ctx = talloc_stackframe(); if (mem_ctx == NULL) { return WERR_NOMEM; } rc = regdb->traverse(regdb, regdb_normalize_keynames_fn, mem_ctx); talloc_destroy(mem_ctx); if (rc == -1) { return WERR_REG_IO_FAILURE; } werr = regdb_store_regdb_version(REGVER_V2); return werr; }
WERROR regdb_init(void) { int32_t vers_id; WERROR werr; NTSTATUS status; if (regdb) { DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n", regdb_refcount, regdb_refcount+1)); regdb_refcount++; return WERR_OK; } regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600, DBWRAP_LOCK_ORDER_1); if (!regdb) { regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600, DBWRAP_LOCK_ORDER_1); if (!regdb) { werr = ntstatus_to_werror(map_nt_error_from_unix(errno)); DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n", state_path("registry.tdb"), strerror(errno) )); return werr; } werr = regdb_store_regdb_version(regdb, REGDB_CODE_VERSION); if (!W_ERROR_IS_OK(werr)) { DEBUG(1, ("regdb_init: Failed to store version: %s\n", win_errstr(werr))); 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)); status = dbwrap_fetch_int32(regdb, REGDB_VERSION_KEYNAME, &vers_id); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("regdb_init: registry version uninitialized " "(got %d), initializing to version %d\n", vers_id, REGDB_VERSION_V1)); /* * There was a regdb format version prior to version 1 * which did not store a INFO/version key. The format * of this version was identical to version 1 except for * the lack of the sorted subkey cache records. * Since these are disposable, we can safely assume version * 1 if no INFO/version key is found and run the db through * the whole chain of upgrade. If the database was not * initialized, this does not harm. If it was the unversioned * version ("0"), then it do the right thing with the records. */ werr = regdb_store_regdb_version(regdb, REGDB_VERSION_V1); if (!W_ERROR_IS_OK(werr)) { return werr; } vers_id = REGDB_VERSION_V1; } if (vers_id == REGDB_CODE_VERSION) { return WERR_OK; } if (vers_id > REGDB_CODE_VERSION || vers_id == 0) { DEBUG(0, ("regdb_init: unknown registry version %d " "(code version = %d), refusing initialization\n", vers_id, REGDB_CODE_VERSION)); return WERR_CAN_NOT_COMPLETE; } if (dbwrap_transaction_start(regdb) != 0) { return WERR_REG_IO_FAILURE; } if (vers_id == REGDB_VERSION_V1) { DEBUG(10, ("regdb_init: upgrading registry from version %d " "to %d\n", REGDB_VERSION_V1, REGDB_VERSION_V2)); werr = regdb_upgrade_v1_to_v2(regdb); if (!W_ERROR_IS_OK(werr)) { dbwrap_transaction_cancel(regdb); return werr; } vers_id = REGDB_VERSION_V2; } if (vers_id == REGDB_VERSION_V2) { DEBUG(10, ("regdb_init: upgrading registry from version %d " "to %d\n", REGDB_VERSION_V2, REGDB_VERSION_V3)); werr = regdb_upgrade_v2_to_v3(regdb); if (!W_ERROR_IS_OK(werr)) { dbwrap_transaction_cancel(regdb); return werr; } vers_id = REGDB_VERSION_V3; } /* future upgrade code should go here */ if (dbwrap_transaction_commit(regdb) != 0) { return WERR_REG_IO_FAILURE; } return WERR_OK; }
static bool upgrade_v2_to_v3_check_subkeylist(struct db_context *db, const char *key, const char *subkey) { static uint32_t zero = 0; static TDB_DATA empty_subkey_list = { .dptr = (unsigned char*)&zero, .dsize = sizeof(uint32_t), }; bool success = false; char *path = talloc_asprintf(talloc_tos(), "%s\\%s", key, subkey); strupper_m(path); if (!dbwrap_exists(db, string_term_tdb_data(path))) { NTSTATUS status; DEBUG(10, ("regdb_upgrade_v2_to_v3: writing subkey list [%s]\n", path)); status = dbwrap_store_bystring(db, path, empty_subkey_list, TDB_INSERT); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("regdb_upgrade_v2_to_v3: writing subkey list " "[%s] failed\n", path)); goto done; } } success = true; done: talloc_free(path); return success; } static bool upgrade_v2_to_v3_check_parent(struct db_context *db, const char *key) { const char *sep = strrchr_m(key, '\\'); if (sep != NULL) { char *pkey = talloc_strndup(talloc_tos(), key, sep-key); if (!dbwrap_exists(db, string_term_tdb_data(pkey))) { DEBUG(0, ("regdb_upgrade_v2_to_v3: missing subkey list " "[%s]\nrun \"net registry check\"\n", pkey)); } talloc_free(pkey); } return true; } #define IS_EQUAL(d,s) (((d).dsize == strlen(s)+1) && \ (strcmp((char*)(d).dptr, (s)) == 0)) #define STARTS_WITH(d,s) (((d).dsize > strlen(s)) && \ (strncmp((char*)(d).dptr, (s), strlen(s)) == 0)) #define SSTR(d) (int)(d).dsize , (char*)(d).dptr static int regdb_upgrade_v2_to_v3_fn(struct db_record *rec, void *private_data) { struct db_context *db = (struct db_context *)private_data; TDB_DATA key = dbwrap_record_get_key(rec); TDB_DATA val = dbwrap_record_get_value(rec); if (tdb_data_is_empty(key)) { return 0; } if (db == NULL) { DEBUG(0, ("regdb_upgrade_v2_to_v3_fn: ERROR: " "NULL db context handed in via private_data\n")); return 1; } if (IS_EQUAL(key, REGDB_VERSION_KEYNAME) || STARTS_WITH(key, REG_VALUE_PREFIX) || STARTS_WITH(key, REG_SECDESC_PREFIX)) { DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%.*s]\n", SSTR(key))); return 0; } if (STARTS_WITH(key, REG_SORTED_SUBKEYS_PREFIX)) { NTSTATUS status; /* Delete the deprecated sorted subkeys cache. */ DEBUG(10, ("regdb_upgrade_v2_to_v3: deleting [%.*s]\n", SSTR(key))); status = dbwrap_record_delete(rec); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("regdb_upgrade_v2_to_v3: deleting [%.*s] " "failed!\n", SSTR(key))); return 1; } return 0; } if ( tdb_data_is_cstr(key) && hive_info((char*)key.dptr) != NULL ) { /* * Found a regular subkey list record. * Walk the list and create the list record for those * subkeys that don't already have one. */ TDB_DATA pos = val; char *subkey, *path = (char*)key.dptr; uint32_t num_items, found_items = 0; DEBUG(10, ("regdb_upgrade_v2_to_v3: scanning subkeylist of " "[%s]\n", path)); if (!tdb_data_read_uint32(&pos, &num_items)) { /* invalid or empty - skip */ return 0; } while (tdb_data_read_cstr(&pos, &subkey)) { found_items++; if (!upgrade_v2_to_v3_check_subkeylist(db, path, subkey)) { return 1; } if (!upgrade_v2_to_v3_check_parent(db, path)) { return 1; } } if (found_items != num_items) { DEBUG(0, ("regdb_upgrade_v2_to_v3: inconsistent subkey " "list [%s]\nrun \"net registry check\"\n", path)); } } else { DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping invalid [%.*s]\n" "run \"net registry check\"\n", SSTR(key))); } return 0; } static WERROR regdb_upgrade_v2_to_v3(struct db_context *db) { NTSTATUS status; WERROR werr; status = dbwrap_traverse(db, regdb_upgrade_v2_to_v3_fn, db, NULL); if (!NT_STATUS_IS_OK(status)) { werr = WERR_REG_IO_FAILURE; goto done; } werr = regdb_store_regdb_version(db, REGDB_VERSION_V3); done: return werr; }
WERROR regdb_init(void) { const char *vstring = "INFO/version"; uint32 vers_id, expected_version; WERROR werr; if (regdb) { DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n", regdb_refcount, regdb_refcount+1)); regdb_refcount++; return WERR_OK; } regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR, 0600); if (!regdb) { regdb = db_open(NULL, state_path("registry.tdb"), 0, REG_TDB_FLAGS, O_RDWR|O_CREAT, 0600); if (!regdb) { werr = ntstatus_to_werror(map_nt_error_from_unix(errno)); DEBUG(1,("regdb_init: Failed to open registry %s (%s)\n", 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) { DEBUG(10, ("regdb_init: registry version uninitialized " "(got %d), initializing to version %d\n", vers_id, expected_version)); werr = regdb_store_regdb_version(expected_version); return werr; } if (vers_id > expected_version || vers_id == 0) { DEBUG(1, ("regdb_init: unknown registry version %d " "(code version = %d), refusing initialization\n", vers_id, expected_version)); return WERR_CAN_NOT_COMPLETE; } if (vers_id == REGVER_V1) { DEBUG(10, ("regdb_init: got registry db version %d, upgrading " "to version %d\n", REGVER_V1, REGVER_V2)); if (regdb->transaction_start(regdb) != 0) { return WERR_REG_IO_FAILURE; } werr = regdb_upgrade_v1_to_v2(); if (!W_ERROR_IS_OK(werr)) { regdb->transaction_cancel(regdb); return werr; } if (regdb->transaction_commit(regdb) != 0) { return WERR_REG_IO_FAILURE; } vers_id = REGVER_V2; } /* future upgrade code should go here */ return WERR_OK; }