Samba CIFS implementation
Registry backend for REGF files
Copyright (C) 2005 Jelmer Vernooij, jelmer@samba.org
+ Copyright (C) 2006 Wilco Baan Hofman, wilco@baanhofman.nl
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/>. */
#include "includes.h"
-#include "registry.h"
+#include "lib/registry/registry.h"
#include "system/filesys.h"
#include "system/time.h"
#include "lib/registry/tdr_regf.h"
struct hbin_block *hbin = NULL;
int i;
+ *offset = 0;
+
if (size == 0)
return data_blob(NULL, 0);
}
if ((*ret)->data.length < vk->data_length) {
- DEBUG(1, ("Read data less then indicated data length!\n"));
+ DEBUG(1, ("Read data less than indicated data length!\n"));
}
return WERR_OK;
}
-static WERROR regf_get_subkey (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_key **ret)
+static WERROR regf_get_subkey_by_index (TALLOC_CTX *ctx, const struct registry_key *key, int idx, struct registry_key **ret)
{
DATA_BLOB data;
struct nk_block *nk = key->backend_data;
- uint32_t key_off;
+ uint32_t key_off=0;
if (idx >= nk->num_subkeys)
return WERR_NO_MORE_ITEMS;
}
if (!strncmp((char *)data.data, "li", 2)) {
- DEBUG(4, ("Subkeys in LI list\n"));
- SMB_ASSERT(0);
+ struct li_block li;
+ struct tdr_pull pull;
+
+ DEBUG(10, ("Subkeys in LI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li",2));
+
+ if (li.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ key_off = li.nk_offset[idx];
+
} else if (!strncmp((char *)data.data, "lf", 2)) {
struct lf_block lf;
struct tdr_pull pull;
DEBUG(0, ("Error parsing LF list\n"));
return WERR_GENERAL_FAILURE;
}
+ SMB_ASSERT(!strncmp(lf.header, "lf",2));
if (lf.key_count != nk->num_subkeys) {
DEBUG(0, ("Subkey counts don't match\n"));
return WERR_GENERAL_FAILURE;
}
- key_off = lf.hr[idx].nk_off;
- } else if (!strncmp((char *)data.data, "ri", 2)) {
- DEBUG(4, ("Subkeys in RI list\n"));
- SMB_ASSERT(0);
+ key_off = lf.hr[idx].nk_offset;
} else if (!strncmp((char *)data.data, "lh", 2)) {
- DEBUG(4, ("Subkeys in LH list\n"));
- SMB_ASSERT(0);
+ struct lh_block lh;
+ struct tdr_pull pull;
+
+ DEBUG(10, ("Subkeys in LH list"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh",2));
+
+ if (lh.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ key_off = lh.hr[idx].nk_offset;
+ } else if (!strncmp((char *)data.data, "ri", 2)) {
+ struct ri_block ri;
+ struct tdr_pull pull;
+ uint16_t i;
+ uint16_t sublist_count = 0;
+
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+ DEBUG(0, ("Error parsing RI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(ri.header, "ri",2));
+
+ for (i = 0; i < ri.key_count; i++) {
+ DATA_BLOB list_data;
+
+ /* Get sublist data blob */
+ list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
+ if (!list_data.data) {
+ DEBUG(0, ("Error getting RI list."));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = list_data;
+
+ if (!strncmp((char *)list_data.data, "li", 2)) {
+ struct li_block li;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li",2));
+
+ /* Advance to next sublist if necessary */
+ if (idx >= sublist_count + li.key_count) {
+ sublist_count += li.key_count;
+ continue;
+ }
+ key_off = li.nk_offset[idx - sublist_count];
+ sublist_count += li.key_count;
+ break;
+ } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+ struct lh_block lh;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh",2));
+
+
+ /* Advance to next sublist if necessary */
+ if (idx >= sublist_count + lh.key_count) {
+ sublist_count += lh.key_count;
+ continue;
+ }
+ key_off = lh.hr[idx - sublist_count].nk_offset;
+ sublist_count += lh.key_count;
+ break;
+ } else {
+ DEBUG(0,("Unknown sublist in ri block\n"));
+ SMB_ASSERT(0);
+ }
+
+ }
+
+ if (idx > sublist_count) {
+ return WERR_NO_MORE_ITEMS;
+ }
+
} else {
DEBUG(0, ("Unknown type for subkey list (0x%04x): %c%c\n", nk->subkeys_offset, data.data[0], data.data[1]));
return WERR_GENERAL_FAILURE;
return WERR_OK;
}
+static WERROR regf_match_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, uint32_t offset, const char *name, uint32_t *ret)
+{
+ DATA_BLOB subkey_data;
+ struct nk_block subkey;
+ struct tdr_pull pull;
+
+ subkey_data = hbin_get(key->hive->backend_data, offset);
+ if (!subkey_data.data) {
+ DEBUG(0, ("Unable to retrieve subkey HBIN\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = subkey_data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_nk_block(&pull, ctx, &subkey))) {
+ DEBUG(0, ("Error parsing NK structure.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ if (strncmp(subkey.header, "nk", 2)) {
+ DEBUG(0, ("Not an NK structure.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ if (!strcasecmp(subkey.key_name, name)) {
+ *ret = offset;
+ } else {
+ *ret = 0;
+ }
+ return WERR_OK;
+}
+
+static WERROR regf_get_subkey_by_name (TALLOC_CTX *ctx, const struct registry_key *key, const char *name, struct registry_key **ret)
+{
+ DATA_BLOB data;
+ struct nk_block *nk = key->backend_data;
+ uint32_t key_off = 0;
+
+ data = hbin_get(key->hive->backend_data, nk->subkeys_offset);
+ if (!data.data) {
+ DEBUG(0, ("Unable to find subkey list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ if (!strncmp((char *)data.data, "li",2)) {
+ struct li_block li;
+ struct tdr_pull pull;
+ uint16_t i;
+
+ DEBUG(10, ("Subkeys in LI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li",2));
+
+ if (li.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < li.key_count; i++) {
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, li.nk_offset[i], name, &key_off));
+ if (key_off) {
+ break;
+ }
+ }
+ if (!key_off) {
+ return WERR_DEST_NOT_FOUND;
+ }
+ } else if (!strncmp((char *)data.data, "lf",2)) {
+ struct lf_block lf;
+ struct tdr_pull pull;
+ uint16_t i;
+
+ DEBUG(10, ("Subkeys in LF list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lf_block(&pull, nk, &lf))) {
+ DEBUG(0, ("Error parsing LF list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lf.header, "lf",2));
+
+ if (lf.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ for (i = 0; i < lf.key_count; i++) {
+ if (strncmp(lf.hr[i].hash, name, 4)) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lf.hr[i].nk_offset, name, &key_off));
+ if (key_off) {
+ break;
+ }
+ }
+ if (!key_off) {
+ return WERR_DEST_NOT_FOUND;
+ }
+ } else if (!strncmp((char *)data.data, "lh",2)) {
+ struct lh_block lh;
+ struct tdr_pull pull;
+ uint16_t i;
+ uint32_t hash = 0;
+ char *hash_name;
+
+ DEBUG(10, ("Subkeys in LH list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh",2));
+
+ if (lh.key_count != nk->num_subkeys) {
+ DEBUG(0, ("Subkey counts don't match\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ /* Compute hash for the name */
+ hash_name = strupper_talloc(nk, name);
+ for (i = 0; *(hash_name + i) != 0; i++) {
+ hash *= 37;
+ hash += *(hash_name + i);
+ }
+ for (i = 0; i < lh.key_count; i++) {
+ if (lh.hr[i].base37 != hash) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key, lh.hr[i].nk_offset, name, &key_off));
+ if (key_off) {
+ break;
+ }
+ }
+ if (!key_off) {
+ return WERR_DEST_NOT_FOUND;
+ }
+ } else if (!strncmp((char *)data.data, "ri", 2)) {
+ struct ri_block ri;
+ struct tdr_pull pull;
+ uint16_t i, j;
+
+ DEBUG(10, ("Subkeys in RI list\n"));
+ ZERO_STRUCT(pull);
+ pull.data = data;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_ri_block(&pull, nk, &ri))) {
+ DEBUG(0, ("Error parsing RI list\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(ri.header, "ri",2));
+
+
+ for (i = 0; i < ri.key_count; i++) {
+ DATA_BLOB list_data;
+
+ /* Get sublist data blob */
+ list_data = hbin_get(key->hive->backend_data, ri.offset[i]);
+ if (!list_data.data) {
+ DEBUG(0, ("Error getting RI list."));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ ZERO_STRUCT(pull);
+ pull.data = list_data;
+
+ if (!strncmp((char *)list_data.data, "li", 2)) {
+ struct li_block li;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_li_block(&pull, nk, &li))) {
+ DEBUG(0, ("Error parsing LI list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(li.header, "li",2));
+
+ for (j = 0; j < li.key_count; j++) {
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
+ li.nk_offset[j], name, &key_off));
+ if (key_off) {
+ break;
+ }
+ }
+ } else if (!strncmp((char *)list_data.data, "lh", 2)) {
+ struct lh_block lh;
+ uint32_t hash = 0;
+ char *hash_name;
+
+ if (NT_STATUS_IS_ERR(tdr_pull_lh_block(&pull, nk, &lh))) {
+ DEBUG(0, ("Error parsing LH list from RI\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+ SMB_ASSERT(!strncmp(lh.header, "lh",2));
+
+ /* Compute hash for the name */
+ hash_name = strupper_talloc(nk, name);
+ for (j = 0; *(hash_name + j) != 0; j++) {
+ hash *= 37;
+ hash += *(hash_name + j);
+ }
+ for (j = 0; j < lh.key_count; j++) {
+ if (lh.hr[j].base37 != hash) {
+ continue;
+ }
+ W_ERROR_NOT_OK_RETURN(regf_match_subkey_by_name(nk, key,
+ lh.hr[j].nk_offset, name, &key_off));
+ if (key_off) {
+ break;
+ }
+ }
+ }
+ if (key_off) {
+ break;
+ }
+
+ }
+ if (!key_off) {
+ return WERR_DEST_NOT_FOUND;
+ }
+ } else {
+ DEBUG(0, ("Unknown subkey list type.\n"));
+ return WERR_GENERAL_FAILURE;
+ }
+
+ *ret = regf_get_key (ctx, key->hive->backend_data, key_off);
+ return WERR_OK;
+}
static WERROR regf_set_sec_desc (const struct registry_key *key, const struct security_descriptor *sec_desc)
{
uint32_t ret;
struct lf_block lf;
+ ZERO_STRUCT(lf);
+
/* Add to subkeys list */
if (list_offset == -1) { /* Need to create subkeys list */
lf.header = "lf";
- lf.key_count = 0;
- lf.hr = NULL;
} else {
if (!hbin_get_tdr(regf, list_offset, regf, (tdr_pull_fn_t)tdr_pull_lf_block, &lf)) {
DEBUG(0, ("Can't get subkeys list\n"));
}
lf.hr = talloc_realloc(regf, lf.hr, struct hash_record, lf.key_count+1);
- lf.hr[lf.key_count].nk_off = key_offset;
+ lf.hr[lf.key_count].nk_offset = key_offset;
lf.hr[lf.key_count].hash = talloc_strndup(regf, name, 4);
lf.key_count++;
regf->hbins = talloc_array(regf, struct hbin_block *, 1);
regf->hbins[0] = NULL;
- while (pull.offset < pull.data.length) {
+ while (pull.offset < pull.data.length && pull.offset < regf->header->last_block) {
struct hbin_block *hbin = talloc(regf->hbins, struct hbin_block);
if (NT_STATUS_IS_ERR(tdr_pull_hbin_block(&pull, hbin, hbin))) {
.open_hive = nt_open_hive,
.num_subkeys = regf_num_subkeys,
.num_values = regf_num_values,
- .get_subkey_by_index = regf_get_subkey,
+ .get_subkey_by_index = regf_get_subkey_by_index,
+ .get_subkey_by_name = regf_get_subkey_by_name,
.get_value_by_index = regf_get_value,
.key_get_sec_desc = regf_get_sec_desc,
.key_set_sec_desc = regf_set_sec_desc,