diff options
author | Volker Lendecke <vlendec@samba.org> | 2006-12-01 20:01:09 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:16:18 -0500 |
commit | ecf90c495eb850cd6f376fb4e090640b69f0c029 (patch) | |
tree | f3f30d71daab2abb56f50bac558fb9a43f28d6f1 /source3/registry | |
parent | e57de5730cd65bca08ea2dabcf2d74d52825285e (diff) | |
download | samba-ecf90c495eb850cd6f376fb4e090640b69f0c029.tar.gz samba-ecf90c495eb850cd6f376fb4e090640b69f0c029.tar.bz2 samba-ecf90c495eb850cd6f376fb4e090640b69f0c029.zip |
r19991: Sorry for this 2000-liner...
The main thing here is a rewrite of srv_winreg_nt.c. The core functionality
has moved to registry/reg_api.c which is then usable by the rest of Samba as
well.
On that way it fixes creating keys with more than one element in the
path. This did not work before.
Two things that sneaked in (sorry :-) is the change of some routines from
NTSTATUS to WERROR the removed "parent" argument to regkey_open_internal.
Volker
(This used to be commit fea52801de8c7b85c578d200c599475680c5339f)
Diffstat (limited to 'source3/registry')
-rw-r--r-- | source3/registry/reg_api.c | 511 | ||||
-rw-r--r-- | source3/registry/reg_frontend.c | 63 |
2 files changed, 541 insertions, 33 deletions
diff --git a/source3/registry/reg_api.c b/source3/registry/reg_api.c new file mode 100644 index 0000000000..672e69c6c7 --- /dev/null +++ b/source3/registry/reg_api.c @@ -0,0 +1,511 @@ +/* + * Unix SMB/CIFS implementation. + * Virtual Windows Registry Layer + * Copyright (C) Volker Lendecke 2006 + * + * 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 + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * 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. + */ + +/* Attempt to wrap the existing API in a more winreg.idl-like way */ + +#include "includes.h" + +static WERROR fill_value_cache(struct registry_key *key) +{ + if (key->values != NULL) { + return WERR_OK; + } + + if (!(key->values = TALLOC_ZERO_P(key, REGVAL_CTR))) { + return WERR_NOMEM; + } + if (fetch_reg_values(key->key, key->values) == -1) { + TALLOC_FREE(key->values); + return WERR_BADFILE; + } + + return WERR_OK; +} + +static WERROR fill_subkey_cache(struct registry_key *key) +{ + if (key->subkeys != NULL) { + return WERR_OK; + } + + if (!(key->subkeys = TALLOC_ZERO_P(key, REGSUBKEY_CTR))) { + return WERR_NOMEM; + } + + if (fetch_reg_keys(key->key, key->subkeys) == -1) { + TALLOC_FREE(key->subkeys); + return WERR_NO_MORE_ITEMS; + } + + 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) +{ + struct registry_key *key; + WERROR err; + + SMB_ASSERT(hive[0] != '\0'); + SMB_ASSERT(strchr(hive, '\\') == NULL); + + if (!(key = TALLOC_ZERO_P(mem_ctx, struct registry_key))) { + return WERR_NOMEM; + } + + if (!(key->token = dup_nt_token(key, token))) { + TALLOC_FREE(key); + return WERR_NOMEM; + } + + err = regkey_open_internal(key, &key->key, hive, token, + desired_access); + + if (!W_ERROR_IS_OK(err)) { + TALLOC_FREE(key); + return err; + } + + *pkey = key; + return WERR_OK; + +} + +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; + WERROR err; + char *path; + + if (!(key = TALLOC_ZERO_P(mem_ctx, struct registry_key))) { + return WERR_NOMEM; + } + + if (!(key->token = dup_nt_token(key, parent->token))) { + TALLOC_FREE(key); + return WERR_NOMEM; + } + + 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 (!path) { + TALLOC_FREE(key); + return WERR_NOMEM; + } + + err = regkey_open_internal(key, &key->key, path, parent->token, + desired_access); + TALLOC_FREE(path); + + if (!W_ERROR_IS_OK(err)) { + TALLOC_FREE(key); + return err; + } + + *pkey = key; + return WERR_OK; +} + +WERROR reg_enumkey(TALLOC_CTX *mem_ctx, struct registry_key *key, + uint32 idx, char **name, NTTIME *last_write_time) +{ + WERROR err; + + if (!(key->key->access_granted & SEC_RIGHTS_ENUM_SUBKEYS)) { + return WERR_ACCESS_DENIED; + } + + if (!W_ERROR_IS_OK(err = fill_subkey_cache(key))) { + return err; + } + + if (idx >= key->subkeys->num_subkeys) { + return WERR_NO_MORE_ITEMS; + } + + if (!(*name = talloc_strdup(mem_ctx, key->subkeys->subkeys[idx]))) { + return WERR_NOMEM; + } + + if (last_write_time) { + *last_write_time = 0; + } + + return WERR_OK; +} + +WERROR reg_enumvalue(TALLOC_CTX *mem_ctx, struct registry_key *key, + uint32 idx, const char **pname, + struct registry_value **pval) +{ + struct registry_value *val; + WERROR err; + + if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) { + return WERR_ACCESS_DENIED; + } + + if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) { + return err; + } + + if (idx >= key->values->num_values) { + return WERR_BADFILE; + } + + err = registry_pull_value(mem_ctx, &val, + key->values->values[idx]->type, + key->values->values[idx]->data_p, + key->values->values[idx]->size, + key->values->values[idx]->size); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + if (pname + && !(*pname = talloc_strdup( + mem_ctx, key->values->values[idx]->valuename))) { + SAFE_FREE(val); + return WERR_NOMEM; + } + + *pval = val; + return WERR_OK; +} + +WERROR reg_queryvalue(TALLOC_CTX *mem_ctx, struct registry_key *key, + const char *name, struct registry_value **pval) +{ + WERROR err; + uint32 i; + + if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) { + return WERR_ACCESS_DENIED; + } + + if (!(W_ERROR_IS_OK(err = fill_value_cache(key)))) { + return err; + } + + for (i=0; i<key->values->num_values; i++) { + if (strequal(key->values->values[i]->valuename, name)) { + return reg_enumvalue(mem_ctx, key, i, NULL, pval); + } + } + + return WERR_BADFILE; +} + +WERROR reg_queryinfokey(struct registry_key *key, uint32_t *num_subkeys, + uint32_t *max_subkeylen, uint32_t *max_subkeysize, + uint32_t *num_values, uint32_t *max_valnamelen, + uint32_t *max_valbufsize, uint32_t *secdescsize, + NTTIME *last_changed_time) +{ + uint32 i, max_size; + size_t max_len; + TALLOC_CTX *mem_ctx; + WERROR err; + struct security_descriptor *secdesc; + + if (!(key->key->access_granted & SEC_RIGHTS_QUERY_VALUE)) { + return WERR_ACCESS_DENIED; + } + + if (!W_ERROR_IS_OK(fill_subkey_cache(key)) || + !W_ERROR_IS_OK(fill_value_cache(key))) { + return WERR_BADFILE; + } + + max_len = 0; + for (i=0; i<key->subkeys->num_subkeys; i++) { + max_len = MAX(max_len, strlen(key->subkeys->subkeys[i])); + } + + *num_subkeys = key->subkeys->num_subkeys; + *max_subkeylen = max_len; + *max_subkeysize = 0; /* Class length? */ + + max_len = 0; + max_size = 0; + for (i=0; i<key->values->num_values; i++) { + max_len = MAX(max_len, + strlen(key->values->values[i]->valuename)); + max_size = MAX(max_size, key->values->values[i]->size); + } + + *num_values = key->values->num_values; + *max_valnamelen = max_len; + *max_valbufsize = max_size; + + if (!(mem_ctx = talloc_new(key))) { + return WERR_NOMEM; + } + + err = regkey_get_secdesc(mem_ctx, key->key, &secdesc); + if (!W_ERROR_IS_OK(err)) { + TALLOC_FREE(mem_ctx); + return err; + } + + *secdescsize = sec_desc_size(secdesc); + TALLOC_FREE(mem_ctx); + + *last_changed_time = 0; + + return WERR_OK; +} + +WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent, + const char *subkeypath, uint32 desired_access, + struct registry_key **pkey, + enum winreg_CreateAction *paction) +{ + struct registry_key *key = parent; + struct registry_key *create_parent; + TALLOC_CTX *mem_ctx; + char *path, *end; + WERROR err; + REGSUBKEY_CTR *subkeys; + + if (!(mem_ctx = talloc_new(ctx))) return WERR_NOMEM; + + if (!(path = talloc_strdup(mem_ctx, subkeypath))) { + err = WERR_NOMEM; + goto done; + } + + while ((end = strchr(path, '\\')) != NULL) { + struct registry_key *tmp; + enum winreg_CreateAction action; + + *end = '\0'; + + err = reg_createkey(mem_ctx, key, path, + SEC_RIGHTS_ENUM_SUBKEYS, &tmp, &action); + if (!W_ERROR_IS_OK(err)) { + goto done; + } + + if (key != parent) { + TALLOC_FREE(key); + } + + key = tmp; + path = end+1; + } + + /* + * At this point, "path" contains the one-element subkey of "key". We + * can try to open it. + */ + + err = reg_openkey(ctx, key, path, desired_access, pkey); + if (W_ERROR_IS_OK(err)) { + *paction = REG_OPENED_EXISTING_KEY; + return WERR_OK; + } + + if (!W_ERROR_EQUAL(err, WERR_BADFILE)) { + /* + * Something but "notfound" has happened, so bail out + */ + goto done; + } + + /* + * We have to make a copy of the current key, as we opened it only + * with ENUM_SUBKEY access. + */ + + err = reg_openkey(mem_ctx, key, "", SEC_RIGHTS_CREATE_SUBKEY, + &create_parent); + if (!W_ERROR_IS_OK(err)) { + goto done; + } + + /* + * Actually create the subkey + */ + + if (!(subkeys = TALLOC_ZERO_P(mem_ctx, REGSUBKEY_CTR))) { + err = WERR_NOMEM; + goto done; + } + + err = fill_subkey_cache(create_parent); + if (!W_ERROR_IS_OK(err)) goto done; + + err = regsubkey_ctr_addkey(create_parent->subkeys, path); + if (!W_ERROR_IS_OK(err)) goto done; + + if (!store_reg_keys(create_parent->key, create_parent->subkeys)) { + TALLOC_FREE(create_parent->subkeys); + err = WERR_REG_IO_FAILURE; + goto done; + } + + /* + * Now open the newly created key + */ + + err = reg_openkey(ctx, create_parent, path, desired_access, pkey); + if (W_ERROR_IS_OK(err) && (paction != NULL)) { + *paction = REG_CREATED_NEW_KEY; + } + + done: + TALLOC_FREE(mem_ctx); + return err; +} + + +WERROR reg_deletekey(struct registry_key *parent, const char *path) +{ + WERROR err; + TALLOC_CTX *mem_ctx; + char *name, *end; + int num_subkeys; + + if (!(mem_ctx = talloc_init("reg_createkey"))) return WERR_NOMEM; + + if (!(name = talloc_strdup(mem_ctx, path))) { + err = WERR_NOMEM; + goto error; + } + + if ((end = strrchr(name, '\\')) != NULL) { + struct registry_key *tmp; + + *end = '\0'; + + err = reg_openkey(mem_ctx, parent, name, + SEC_RIGHTS_CREATE_SUBKEY, &tmp); + if (!W_ERROR_IS_OK(err)) { + goto error; + } + + parent = tmp; + name = end+1; + } + + if (name[0] == '\0') { + err = WERR_INVALID_PARAM; + goto error; + } + + if (!W_ERROR_IS_OK(err = fill_subkey_cache(parent))) { + goto error; + } + + num_subkeys = parent->subkeys->num_subkeys; + + if (regsubkey_ctr_delkey(parent->subkeys, name) == num_subkeys) { + err = WERR_BADFILE; + goto error; + } + + if (!store_reg_keys(parent->key, parent->subkeys)) { + TALLOC_FREE(parent->subkeys); + err = WERR_REG_IO_FAILURE; + goto error; + } + + err = WERR_OK; + error: + TALLOC_FREE(mem_ctx); + return err; +} + +WERROR reg_setvalue(struct registry_key *key, const char *name, + const struct registry_value *val) +{ + WERROR err; + DATA_BLOB value_data; + int res; + + if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) { + return WERR_ACCESS_DENIED; + } + + if (!W_ERROR_IS_OK(err = fill_value_cache(key))) { + return err; + } + + err = registry_push_value(key, val, &value_data); + if (!W_ERROR_IS_OK(err)) { + return err; + } + + res = regval_ctr_addvalue(key->values, name, val->type, + (char *)value_data.data, value_data.length); + TALLOC_FREE(value_data.data); + + if (res == 0) { + TALLOC_FREE(key->values); + return WERR_NOMEM; + } + + if (!store_reg_values(key->key, key->values)) { + TALLOC_FREE(key->values); + return WERR_REG_IO_FAILURE; + } + + return WERR_OK; +} + +WERROR reg_deletevalue(struct registry_key *key, const char *name) +{ + WERROR err; + + if (!(key->key->access_granted & SEC_RIGHTS_SET_VALUE)) { + return WERR_ACCESS_DENIED; + } + + if (!W_ERROR_IS_OK(err = fill_value_cache(key))) { + return err; + } + + regval_ctr_delvalue(key->values, name); + + if (!store_reg_values(key->key, key->values)) { + TALLOC_FREE(key->values); + return WERR_REG_IO_FAILURE; + } + + return WERR_OK; +} + diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_frontend.c index 79fbc8ef52..aefd2b6f51 100644 --- a/source3/registry/reg_frontend.c +++ b/source3/registry/reg_frontend.c @@ -189,9 +189,9 @@ int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val ) return result; } -NTSTATUS registry_fetch_values(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, - uint32 *pnum_values, char ***pnames, - struct registry_value ***pvalues) +WERROR registry_fetch_values(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, + uint32 *pnum_values, char ***pnames, + struct registry_value ***pvalues) { REGVAL_CTR *ctr; char **names; @@ -199,42 +199,42 @@ NTSTATUS registry_fetch_values(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, uint32 i; if (!(ctr = TALLOC_ZERO_P(mem_ctx, REGVAL_CTR))) { - return NT_STATUS_NO_MEMORY; + return WERR_NOMEM; } if (fetch_reg_values(key, ctr) == -1) { TALLOC_FREE(ctr); - return NT_STATUS_INVALID_PARAMETER; + return WERR_INVALID_PARAM; } if (ctr->num_values == 0) { *pnum_values = 0; TALLOC_FREE(ctr); - return NT_STATUS_OK; + return WERR_OK; } if ((!(names = TALLOC_ARRAY(ctr, char *, ctr->num_values))) || (!(values = TALLOC_ARRAY(ctr, struct registry_value *, ctr->num_values)))) { TALLOC_FREE(ctr); - return NT_STATUS_NO_MEMORY; + return WERR_NOMEM; } for (i=0; i<ctr->num_values; i++) { REGISTRY_VALUE *val = ctr->values[i]; - NTSTATUS status; + WERROR err; if (!(names[i] = talloc_strdup(names, val->valuename))) { TALLOC_FREE(ctr); - return NT_STATUS_NO_MEMORY; + return WERR_NOMEM; } - status = registry_pull_value(values, &values[i], - val->type, val->data_p, - val->size, val->size); - if (!NT_STATUS_IS_OK(status)) { + err = registry_pull_value(values, &values[i], + val->type, val->data_p, + val->size, val->size); + if (!W_ERROR_IS_OK(err)) { TALLOC_FREE(ctr); - return status; + return err; } } @@ -243,7 +243,7 @@ NTSTATUS registry_fetch_values(TALLOC_CTX *mem_ctx, REGISTRY_KEY *key, *pvalues = talloc_move(mem_ctx, &values); TALLOC_FREE(ctr); - return NT_STATUS_OK; + return WERR_OK; } /*********************************************************************** @@ -310,7 +310,7 @@ WERROR regkey_open_onelevel( TALLOC_CTX *mem_ctx, REGISTRY_KEY *parent, REGISTRY_KEY *key; REGSUBKEY_CTR *subkeys = NULL; - DEBUG(7,("regkey_open_internal: name = [%s]\n", name)); + DEBUG(7,("regkey_open_onelevel: name = [%s]\n", name)); if ((parent != NULL) && ((parent->access_granted & SEC_RIGHTS_ENUM_SUBKEYS) == 0)) { @@ -365,7 +365,7 @@ WERROR regkey_open_onelevel( TALLOC_CTX *mem_ctx, REGISTRY_KEY *parent, /* Look up the table of registry I/O operations */ if ( !(key->hook = reghook_cache_find( key->name )) ) { - DEBUG(0,("open_registry_key: Failed to assigned a " + DEBUG(0,("reg_open_onelevel: Failed to assigned a " "REGISTRY_HOOK to [%s]\n", key->name )); result = WERR_BADFILE; goto done; @@ -403,13 +403,14 @@ done: return result; } -WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY *parent, - REGISTRY_KEY **regkey, const char *name, - NT_USER_TOKEN *token, uint32 access_desired ) +WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey, + const char *path, + const struct nt_user_token *token, + uint32 access_desired ) { TALLOC_CTX *mem_ctx; const char *p; - BOOL free_parent = False; + REGISTRY_KEY *parent = NULL; WERROR err; size_t len; @@ -417,21 +418,20 @@ WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY *parent, return WERR_NOMEM; } - len = strlen(name); - if ((len > 0) && (name[len-1] == '\\')) { - if (!(name = talloc_strndup(mem_ctx, name, len-1))) { + len = strlen(path); + if ((len > 0) && (path[len-1] == '\\')) { + if (!(path = talloc_strndup(mem_ctx, path, len-1))) { TALLOC_FREE(mem_ctx); return WERR_NOMEM; } } - while ((p = strchr(name, '\\')) != NULL) { + while ((p = strchr(path, '\\')) != NULL) { char *name_component; REGISTRY_KEY *intermediate; - if (!(name_component = talloc_strndup( - mem_ctx, name, (p - name)))) { + mem_ctx, path, (p - path)))) { TALLOC_FREE(mem_ctx); return WERR_NOMEM; } @@ -446,15 +446,12 @@ WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY *parent, return WERR_NOMEM; } - if (free_parent) { - TALLOC_FREE(parent); - } + TALLOC_FREE(parent); parent = intermediate; - free_parent = True; - name = p+1; + path = p+1; } - err = regkey_open_onelevel(ctx, parent, regkey, name, token, + err = regkey_open_onelevel(ctx, parent, regkey, path, token, access_desired); TALLOC_FREE(mem_ctx); return err; |