*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* Attempt to wrap the existing API in a more winreg.idl-like way */
return WERR_OK;
}
-WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
- uint32 desired_access,
- const struct nt_user_token *token,
- struct registry_key **pkey)
+static int regkey_destructor(REGISTRY_KEY *key)
{
- struct registry_key *key;
- WERROR err;
+ return regdb_close();
+}
- SMB_ASSERT(hive[0] != '\0');
- SMB_ASSERT(strchr(hive, '\\') == NULL);
+static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
+ struct registry_key *parent,
+ const char *name,
+ const struct nt_user_token *token,
+ uint32 access_desired,
+ struct registry_key **pregkey)
+{
+ WERROR result = WERR_OK;
+ struct registry_key *regkey;
+ REGISTRY_KEY *key;
+ REGSUBKEY_CTR *subkeys = NULL;
- if (!(key = TALLOC_ZERO_P(mem_ctx, struct registry_key))) {
- return WERR_NOMEM;
+ DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name));
+
+ SMB_ASSERT(strchr(name, '\\') == NULL);
+
+ if (!(regkey = TALLOC_ZERO_P(mem_ctx, struct registry_key)) ||
+ !(regkey->token = dup_nt_token(regkey, token)) ||
+ !(regkey->key = TALLOC_ZERO_P(regkey, REGISTRY_KEY))) {
+ result = WERR_NOMEM;
+ goto done;
}
- if (!(key->token = dup_nt_token(key, token))) {
- TALLOC_FREE(key);
- return WERR_NOMEM;
+ if ( !(W_ERROR_IS_OK(result = regdb_open())) ) {
+ goto done;
}
- err = regkey_open_internal(key, &key->key, hive, token,
- desired_access);
+ key = regkey->key;
+ talloc_set_destructor(key, regkey_destructor);
+
+ /* initialization */
+
+ key->type = REG_KEY_GENERIC;
- if (!W_ERROR_IS_OK(err)) {
- TALLOC_FREE(key);
- return err;
+ if (name[0] == '\0') {
+ /*
+ * Open a copy of the parent key
+ */
+ if (!parent) {
+ result = WERR_BADFILE;
+ goto done;
+ }
+ key->name = talloc_strdup(key, parent->key->name);
+ }
+ else {
+ /*
+ * Normal subkey open
+ */
+ key->name = talloc_asprintf(key, "%s%s%s",
+ parent ? parent->key->name : "",
+ parent ? "\\": "",
+ name);
}
- *pkey = key;
- return WERR_OK;
+ if (key->name == NULL) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ /* Tag this as a Performance Counter Key */
+
+ if( StrnCaseCmp(key->name, KEY_HKPD, strlen(KEY_HKPD)) == 0 )
+ key->type = REG_KEY_HKPD;
+
+ /* Look up the table of registry I/O operations */
+ if ( !(key->hook = reghook_cache_find( key->name )) ) {
+ DEBUG(0,("reg_open_onelevel: Failed to assigned a "
+ "REGISTRY_HOOK to [%s]\n", key->name ));
+ result = WERR_BADFILE;
+ goto done;
+ }
+
+ /* check if the path really exists; failed is indicated by -1 */
+ /* if the subkey count failed, bail out */
+
+ if ( !(subkeys = TALLOC_ZERO_P( key, REGSUBKEY_CTR )) ) {
+ result = WERR_NOMEM;
+ goto done;
+ }
+
+ if ( fetch_reg_keys( key, subkeys ) == -1 ) {
+ result = WERR_BADFILE;
+ goto done;
+ }
+
+ TALLOC_FREE( subkeys );
+
+ if ( !regkey_access_check( key, access_desired, &key->access_granted,
+ token ) ) {
+ result = WERR_ACCESS_DENIED;
+ goto done;
+ }
+
+ *pregkey = regkey;
+ result = WERR_OK;
+
+done:
+ if ( !W_ERROR_IS_OK(result) ) {
+ TALLOC_FREE(regkey);
+ }
+
+ return result;
+}
+
+WERROR reg_openhive(TALLOC_CTX *mem_ctx, const char *hive,
+ uint32 desired_access,
+ const struct nt_user_token *token,
+ struct registry_key **pkey)
+{
+ SMB_ASSERT(hive != NULL);
+ SMB_ASSERT(hive[0] != '\0');
+ SMB_ASSERT(strchr(hive, '\\') == NULL);
+
+ return regkey_open_onelevel(mem_ctx, NULL, hive, token, desired_access,
+ pkey);
}
WERROR reg_openkey(TALLOC_CTX *mem_ctx, struct registry_key *parent,
const char *name, uint32 desired_access,
struct registry_key **pkey)
{
- struct registry_key *key;
+ struct registry_key *direct_parent = parent;
WERROR err;
- char *path;
+ char *p, *path, *to_free;
+ size_t len;
- if (!(key = TALLOC_ZERO_P(mem_ctx, struct registry_key))) {
+ if (!(path = SMB_STRDUP(name))) {
return WERR_NOMEM;
}
+ to_free = path;
- if (!(key->token = dup_nt_token(key, parent->token))) {
- TALLOC_FREE(key);
- return WERR_NOMEM;
- }
+ len = strlen(path);
- if (name[0] == '\0') {
- /*
- * Make a copy of the parent
- */
- path = talloc_strdup(key, parent->key->name);
- }
- else {
- /*
- * Normal subpath open
- */
- path = talloc_asprintf(key, "%s\\%s", parent->key->name,
- name);
+ if ((len > 0) && (path[len-1] == '\\')) {
+ path[len-1] = '\0';
}
- if (!path) {
- TALLOC_FREE(key);
- return WERR_NOMEM;
- }
+ while ((p = strchr(path, '\\')) != NULL) {
+ char *name_component;
+ struct registry_key *tmp;
- err = regkey_open_internal(key, &key->key, path, parent->token,
- desired_access);
- TALLOC_FREE(path);
+ if (!(name_component = SMB_STRNDUP(path, (p - path)))) {
+ err = WERR_NOMEM;
+ goto error;
+ }
- if (!W_ERROR_IS_OK(err)) {
- TALLOC_FREE(key);
- return err;
+ err = regkey_open_onelevel(mem_ctx, direct_parent,
+ name_component, parent->token,
+ SEC_RIGHTS_ENUM_SUBKEYS, &tmp);
+ SAFE_FREE(name_component);
+
+ if (!W_ERROR_IS_OK(err)) {
+ goto error;
+ }
+ if (direct_parent != parent) {
+ TALLOC_FREE(direct_parent);
+ }
+
+ direct_parent = tmp;
+ path = p+1;
}
- *pkey = key;
- return WERR_OK;
+ err = regkey_open_onelevel(mem_ctx, direct_parent, path, parent->token,
+ desired_access, pkey);
+ error:
+ if (direct_parent != parent) {
+ TALLOC_FREE(direct_parent);
+ }
+ SAFE_FREE(to_free);
+ return err;
}
WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key,
}
if (idx >= key->values->num_values) {
- return WERR_BADFILE;
+ return WERR_NO_MORE_ITEMS;
}
err = registry_pull_value(mem_ctx, &val,
TALLOC_CTX *mem_ctx;
char *name, *end;
int num_subkeys;
+ struct registry_key *tmp_key;
if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM;
goto error;
}
- if ((end = strrchr(name, '\\')) != NULL) {
- struct registry_key *tmp;
+ /* check if the key has subkeys */
+ err = reg_openkey(mem_ctx, parent, name, REG_KEY_READ, &tmp_key);
+ if (!W_ERROR_IS_OK(err)) {
+ goto error;
+ }
+ if (!W_ERROR_IS_OK(err = fill_subkey_cache(tmp_key))) {
+ goto error;
+ }
+ if (tmp_key->subkeys->num_subkeys > 0) {
+ err = WERR_ACCESS_DENIED;
+ goto error;
+ }
+ /* no subkeys - proceed with delete */
+ if ((end = strrchr(name, '\\')) != NULL) {
*end = '\0';
err = reg_openkey(mem_ctx, parent, name,
- SEC_RIGHTS_CREATE_SUBKEY, &tmp);
+ SEC_RIGHTS_CREATE_SUBKEY, &tmp_key);
if (!W_ERROR_IS_OK(err)) {
goto error;
}
- parent = tmp;
+ parent = tmp_key;
name = end+1;
}
return WERR_OK;
}
+
+/*
+ * Utility function to open a complete registry path including the hive
+ * prefix. This should become the replacement function for
+ * regkey_open_internal.
+ */
+
+WERROR reg_open_path(TALLOC_CTX *mem_ctx, const char *orig_path,
+ uint32 desired_access, const struct nt_user_token *token,
+ struct registry_key **pkey)
+{
+ struct registry_key *hive, *key;
+ char *path, *p;
+ WERROR err;
+
+ if (!(path = SMB_STRDUP(orig_path))) {
+ return WERR_NOMEM;
+ }
+
+ p = strchr(path, '\\');
+
+ if ((p == NULL) || (p[1] == '\0')) {
+ /*
+ * No key behind the hive, just return the hive
+ */
+
+ err = reg_openhive(mem_ctx, path, desired_access, token,
+ &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+ SAFE_FREE(path);
+ *pkey = hive;
+ return WERR_OK;
+ }
+
+ *p = '\0';
+
+ err = reg_openhive(mem_ctx, path, SEC_RIGHTS_ENUM_SUBKEYS, token,
+ &hive);
+ if (!W_ERROR_IS_OK(err)) {
+ SAFE_FREE(path);
+ return err;
+ }
+
+ err = reg_openkey(mem_ctx, hive, p+1, desired_access, &key);
+
+ TALLOC_FREE(hive);
+ SAFE_FREE(path);
+
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ *pkey = key;
+ return WERR_OK;
+}
+
+
+/*
+ * Utility function to delete a registry key with all its subkeys.
+ * Note that reg_deletekey returns ACCESS_DENIED when called on a
+ * key that has subkeys.
+ */
+WERROR reg_deletekey_recursive(TALLOC_CTX *ctx,
+ struct registry_key *parent,
+ const char *path)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ WERROR werr = WERR_OK;
+ struct registry_key *key;
+ char *subkey_name = NULL;
+
+ mem_ctx = talloc_new(ctx);
+ if (mem_ctx == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
+
+ /* recurse through subkeys first */
+ werr = reg_openkey(mem_ctx, parent, path, REG_KEY_WRITE, &key);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+
+ while (W_ERROR_IS_OK(werr = reg_enumkey(mem_ctx, key, 0,
+ &subkey_name, NULL)))
+ {
+ werr = reg_deletekey_recursive(mem_ctx, key, subkey_name);
+ if (!W_ERROR_IS_OK(werr)) {
+ goto done;
+ }
+ }
+ if (!W_ERROR_EQUAL(WERR_NO_MORE_ITEMS, werr)) {
+ DEBUG(1, ("reg_deletekey_recursive: Error enumerating "
+ "subkeys: %s\n", dos_errstr(werr)));
+ goto done;
+ }
+
+ /* now delete the actual key */
+ werr = reg_deletekey(parent, path);
+
+done:
+ TALLOC_FREE(mem_ctx);
+ return werr;
+}