#include "registry.h"
#include "reg_db.h"
#include "reg_util_internal.h"
+#include "reg_parse_internal.h"
#include "reg_backend_db.h"
#include "reg_objects.h"
#include "nt_printing.h"
int32_t version_id;
struct regdb_trans_ctx *ctx = (struct regdb_trans_ctx *)private_data;
- version_id = dbwrap_fetch_int32(db, REGDB_VERSION_KEYNAME);
+ status = dbwrap_fetch_int32(db, REGDB_VERSION_KEYNAME, &version_id);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ERROR: could not fetch registry db version: %s. "
+ "Denying access.\n", nt_errstr(status)));
+ return NT_STATUS_ACCESS_DENIED;
+ }
if (version_id != REGDB_CODE_VERSION) {
DEBUG(0, ("ERROR: changed registry version %d found while "
TALLOC_CTX *mem_ctx = talloc_tos();
const char *keyname;
NTSTATUS status;
+ TDB_DATA key;
+ TDB_DATA value;
struct db_context *db = (struct db_context *)private_data;
- if (rec->key.dptr == NULL || rec->key.dsize == 0) {
+ key = dbwrap_record_get_key(rec);
+ if (key.dptr == NULL || key.dsize == 0) {
return 0;
}
+ value = dbwrap_record_get_value(rec);
+
if (db == NULL) {
DEBUG(0, ("regdb_normalize_keynames_fn: ERROR: "
"NULL db context handed in via private_data\n"));
return 1;
}
- if (strncmp((const char *)rec->key.dptr, REGDB_VERSION_KEYNAME,
+ if (strncmp((const char *)key.dptr, REGDB_VERSION_KEYNAME,
strlen(REGDB_VERSION_KEYNAME)) == 0)
{
return 0;
}
- keyname = strchr((const char *) rec->key.dptr, '/');
+ keyname = strchr((const char *)key.dptr, '/');
if (keyname) {
keyname = talloc_string_sub(mem_ctx,
- (const char *) rec->key.dptr,
+ (const char *)key.dptr,
"/",
"\\");
DEBUG(2, ("regdb_normalize_keynames_fn: Convert %s to %s\n",
- (const char *) rec->key.dptr,
+ (const char *)key.dptr,
keyname));
/* Delete the original record and store the normalized key */
- status = rec->delete_rec(rec);
+ status = dbwrap_record_delete(rec);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("regdb_normalize_keynames_fn: "
"tdb_delete for [%s] failed!\n",
- rec->key.dptr));
+ (const char *)key.dptr));
return 1;
}
- status = dbwrap_store_bystring(db, keyname, rec->value,
- TDB_REPLACE);
+ status = dbwrap_store_bystring(db, keyname, value, TDB_REPLACE);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0,("regdb_normalize_keynames_fn: "
"failed to store new record for [%s]!\n",
static WERROR regdb_upgrade_v1_to_v2(struct db_context *db)
{
TALLOC_CTX *mem_ctx;
- int rc;
+ NTSTATUS status;
WERROR werr;
mem_ctx = talloc_stackframe();
- rc = db->traverse(db, regdb_normalize_keynames_fn, db);
+ 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;
+}
- if (rc < 0) {
- return WERR_REG_IO_FAILURE;
+static bool tdb_data_read_uint32(TDB_DATA *buf, uint32_t *result)
+{
+ const size_t len = sizeof(uint32_t);
+ if (buf->dsize >= len) {
+ *result = IVAL(buf->dptr, 0);
+ buf->dptr += len;
+ buf->dsize -= len;
+ return true;
+ }
+ return false;
+}
+
+static bool tdb_data_read_cstr(TDB_DATA *buf, char **result)
+{
+ const size_t len = strnlen((char*)buf->dptr, buf->dsize) + 1;
+ if (buf->dsize >= len) {
+ *result = (char*)buf->dptr;
+ buf->dptr += len;
+ buf->dsize -= len;
+ return true;
+ }
+ return false;
+}
+
+static bool tdb_data_is_cstr(TDB_DATA d) {
+ if (tdb_data_is_empty(d) || (d.dptr[d.dsize-1] != '\0')) {
+ return false;
}
+ return strchr((char *)d.dptr, '\0') == (char *)&d.dptr[d.dsize-1];
+}
- werr = regdb_store_regdb_version(db, REGDB_VERSION_V2);
- return werr;
+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)
{
- const char *keyname;
- fstring subkeyname;
- NTSTATUS status;
- WERROR werr;
- uint8_t *buf;
- uint32_t buflen, len;
- uint32_t num_items;
- uint32_t i;
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 (rec->key.dptr == NULL || rec->key.dsize == 0) {
+ if (tdb_data_is_empty(key)) {
return 0;
}
return 1;
}
- keyname = (const char *)rec->key.dptr;
-
- if (strncmp(keyname, REGDB_VERSION_KEYNAME,
- strlen(REGDB_VERSION_KEYNAME)) == 0)
+ 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 (strncmp(keyname, REG_SORTED_SUBKEYS_PREFIX,
- strlen(REG_SORTED_SUBKEYS_PREFIX)) == 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", keyname));
+ DEBUG(10, ("regdb_upgrade_v2_to_v3: deleting [%.*s]\n",
+ SSTR(key)));
- status = rec->delete_rec(rec);
+ status = dbwrap_record_delete(rec);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("regdb_upgrade_v2_to_v3: tdb_delete for [%s] "
- "failed!\n", keyname));
+ DEBUG(0, ("regdb_upgrade_v2_to_v3: deleting [%.*s] "
+ "failed!\n", SSTR(key)));
return 1;
}
return 0;
}
- if (strncmp(keyname, REG_VALUE_PREFIX, strlen(REG_VALUE_PREFIX)) == 0) {
- DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%s]\n", keyname));
- return 0;
- }
-
- if (strncmp(keyname, REG_SECDESC_PREFIX,
- strlen(REG_SECDESC_PREFIX)) == 0)
+ if ( tdb_data_is_cstr(key) &&
+ hive_info((char*)key.dptr) != NULL )
{
- DEBUG(10, ("regdb_upgrade_v2_to_v3: skipping [%s]\n", keyname));
- return 0;
- }
-
- /*
- * Found a regular subkey list record.
- * Walk the list and create the list record for those
- * subkeys that don't already have one.
- */
- DEBUG(10, ("regdb_upgrade_v2_to_v3: scanning subkey list of [%s]\n",
- keyname));
+ /*
+ * 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;
+ }
- buf = rec->value.dptr;
- buflen = rec->value.dsize;
+ while (tdb_data_read_cstr(&pos, &subkey)) {
+ found_items++;
- len = tdb_unpack(buf, buflen, "d", &num_items);
- if (len == (uint32_t)-1) {
- /* invalid or empty - skip */
- return 0;
- }
+ if (!upgrade_v2_to_v3_check_subkeylist(db, path, subkey))
+ {
+ return 1;
+ }
- for (i=0; i<num_items; i++) {
- len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
- DEBUG(10, ("regdb_upgrade_v2_to_v3: "
- "writing subkey list for [%s\\%s]\n",
- keyname, subkeyname));
- werr = regdb_store_subkey_list(db, keyname, subkeyname);
- if (!W_ERROR_IS_OK(werr)) {
- 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)
{
- int rc;
+ NTSTATUS status;
WERROR werr;
- rc = regdb->traverse(db, regdb_upgrade_v2_to_v3_fn, db);
- if (rc < 0) {
+ 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;
}
WERROR regdb_init(void)
{
- uint32 vers_id;
+ int32_t vers_id;
WERROR werr;
+ NTSTATUS status;
if (regdb) {
DEBUG(10, ("regdb_init: incrementing refcount (%d->%d)\n",
}
regdb = db_open(NULL, state_path("registry.tdb"), 0,
- REG_TDB_FLAGS, O_RDWR, 0600);
+ 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);
+ 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",
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"));
}
DEBUG(10, ("regdb_init: registry db openend. refcount reset (%d)\n",
regdb_refcount));
- vers_id = dbwrap_fetch_int32(regdb, REGDB_VERSION_KEYNAME);
- if (vers_id == -1) {
+ 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_CODE_VERSION));
+ 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;
+ }
- werr = regdb_store_regdb_version(regdb, REGDB_CODE_VERSION);
- return werr;
+ if (vers_id == REGDB_CODE_VERSION) {
+ return WERR_OK;
}
if (vers_id > REGDB_CODE_VERSION || vers_id == 0) {
return WERR_CAN_NOT_COMPLETE;
}
- if (regdb->transaction_start(regdb) != 0) {
+ if (dbwrap_transaction_start(regdb) != 0) {
return WERR_REG_IO_FAILURE;
}
werr = regdb_upgrade_v1_to_v2(regdb);
if (!W_ERROR_IS_OK(werr)) {
- regdb->transaction_cancel(regdb);
+ dbwrap_transaction_cancel(regdb);
return werr;
}
werr = regdb_upgrade_v2_to_v3(regdb);
if (!W_ERROR_IS_OK(werr)) {
- regdb->transaction_cancel(regdb);
+ dbwrap_transaction_cancel(regdb);
return werr;
}
/* future upgrade code should go here */
- if (regdb->transaction_commit(regdb) != 0) {
+ if (dbwrap_transaction_commit(regdb) != 0) {
return WERR_REG_IO_FAILURE;
}
become_root();
regdb = db_open(NULL, state_path("registry.tdb"), 0,
- REG_TDB_FLAGS, O_RDWR, 0600);
+ REG_TDB_FLAGS, O_RDWR, 0600,
+ DBWRAP_LOCK_ORDER_1);
if ( !regdb ) {
result = ntstatus_to_werror( map_nt_error_from_unix( errno ) );
DEBUG(0,("regdb_open: Failed to open %s! (%s)\n",
WERROR regdb_transaction_start(void)
{
- return (regdb->transaction_start(regdb) == 0) ?
+ return (dbwrap_transaction_start(regdb) == 0) ?
WERR_OK : WERR_REG_IO_FAILURE;
}
WERROR regdb_transaction_commit(void)
{
- return (regdb->transaction_commit(regdb) == 0) ?
+ return (dbwrap_transaction_commit(regdb) == 0) ?
WERR_OK : WERR_REG_IO_FAILURE;
}
WERROR regdb_transaction_cancel(void)
{
- return (regdb->transaction_cancel(regdb) == 0) ?
+ return (dbwrap_transaction_cancel(regdb) == 0) ?
WERR_OK : WERR_REG_IO_FAILURE;
}
***********************************************************************/
int regdb_get_seqnum(void)
{
- return regdb->get_seqnum(regdb);
+ return dbwrap_get_seqnum(regdb);
}
return ret;
}
-bool regdb_store_keys(const char *key, struct regsubkey_ctr *ctr)
+static bool regdb_store_keys(const char *key, struct regsubkey_ctr *ctr)
{
return regdb_store_keys_internal(regdb, key, ctr);
}
W_ERROR_NOT_OK_GOTO_DONE(werr);
if (regsubkey_ctr_key_exists(subkeys, subkey)) {
- werr = WERR_OK;
- goto done;
+ char *newkey;
+
+ newkey = talloc_asprintf(mem_ctx, "%s\\%s", key, subkey);
+ if (newkey == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ if (regdb_key_exists(db, newkey)) {
+ werr = WERR_OK;
+ goto done;
+ }
}
talloc_free(subkeys);
{
char *path = NULL;
TDB_DATA data;
+ NTSTATUS status;
path = normalize_reg_path(mem_ctx, key);
if (!path) {
return make_tdb_data(NULL, 0);
}
- data = dbwrap_fetch_bystring(db, mem_ctx, path);
+ status = dbwrap_fetch_bystring(db, mem_ctx, path, &data);
+ if (!NT_STATUS_IS_OK(status)) {
+ data = tdb_null;
+ }
TALLOC_FREE(path);
return data;
werr = regsubkey_ctr_reinit(ctr);
W_ERROR_NOT_OK_GOTO_DONE(werr);
- werr = regsubkey_ctr_set_seqnum(ctr, db->get_seqnum(db));
+ werr = regsubkey_ctr_set_seqnum(ctr, dbwrap_get_seqnum(db));
W_ERROR_NOT_OK_GOTO_DONE(werr);
value = regdb_fetch_key_internal(db, frame, key);
return werr;
}
-int regdb_fetch_keys(const char *key, struct regsubkey_ctr *ctr)
+static int regdb_fetch_keys(const char *key, struct regsubkey_ctr *ctr)
{
WERROR werr;
goto done;
}
- werr = regval_ctr_set_seqnum(values, db->get_seqnum(db));
+ werr = regval_ctr_set_seqnum(values, dbwrap_get_seqnum(db));
W_ERROR_NOT_OK_GOTO_DONE(werr);
value = regdb_fetch_key_internal(db, ctx, keystr);
goto done;
}
+ if (regval_ctr_numvals(values) == 0) {
+ WERROR werr = regdb_delete_values(db, key);
+ return werror_to_ntstatus(werr);
+ }
+
ZERO_STRUCT(data);
len = regdb_pack_values(values, data.dptr, data.dsize);
goto done;
}
- old_data = dbwrap_fetch_bystring(db, ctx, keystr);
+ status = dbwrap_fetch_bystring(db, ctx, keystr, &old_data);
- if ((old_data.dptr != NULL)
+ if (NT_STATUS_IS_OK(status)
+ && (old_data.dptr != NULL)
&& (old_data.dsize == data.dsize)
&& (memcmp(old_data.dptr, data.dptr, data.dsize) == 0))
{
goto done;
}
- data = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey);
- if (data.dptr == NULL) {
+ status = dbwrap_fetch_bystring(regdb, tmp_ctx, tdbkey, &data);
+ if (!NT_STATUS_IS_OK(status)) {
err = WERR_BADFILE;
goto done;
}