The branch, v3-3-test has been updated via a01d8fe5e89ca9620d23198b11e5ae605a97e5a6 (commit) via 3e89217e7edea5d7ec707de065d38b1921ed09af (commit) via f7c8718dead63964481954a86427b8c05d15452c (commit) via 97592db08a109ffbea8c85b17686fa565c5cf8c9 (commit) via a03a17365d64f7fe83a9f2e866c4f069a1dd1682 (commit) via 986030cdda828f7f87c5464d1837324b7033e27e (commit) via 55dd9bdd148fc942e15aacfe9f6b38b1a5c53158 (commit) via 52413c94fcc56c4055de4d35bea8a00646352122 (commit) via c27d03bba842ecf99f23b22dc40fa7df33392fa0 (commit) via 347bab7f4aca7f26a88affea954a514c25735abf (commit) via 727e5a87c0ed3e0a2b9c2b508b1f81e6a6d26732 (commit) via 8a2c9d965d332ccd290089b92e9cfbba2413067c (commit) via cf653e101d1b2c38b5e9de35732421a120213170 (commit) via 56a58690d3ab2e01ed28388bd59424d3abc7a0d3 (commit) via 978aef3a862065be856b36b38d72d581c3ac0ba1 (commit) via 477008367f0ac90624b4b751955cd3235b2c9cc6 (commit) via 04762cfcdba741afa457c96cd2f24e50cf83b15a (commit) via 2b25f480ba13ae125d081bab55ee3cbd3c4f425a (commit) via 23d7002b22ddcd2c52650463f31b72449aecaaaa (commit) from ec9f8c4cf67c82f4665ed51e4fd0181f5f147ea0 (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-3-test - Log ----------------------------------------------------------------- commit a01d8fe5e89ca9620d23198b11e5ae605a97e5a6 Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 18:08:41 2008 +0200 registry: add removal of secdesc of a key to regdb_store_keys(). Michael commit 3e89217e7edea5d7ec707de065d38b1921ed09af Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 18:05:58 2008 +0200 registry: add comments to removing lists in regdb_store_keys(). Michael commit f7c8718dead63964481954a86427b8c05d15452c Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 17:59:32 2008 +0200 registry: change order of deleting value and subkey lists in store_keys(). Next step in the plan to make store_keys safer without transactions. Michael commit 97592db08a109ffbea8c85b17686fa565c5cf8c9 Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 16:55:14 2008 +0200 registry: adapt comment to first step in regdb_store_keys(). Michael commit a03a17365d64f7fe83a9f2e866c4f069a1dd1682 Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 16:32:51 2008 +0200 registry: adapt comment of last step in regdb_store_keys(). adding number (3) .... Michael commit 986030cdda828f7f87c5464d1837324b7033e27e Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 14:33:02 2008 +0200 registry: regdb_store_keys: move storing the subkey list down after removing values. Michael commit 55dd9bdd148fc942e15aacfe9f6b38b1a5c53158 Author: Michael Adam <[EMAIL PROTECTED]> Date: Tue May 6 10:06:34 2008 +0200 registry: add comment explaining workflow to make store_keys safe w/o transactions /* * Make the store operation as safe as possible without transactions: * * (1) For each subkey removed from ctr compared with old_subkeys: * * (a) First delete the value db entry. * * (b) Next delete the secdesc db record. * * (c) Then delete the subkey list entry. * * (2) Now write the list of subkeys of the parent key, * deleting removed entries and adding new ones. * * (3) Finally create the subkey list entries for the added keys. * * This way if we crash half-way in between deleting the subkeys * and storing the parent's list of subkeys, no old data can pop up * out of the blue when re-adding keys later on. */ The workflow is going to be modified to meet this agendain the next commits. Michael commit 52413c94fcc56c4055de4d35bea8a00646352122 Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 14:01:49 2008 +0200 registry: check for existence of non base key in regdb_store_keys() before proceeding. Michael commit c27d03bba842ecf99f23b22dc40fa7df33392fa0 Author: Michael Adam <[EMAIL PROTECTED]> Date: Thu May 8 00:34:35 2008 +0200 registry: add a function regdb_key_is_base_key() to check whether is composite. This partly duplicates code from regdb_key_exists(). Maybe refactor later. Michael commit 347bab7f4aca7f26a88affea954a514c25735abf Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:50:01 2008 +0200 registry: check for existence of key in regdb_set_secdesc() before proceeding. Michael commit 727e5a87c0ed3e0a2b9c2b508b1f81e6a6d26732 Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:48:28 2008 +0200 registry: check for existence of key in regdb_get_secdesc() before proceeding. Michael commit 8a2c9d965d332ccd290089b92e9cfbba2413067c Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:45:02 2008 +0200 registry: check for existence of key in regdb_store_values() before proceeding. Michael commit cf653e101d1b2c38b5e9de35732421a120213170 Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:42:48 2008 +0200 registry: check for existence of key in regdb_fetch_keys() before proceeding. Michael commit 56a58690d3ab2e01ed28388bd59424d3abc7a0d3 Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:27:56 2008 +0200 registry: check for existence of key in regdb_fetch_values() first. This uses the new semantics for existence of a key. Michael commit 978aef3a862065be856b36b38d72d581c3ac0ba1 Author: Michael Adam <[EMAIL PROTECTED]> Date: Wed May 7 13:26:13 2008 +0200 registry: free talloc context on error path in regdb_fetch_values(). Michael commit 477008367f0ac90624b4b751955cd3235b2c9cc6 Author: Michael Adam <[EMAIL PROTECTED]> Date: Tue May 6 10:05:20 2008 +0200 registry: Implement new semantics for existence of registry key in tdb. Existence of a key is defined as follows: * If the key is a base key (without separator), the key exists iff the corresponding entry exist in the registry tdb. * If the key is not a base key, the key exists, iff it exists in the list of subkeys of it's parent keyname's tdb entry. Michael commit 04762cfcdba741afa457c96cd2f24e50cf83b15a Author: Michael Adam <[EMAIL PROTECTED]> Date: Tue May 6 22:20:49 2008 +0200 registry: make normalize_reg_path() strip leading and trailing '/' chars. Michael commit 2b25f480ba13ae125d081bab55ee3cbd3c4f425a Author: Michael Adam <[EMAIL PROTECTED]> Date: Tue May 6 17:15:50 2008 +0200 registry: free temporary data in regdb_fetch_key_internal(). Michael commit 23d7002b22ddcd2c52650463f31b72449aecaaaa Author: Michael Adam <[EMAIL PROTECTED]> Date: Tue May 6 17:09:57 2008 +0200 registry: change order of arguments of regdb_fetch_key_internal() list talloc context first. Michael ----------------------------------------------------------------------- Summary of changes: source/registry/reg_backend_db.c | 209 ++++++++++++++++++++++++++++++++----- source/registry/reg_util.c | 33 +++++-- 2 files changed, 206 insertions(+), 36 deletions(-) Changeset truncated at 500 lines: diff --git a/source/registry/reg_backend_db.c b/source/registry/reg_backend_db.c index 8ebe647..0d976be 100644 --- a/source/registry/reg_backend_db.c +++ b/source/registry/reg_backend_db.c @@ -28,6 +28,7 @@ static struct db_context *regdb = NULL; static int regdb_refcount; static bool regdb_key_exists(const char *key); +static bool regdb_key_is_base_key(const char *key); /* List the deepest path into the registry. All part components will be created.*/ @@ -582,6 +583,10 @@ bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr) TALLOC_CTX *ctx = talloc_stackframe(); NTSTATUS status; + if (!regdb_key_is_base_key(key) && !regdb_key_exists(key)) { + goto fail; + } + /* * fetch a list of the old subkeys so we can determine if anything has * changed @@ -631,15 +636,28 @@ bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr) regdb_fetch_keys(key, old_subkeys); - /* store the subkey list for the parent */ - - if (!regdb_store_keys_internal(key, ctr) ) { - DEBUG(0,("regdb_store_keys: Failed to store new subkey list " - "for parent [%s]\n", key)); - goto cancel; - } + /* + * Make the store operation as safe as possible without transactions: + * + * (1) For each subkey removed from ctr compared with old_subkeys: + * + * (a) First delete the value db entry. + * + * (b) Next delete the secdesc db record. + * + * (c) Then delete the subkey list entry. + * + * (2) Now write the list of subkeys of the parent key, + * deleting removed entries and adding new ones. + * + * (3) Finally create the subkey list entries for the added keys. + * + * This way if we crash half-way in between deleting the subkeys + * and storing the parent's list of subkeys, no old data can pop up + * out of the blue when re-adding keys later on. + */ - /* now delete removed keys */ + /* (1) delete removed keys' lists (values/secdesc/subkeys) */ num_subkeys = regsubkey_ctr_numkeys(old_subkeys); for (i=0; i<num_subkeys; i++) { @@ -653,7 +671,12 @@ bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr) continue; } - path = talloc_asprintf(ctx, "%s/%s", key, oldkeyname); + /* (a) Delete the value list for this key */ + + path = talloc_asprintf(ctx, "%s/%s/%s", + REG_VALUE_PREFIX, + key, + oldkeyname ); if (!path) { goto cancel; } @@ -661,15 +684,14 @@ bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr) if (!path) { goto cancel; } - status = dbwrap_delete_bystring(regdb, path); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(1, ("Deleting %s failed\n", path)); - goto cancel; - } - + /* Ignore errors here, we might have no values around */ + dbwrap_delete_bystring(regdb, path); TALLOC_FREE(path); + + /* (b) Delete the secdesc for this key */ + path = talloc_asprintf(ctx, "%s/%s/%s", - REG_VALUE_PREFIX, + REG_SECDESC_PREFIX, key, oldkeyname ); if (!path) { @@ -679,17 +701,39 @@ bool regdb_store_keys(const char *key, REGSUBKEY_CTR *ctr) if (!path) { goto cancel; } - - /* - * Ignore errors here, we might have no values around - */ + /* Ignore errors here, we might have no values around */ dbwrap_delete_bystring(regdb, path); TALLOC_FREE(path); + + /* (c) Delete the list of subkeys of this key */ + + path = talloc_asprintf(ctx, "%s/%s", key, oldkeyname); + if (!path) { + goto cancel; + } + path = normalize_reg_path(ctx, path); + if (!path) { + goto cancel; + } + status = dbwrap_delete_bystring(regdb, path); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(1, ("Deleting %s failed\n", path)); + goto cancel; + } + TALLOC_FREE(path); } TALLOC_FREE(old_subkeys); - /* now create records for any subkeys that don't already exist */ + /* (2) store the subkey list for the parent */ + + if (!regdb_store_keys_internal(key, ctr) ) { + DEBUG(0,("regdb_store_keys: Failed to store new subkey list " + "for parent [%s]\n", key)); + goto cancel; + } + + /* (3) now create records for any subkeys that don't already exist */ num_subkeys = regsubkey_ctr_numkeys(ctr); @@ -753,28 +797,113 @@ fail: } -static TDB_DATA regdb_fetch_key_internal(const char *key, TALLOC_CTX *mem_ctx) +static TDB_DATA regdb_fetch_key_internal(TALLOC_CTX *mem_ctx, const char *key) { char *path = NULL; + TDB_DATA data; path = normalize_reg_path(mem_ctx, key); if (!path) { return make_tdb_data(NULL, 0); } - return dbwrap_fetch_bystring(regdb, mem_ctx, path); + data = dbwrap_fetch_bystring(regdb, mem_ctx, path); + + TALLOC_FREE(path); + return data; +} + + +/** + * check whether a given key name represents a base key, + * i.e one without a subkey separator ('/' or '\'). + */ +static bool regdb_key_is_base_key(const char *key) +{ + TALLOC_CTX *mem_ctx = talloc_stackframe(); + bool ret = false; + char *path; + + if (key == NULL) { + goto done; + } + + path = normalize_reg_path(mem_ctx, key); + if (path == NULL) { + DEBUG(0, ("out of memory! (talloc failed)\n")); + goto done; + } + + if (*path == '\0') { + goto done; + } + + ret = (strrchr(path, '/') == NULL); + +done: + TALLOC_FREE(mem_ctx); + return ret; } +/** + * Check for the existence of a key. + * + * Existence of a key is authoritatively defined by its + * existence in the list of subkeys of its parent key. + * The exeption of this are keys without a parent key, + * i.e. the "base" keys (HKLM, HKCU, ...). + */ static bool regdb_key_exists(const char *key) { TALLOC_CTX *mem_ctx = talloc_stackframe(); TDB_DATA value; - bool ret; + bool ret = false; + char *path, *p; + + if (key == NULL) { + goto done; + } + + path = normalize_reg_path(mem_ctx, key); + if (path == NULL) { + DEBUG(0, ("out of memory! (talloc failed)\n")); + goto done; + } + + if (*path == '\0') { + goto done; + } - value = regdb_fetch_key_internal(key, mem_ctx); - ret = (value.dptr != NULL); + p = strrchr(path, '/'); + if (p == NULL) { + /* this is a base key */ + value = regdb_fetch_key_internal(mem_ctx, path); + ret = (value.dptr != NULL); + } else { + /* get the list of subkeys of the parent key */ + uint32 num_items, len, i; + fstring subkeyname; + + *p = '\0'; + p++; + value = regdb_fetch_key_internal(mem_ctx, path); + if (value.dptr == NULL) { + goto done; + } + len = tdb_unpack(value.dptr, value.dsize, "d", &num_items); + for (i = 0; i < num_items; i++) { + len += tdb_unpack(value.dptr +len, value.dsize -len, + "f", &subkeyname); + if (strequal(subkeyname, p)) { + ret = true; + goto done; + } + } + } + +done: TALLOC_FREE(mem_ctx); return ret; } @@ -799,9 +928,13 @@ int regdb_fetch_keys(const char *key, REGSUBKEY_CTR *ctr) DEBUG(11,("regdb_fetch_keys: Enter key => [%s]\n", key ? key : "NULL")); + if (!regdb_key_exists(key)) { + goto fail; + } + ctr->seqnum = regdb_get_seqnum(); - value = regdb_fetch_key_internal(key, frame); + value = regdb_fetch_key_internal(frame, key); buf = value.dptr; buflen = value.dsize; @@ -924,14 +1057,18 @@ int regdb_fetch_values( const char* key, REGVAL_CTR *values ) DEBUG(10,("regdb_fetch_values: Looking for value of key [%s] \n", key)); + if (!regdb_key_exists(key)) { + goto done; + } + keystr = talloc_asprintf(ctx, "%s/%s", REG_VALUE_PREFIX, key); if (!keystr) { - return 0; + goto done; } values->seqnum = regdb_get_seqnum(); - value = regdb_fetch_key_internal(keystr, ctx); + value = regdb_fetch_key_internal(ctx, keystr); if (!value.dptr) { /* all keys have zero values by default */ @@ -957,6 +1094,10 @@ bool regdb_store_values( const char *key, REGVAL_CTR *values ) DEBUG(10,("regdb_store_values: Looking for value of key [%s] \n", key)); + if (!regdb_key_exists(key)) { + goto done; + } + ZERO_STRUCT(data); len = regdb_pack_values(values, data.dptr, data.dsize); @@ -1012,6 +1153,11 @@ static WERROR regdb_get_secdesc(TALLOC_CTX *mem_ctx, const char *key, DEBUG(10, ("regdb_get_secdesc: Getting secdesc of key [%s]\n", key)); + if (!regdb_key_exists(key)) { + err = WERR_BADFILE; + goto done; + } + tdbkey = talloc_asprintf(tmp_ctx, "%s/%s", REG_SECDESC_PREFIX, key); if (tdbkey == NULL) { err = WERR_NOMEM; @@ -1048,6 +1194,11 @@ static WERROR regdb_set_secdesc(const char *key, WERROR err = WERR_NOMEM; TDB_DATA tdbdata; + if (!regdb_key_exists(key)) { + err = WERR_BADFILE; + goto done; + } + tdbkey = talloc_asprintf(mem_ctx, "%s/%s", REG_SECDESC_PREFIX, key); if (tdbkey == NULL) { goto done; diff --git a/source/registry/reg_util.c b/source/registry/reg_util.c index e72353e..714a39f 100644 --- a/source/registry/reg_util.c +++ b/source/registry/reg_util.c @@ -83,19 +83,38 @@ bool reg_split_key(char *path, char **base, char **key) return true; } -/********************************************************************** - The full path to the registry key is used as database after the - \'s are converted to /'s. Key string is also normalized to UPPER - case. -**********************************************************************/ +/** + * The full path to the registry key is used as database key + * after the \'s are converted to /'s. + * Leading and trailing '/' and '\' characters are stripped. + * Key string is also normalized to UPPER case. + */ char *normalize_reg_path(TALLOC_CTX *ctx, const char *keyname ) { - char *nkeyname = talloc_string_sub(ctx, keyname, "\\", "/"); - if (!nkeyname) { + char *p; + char *nkeyname; + + /* skip leading '/' and '\' chars */ + p = (char *)keyname; + while ((*p == '/') || (*p == '\\')) { + p++; + } + + nkeyname = talloc_string_sub(ctx, p, "\\", "/"); + if (nkeyname == NULL) { return NULL; } + + /* strip trailing '/' chars */ + p = strrchr(nkeyname, '/'); + while ((p != NULL) && (p[1] == '\0')) { + *p = '\0'; + p = strrchr(nkeyname, '/'); + } + strupper_m(nkeyname); + return nkeyname; } -- Samba Shared Repository