mirror of
https://github.com/samba-team/samba.git
synced 2024-12-27 03:21:53 +03:00
r181: Parsing windows '95 registry files now works (including values)
(This used to be commit 4d6ce64856
)
This commit is contained in:
parent
24cd656ab0
commit
49d54f0298
@ -268,7 +268,10 @@ WERROR reg_key_get_subkey_by_index(REG_KEY *key, int idx, REG_KEY **subkey)
|
||||
{
|
||||
if(!key) return WERR_INVALID_PARAM;
|
||||
|
||||
if(!key->handle->functions->get_subkey_by_index) {
|
||||
if(key->handle->functions->get_subkey_by_index) {
|
||||
WERROR status = key->handle->functions->get_subkey_by_index(key, idx, subkey);
|
||||
if(!NT_STATUS_IS_OK(status)) return status;
|
||||
} else if(key->handle->functions->fetch_subkeys) {
|
||||
if(!key->cache_subkeys)
|
||||
key->handle->functions->fetch_subkeys(key, &key->cache_subkeys_count, &key->cache_subkeys);
|
||||
|
||||
@ -278,8 +281,7 @@ WERROR reg_key_get_subkey_by_index(REG_KEY *key, int idx, REG_KEY **subkey)
|
||||
return WERR_NO_MORE_ITEMS;
|
||||
}
|
||||
} else {
|
||||
WERROR status = key->handle->functions->get_subkey_by_index(key, idx, subkey);
|
||||
if(!NT_STATUS_IS_OK(status)) return status;
|
||||
return WERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
(*subkey)->path = talloc_asprintf((*subkey)->mem_ctx, "%s%s%s", key->path, key->path[strlen(key->path)-1] == '\\'?"":"\\", (*subkey)->name);
|
||||
|
@ -26,7 +26,19 @@
|
||||
* The registry starts with a header that contains pointers to
|
||||
* the rgdb.
|
||||
*
|
||||
* After the main header follows the RGKN header (key index table) */
|
||||
* After the main header follows the RGKN header (key index table).
|
||||
* The RGKN keys are listed after each other. They are put into
|
||||
* blocks, the first having a length of 0x2000 bytes, the others
|
||||
* being 0x1000 bytes long.
|
||||
*
|
||||
* After the RGKN header follow one or more RGDB blocks. These blocks
|
||||
* contain keys. A key is followed by its name and its values.
|
||||
*
|
||||
* Values are followed by their name and then their data.
|
||||
*
|
||||
* Basically the idea is that the RGKN contains the associations between
|
||||
* the keys and the RGDB contains the actual data.
|
||||
*/
|
||||
|
||||
typedef unsigned int DWORD;
|
||||
typedef unsigned short WORD;
|
||||
@ -54,17 +66,22 @@ typedef struct rgkn_block {
|
||||
DWORD uk2;
|
||||
} RGKN_HDR;
|
||||
|
||||
typedef struct rgkn_key {
|
||||
DWORD type;
|
||||
DWORD hash;
|
||||
DWORD next_free;
|
||||
DWORD parent;
|
||||
DWORD child;
|
||||
DWORD next;
|
||||
typedef struct reg_id {
|
||||
WORD id;
|
||||
WORD rgdb;
|
||||
} REG_ID;
|
||||
|
||||
typedef struct rgkn_key {
|
||||
DWORD type; /* 0x00000000 = normal key, 0x80000000 = free block */
|
||||
DWORD hash; /* Contains either hash or size of free blocks that follows */
|
||||
DWORD next_free;
|
||||
DWORD parent_offset;
|
||||
DWORD first_child_offset;
|
||||
DWORD next_offset;
|
||||
REG_ID id;
|
||||
} RGKN_KEY;
|
||||
|
||||
|
||||
typedef struct rgdb_block {
|
||||
DWORD RGDB_ID; /* RGDB */
|
||||
DWORD size;
|
||||
@ -79,21 +96,19 @@ typedef struct rgdb_block {
|
||||
} RGDB_HDR;
|
||||
|
||||
typedef struct rgdb_key {
|
||||
DWORD type;
|
||||
DWORD hash;
|
||||
DWORD next_free;
|
||||
DWORD parent;
|
||||
DWORD child;
|
||||
DWORD next;
|
||||
WORD id;
|
||||
WORD rgdb;
|
||||
DWORD size;
|
||||
REG_ID id;
|
||||
DWORD used_size;
|
||||
WORD name_len;
|
||||
WORD num_values;
|
||||
DWORD uk1;
|
||||
} RGDB_KEY;
|
||||
|
||||
typedef struct rgdb_value {
|
||||
DWORD type;
|
||||
DWORD uk1;
|
||||
DWORD name_len;
|
||||
DWORD data_len;
|
||||
WORD name_len;
|
||||
WORD data_len;
|
||||
} RGDB_VALUE;
|
||||
|
||||
typedef struct creg_struct_s {
|
||||
@ -103,9 +118,16 @@ typedef struct creg_struct_s {
|
||||
struct stat sbuf;
|
||||
CREG_HDR *creg_hdr;
|
||||
RGKN_HDR *rgkn_hdr;
|
||||
char *rgkn;
|
||||
RGDB_KEY ***rgdb_keys;
|
||||
} CREG;
|
||||
|
||||
#define RGKN_START_SIZE 0x2000
|
||||
#define RGKN_INC_SIZE 0x1000
|
||||
|
||||
#define LOCN_RGKN(creg, o) ((RGKN_KEY *)((creg)->base + sizeof(CREG_HDR) + o))
|
||||
#define LOCN_RGDB_BLOCK(creg, o) (((creg)->base + (creg)->creg_hdr->rgdb_offset + o))
|
||||
#define LOCN_RGDB_KEY(creg, rgdb, id) ((RGDB_KEY *)((creg)->rgdb_keys[(rgdb)][(id)]))
|
||||
|
||||
static DWORD str_to_dword(const char *a) {
|
||||
int i;
|
||||
unsigned long ret = 0;
|
||||
@ -115,7 +137,86 @@ static DWORD str_to_dword(const char *a) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define LOCN(creg, o) (((creg)->base + sizeof(CREG_HDR) + o))
|
||||
static DWORD calc_hash(const char *str) {
|
||||
DWORD ret = 0;
|
||||
int i;
|
||||
for(i = 0; str[i] && str[i] != '\\'; i++) {
|
||||
ret+=toupper(str[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void parse_rgkn_block(CREG *creg, off_t start_off, off_t end_off)
|
||||
{
|
||||
off_t i;
|
||||
for(i = start_off; end_off - i > sizeof(RGKN_KEY); i+= sizeof(RGKN_KEY)) {
|
||||
RGKN_KEY *key = (RGKN_KEY *)LOCN_RGKN(creg, i);
|
||||
if(key->type == 0) {
|
||||
DEBUG(4,("Regular, id: %d, %d, parent: %x, firstchild: %x, next: %x hash: %lX\n", key->id.id, key->id.rgdb, key->parent_offset, key->first_child_offset, key->next_offset, key->hash));
|
||||
} else if(key->type == 0x80000000) {
|
||||
DEBUG(3,("free\n"));
|
||||
i += key->hash;
|
||||
} else {
|
||||
DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_rgdb_block(CREG *creg, RGDB_HDR *rgdb_hdr)
|
||||
{
|
||||
DWORD used_size = rgdb_hdr->size - rgdb_hdr->unused_size;
|
||||
DWORD offset = 0;
|
||||
|
||||
while(offset < used_size) {
|
||||
RGDB_KEY *key = (RGDB_KEY *)(((char *)rgdb_hdr) + sizeof(RGDB_HDR) + offset);
|
||||
|
||||
if(!(key->id.id == 0xFFFF && key->id.rgdb == 0xFFFF))creg->rgdb_keys[key->id.rgdb][key->id.id] = key;
|
||||
offset += key->size;
|
||||
}
|
||||
}
|
||||
|
||||
static WERROR w95_open_root (REG_HANDLE *h, REG_KEY **key)
|
||||
{
|
||||
CREG *creg = h->backend_data;
|
||||
|
||||
/* First element in rgkn should be root key */
|
||||
*key = reg_key_new_abs("\\", h, LOCN_RGKN(creg, sizeof(RGKN_HDR)));
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static WERROR w95_get_subkey_by_index (REG_KEY *parent, int n, REG_KEY **key)
|
||||
{
|
||||
CREG *creg = parent->handle->backend_data;
|
||||
RGKN_KEY *rgkn_key = parent->backend_data;
|
||||
RGKN_KEY *child;
|
||||
DWORD child_offset;
|
||||
DWORD cur = 0;
|
||||
|
||||
/* Get id of first child */
|
||||
child_offset = rgkn_key->first_child_offset;
|
||||
|
||||
while(child_offset != 0xFFFFFFFF) {
|
||||
child = LOCN_RGKN(creg, child_offset);
|
||||
|
||||
/* n == cur ? return! */
|
||||
if(cur == n) {
|
||||
RGDB_KEY *rgdb_key;
|
||||
char *name;
|
||||
rgdb_key = LOCN_RGDB_KEY(creg, child->id.rgdb, child->id.id);
|
||||
name = strndup((char *)rgdb_key + sizeof(RGDB_KEY), rgdb_key->name_len);
|
||||
*key = reg_key_new_rel(name, parent, child);
|
||||
SAFE_FREE(name);
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
cur++;
|
||||
|
||||
child_offset = child->next_offset;
|
||||
}
|
||||
|
||||
return WERR_NO_MORE_ITEMS;
|
||||
}
|
||||
|
||||
static WERROR w95_open_reg (REG_HANDLE *h, const char *location, const char *credentials)
|
||||
{
|
||||
@ -124,7 +225,7 @@ static WERROR w95_open_reg (REG_HANDLE *h, const char *location, const char *cre
|
||||
memset(creg, 0, sizeof(CREG));
|
||||
h->backend_data = creg;
|
||||
DWORD i, nfree = 0;
|
||||
DWORD offset;
|
||||
DWORD offset, end_offset;
|
||||
|
||||
if((creg->fd = open(location, O_RDONLY, 0000)) < 0) {
|
||||
return WERR_FOOBAR;
|
||||
@ -149,7 +250,7 @@ static WERROR w95_open_reg (REG_HANDLE *h, const char *location, const char *cre
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
creg->rgkn_hdr = (RGKN_HDR *)LOCN(creg, 0);
|
||||
creg->rgkn_hdr = (RGKN_HDR *)LOCN_RGKN(creg, 0);
|
||||
|
||||
if ((rgkn_id = IVAL(&creg->rgkn_hdr->RGKN_ID,0)) != str_to_dword("RGKN")) {
|
||||
DEBUG(0, ("Unrecognized Windows 95 registry key index id: 0x%0X, %s\n",
|
||||
@ -157,38 +258,39 @@ static WERROR w95_open_reg (REG_HANDLE *h, const char *location, const char *cre
|
||||
return WERR_FOOBAR;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for(i = 0; i < creg->rgkn_hdr->size; i+=sizeof(RGKN_KEY)) {
|
||||
RGKN_KEY *key = (RGKN_KEY *)LOCN(creg, sizeof(RGKN_HDR) + i);
|
||||
if(nfree > 0) {
|
||||
nfree--;
|
||||
} else if(key->type == 0) {
|
||||
DEBUG(0,("Not used\n"));
|
||||
/* Not used */
|
||||
} else if(key->type == 0x80000000) {
|
||||
DEBUG(0,("Regular key\n"));
|
||||
/* Regular key */
|
||||
} else {
|
||||
DEBUG(0,("Invalid key type in RGKN: %0X\n", key->type));
|
||||
}
|
||||
#if 0
|
||||
/* If'ed out because we only need to parse this stuff when allocating new
|
||||
* entries (which we don't do at the moment */
|
||||
/* First parse the 0x2000 long block */
|
||||
parse_rgkn_block(creg, sizeof(RGKN_HDR), 0x2000);
|
||||
|
||||
/* Then parse the other 0x1000 length blocks */
|
||||
for(offset = 0x2000; offset < creg->rgkn_hdr->size; offset+=0x1000) {
|
||||
parse_rgkn_block(creg, offset, offset+0x1000);
|
||||
}
|
||||
|
||||
curpos += creg->rgkn_hdr->size + sizeof(RGKN_HDR);
|
||||
#endif
|
||||
offset = creg->rgkn_hdr->size;
|
||||
|
||||
DEBUG(0, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
|
||||
creg->rgdb_keys = talloc_array_p(h->mem_ctx, RGDB_KEY **, creg->creg_hdr->num_rgdb);
|
||||
|
||||
offset = 0;
|
||||
DEBUG(3, ("Reading %d rgdb entries\n", creg->creg_hdr->num_rgdb));
|
||||
for(i = 0; i < creg->creg_hdr->num_rgdb; i++) {
|
||||
RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN(creg, offset);
|
||||
RGDB_HDR *rgdb_hdr = (RGDB_HDR *)LOCN_RGDB_BLOCK(creg, offset);
|
||||
|
||||
if(strncmp((char *)&(rgdb_hdr->RGDB_ID), "RGDB", 4)) {
|
||||
DEBUG(0, ("unrecognized rgdb entry: %4s, %s\n",
|
||||
&rgdb_hdr->RGDB_ID, location));
|
||||
return WERR_FOOBAR;
|
||||
} else {
|
||||
DEBUG(0, ("Valid rgdb entry\n"));
|
||||
DEBUG(3, ("Valid rgdb entry, first free id: %d, max id: %d\n", rgdb_hdr->first_free_id, rgdb_hdr->max_id));
|
||||
}
|
||||
|
||||
|
||||
creg->rgdb_keys[i] = talloc_array_p(h->mem_ctx, RGDB_KEY *, rgdb_hdr->max_id+1);
|
||||
memset(creg->rgdb_keys[i], 0, sizeof(RGDB_KEY *) * (rgdb_hdr->max_id+1));
|
||||
|
||||
parse_rgdb_block(creg, rgdb_hdr);
|
||||
|
||||
offset+=rgdb_hdr->size;
|
||||
}
|
||||
|
||||
@ -205,10 +307,49 @@ static WERROR w95_close_reg(REG_HANDLE *h)
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
|
||||
static WERROR w95_fetch_values(REG_KEY *k, int *count, REG_VAL ***values)
|
||||
{
|
||||
RGKN_KEY *rgkn_key = k->backend_data;
|
||||
RGDB_VALUE *val;
|
||||
DWORD i;
|
||||
DWORD offset = 0;
|
||||
RGDB_KEY *rgdb_key = LOCN_RGDB_KEY((CREG *)k->handle->backend_data, rgkn_key->id.rgdb, rgkn_key->id.id);
|
||||
|
||||
if(!rgdb_key) return WERR_FOOBAR;
|
||||
|
||||
*count = rgdb_key->num_values;
|
||||
|
||||
if((*count) == 0) return WERR_OK;
|
||||
|
||||
(*values) = talloc_array_p(k->mem_ctx, REG_VAL *, (*count)+1);
|
||||
for(i = 0; i < rgdb_key->num_values; i++) {
|
||||
RGDB_VALUE *val = (RGDB_VALUE *)(((char *)rgdb_key) + sizeof(RGDB_KEY) + rgdb_key->name_len + offset);
|
||||
(*values)[i] = reg_val_new(k, val);
|
||||
|
||||
/* Name */
|
||||
(*values)[i]->name = talloc_strndup(k->mem_ctx, (char *)val+sizeof(RGDB_VALUE), val->name_len);
|
||||
|
||||
/* Value */
|
||||
(*values)[i]->data_len = val->data_len;
|
||||
(*values)[i]->data_blk = talloc_memdup((*values)[i]->mem_ctx, (char *)val+sizeof(RGDB_VALUE)+val->name_len, val->data_len);
|
||||
|
||||
/* Type */
|
||||
(*values)[i]->data_type = val->type;
|
||||
|
||||
offset+=sizeof(RGDB_VALUE) + val->name_len + val->data_len;
|
||||
}
|
||||
|
||||
return WERR_OK;
|
||||
}
|
||||
|
||||
static struct registry_ops reg_backend_w95 = {
|
||||
.name = "w95",
|
||||
.open_registry = w95_open_reg,
|
||||
.close_registry = w95_close_reg,
|
||||
.open_root_key = w95_open_root,
|
||||
.fetch_values = w95_fetch_values,
|
||||
.get_subkey_by_index = w95_get_subkey_by_index,
|
||||
};
|
||||
|
||||
NTSTATUS reg_w95_init(void)
|
||||
|
Loading…
Reference in New Issue
Block a user