⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 regf.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 4 页
字号:
/*   Samba CIFS implementation   Registry backend for REGF files   Copyright (C) 2005-2007 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 3 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, see <http://www.gnu.org/licenses/>.  */#include "includes.h"#include "system/filesys.h"#include "system/time.h"#include "lib/registry/tdr_regf.h"#include "librpc/gen_ndr/ndr_security.h"#include "librpc/gen_ndr/winreg.h"#include "param/param.h"#include "lib/registry/registry.h"#include "libcli/security/security.h"static struct hive_operations reg_backend_regf;/** * There are several places on the web where the REGF format is explained; * * TODO: Links *//* TODO: *  - Return error codes that make more sense *  - Locking *  - do more things in-memory *//* * Read HBIN blocks into memory */struct regf_data {	int fd;	struct hbin_block **hbins;	struct regf_hdr *header;	struct smb_iconv_convenience *iconv_convenience;};static WERROR regf_save_hbin(struct regf_data *data);struct regf_key_data {	struct hive_key key;	struct regf_data *hive;	uint32_t offset;	struct nk_block *nk;};static struct hbin_block *hbin_by_offset(const struct regf_data *data,					 uint32_t offset, uint32_t *rel_offset){	int i;	for (i = 0; data->hbins[i]; i++) {		if (offset >= data->hbins[i]->offset_from_first &&			offset < data->hbins[i]->offset_from_first+					 data->hbins[i]->offset_to_next) {			if (rel_offset != NULL)				*rel_offset = offset - data->hbins[i]->offset_from_first - 0x20;			return data->hbins[i];		}	}	return NULL;}/** * Validate a regf header * For now, do nothing, but we should check the checksum */static uint32_t regf_hdr_checksum(const uint8_t *buffer){	uint32_t checksum = 0, x;	int i;	for (i = 0; i < 0x01FB; i+= 4) {		x = IVAL(buffer, i);		checksum ^= x;	}	return checksum;}/** * Obtain the contents of a HBIN block */static DATA_BLOB hbin_get(const struct regf_data *data, uint32_t offset){	DATA_BLOB ret;	struct hbin_block *hbin;	uint32_t rel_offset;	ret.data = NULL;	ret.length = 0;	hbin = hbin_by_offset(data, offset, &rel_offset);	if (hbin == NULL) {		DEBUG(1, ("Can't find HBIN containing 0x%04x\n", offset));		return ret;	}	ret.length = IVAL(hbin->data, rel_offset);	if (!(ret.length & 0x80000000)) {		DEBUG(0, ("Trying to use dirty block at 0x%04x\n", offset));		return ret;	}	/* remove high bit */	ret.length = (ret.length ^ 0xffffffff) + 1;	ret.length -= 4; /* 4 bytes for the length... */	ret.data = hbin->data +		(offset - hbin->offset_from_first - 0x20) + 4;	return ret;}static bool hbin_get_tdr(struct regf_data *regf, uint32_t offset,			 TALLOC_CTX *ctx, tdr_pull_fn_t pull_fn, void *p){	struct tdr_pull *pull = tdr_pull_init(regf, regf->iconv_convenience);	pull->data = hbin_get(regf, offset);	if (!pull->data.data) {		DEBUG(1, ("Unable to get data at 0x%04x\n", offset));		talloc_free(pull);		return false;	}	if (NT_STATUS_IS_ERR(pull_fn(pull, ctx, p))) {		DEBUG(1, ("Error parsing record at 0x%04x using tdr\n",			offset));		talloc_free(pull);		return false;	}	talloc_free(pull);	return true;}/* Allocate some new data */static DATA_BLOB hbin_alloc(struct regf_data *data, uint32_t size,			    uint32_t *offset){	DATA_BLOB ret;	uint32_t rel_offset = -1; /* Relative offset ! */	struct hbin_block *hbin = NULL;	int i;	*offset = 0;	if (size == 0)		return data_blob(NULL, 0);	size += 4; /* Need to include int32 for the length */	/* Allocate as a multiple of 8 */	size = (size + 7) & ~7;	ret.data = NULL;	ret.length = 0;	for (i = 0; (hbin = data->hbins[i]); i++) {		int j;		int32_t my_size;		for (j = 0; j < hbin->offset_to_next-0x20; j+= my_size) {			my_size = IVALS(hbin->data, j);			if (my_size == 0x0) {				DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));				return ret;			}			if (my_size % 8 != 0) {				DEBUG(0, ("Encountered non-aligned block!\n"));			}			if (my_size < 0) { /* Used... */				my_size = -my_size;			} else if (my_size == size) { /* exact match */				rel_offset = j;				DEBUG(4, ("Found free block of exact size %d in middle of HBIN\n",					size));				break;			} else if (my_size > size) { /* data will remain */				rel_offset = j;				/* Split this block and mark the next block as free */				SIVAL(hbin->data, rel_offset+size, my_size-size);				DEBUG(4, ("Found free block of size %d (needing %d) in middle of HBIN\n",					my_size, size));				break;			}		}		if (rel_offset != -1)			break;	}	/* No space available in previous hbins,	 * allocate new one */	if (data->hbins[i] == NULL) {		DEBUG(4, ("No space available in other HBINs for block of size %d, allocating new HBIN\n",			size));		data->hbins = talloc_realloc(data, data->hbins,					     struct hbin_block *, i+2);		hbin = talloc(data->hbins, struct hbin_block);		SMB_ASSERT(hbin != NULL);		data->hbins[i] = hbin;		data->hbins[i+1] = NULL;		hbin->HBIN_ID = talloc_strdup(hbin, "hbin");		hbin->offset_from_first = (i == 0?0:data->hbins[i-1]->offset_from_first+data->hbins[i-1]->offset_to_next);		hbin->offset_to_next = 0x1000;		hbin->unknown[0] = 0;		hbin->unknown[0] = 0;		unix_to_nt_time(&hbin->last_change, time(NULL));		hbin->block_size = hbin->offset_to_next;		hbin->data = talloc_zero_array(hbin, uint8_t, hbin->block_size - 0x20);		rel_offset = 0x0;		SIVAL(hbin->data, size, hbin->block_size - size - 0x20);	}	/* Set size and mark as used */	SIVAL(hbin->data, rel_offset, -size);	ret.data = hbin->data + rel_offset + 0x4; /* Skip past length */	ret.length = size - 0x4;	if (offset) {		uint32_t new_rel_offset;		*offset = hbin->offset_from_first + rel_offset + 0x20;		SMB_ASSERT(hbin_by_offset(data, *offset, &new_rel_offset) == hbin);		SMB_ASSERT(new_rel_offset == rel_offset);	}	return ret;}/* Store a data blob. Return the offset at which it was stored */static uint32_t hbin_store (struct regf_data *data, DATA_BLOB blob){	uint32_t ret;	DATA_BLOB dest = hbin_alloc(data, blob.length, &ret);	memcpy(dest.data, blob.data, blob.length);	return ret;}static uint32_t hbin_store_tdr(struct regf_data *data,			       tdr_push_fn_t push_fn, void *p){	struct tdr_push *push = tdr_push_init(data, data->iconv_convenience);	uint32_t ret;	if (NT_STATUS_IS_ERR(push_fn(push, p))) {		DEBUG(0, ("Error during push\n"));		return -1;	}	ret = hbin_store(data, push->data);	talloc_free(push);	return ret;}/* Free existing data */static void hbin_free (struct regf_data *data, uint32_t offset){	int32_t size;	uint32_t rel_offset;	int32_t next_size;	struct hbin_block *hbin;	SMB_ASSERT (offset > 0);	hbin = hbin_by_offset(data, offset, &rel_offset);	if (hbin == NULL)		return;	/* Get original size */	size = IVALS(hbin->data, rel_offset);	if (size > 0) {		DEBUG(1, ("Trying to free already freed block at 0x%04x\n",			offset));		return;	}	/* Mark as unused */	size = -size;	/* If the next block is free, merge into big free block */	if (rel_offset + size < hbin->offset_to_next) {		next_size = IVALS(hbin->data, rel_offset+size);		if (next_size > 0) {			size += next_size;		}	}	/* Write block size */	SIVALS(hbin->data, rel_offset, size);}/** * Store a data blob data was already stored, but has changed in size * Will try to save it at the current location if possible, otherwise * does a free + store */static uint32_t hbin_store_resize(struct regf_data *data,				  uint32_t orig_offset, DATA_BLOB blob){	uint32_t rel_offset;	struct hbin_block *hbin = hbin_by_offset(data, orig_offset,						 &rel_offset);	int32_t my_size;	int32_t orig_size;	int32_t needed_size;	int32_t possible_size;	int i;	SMB_ASSERT(orig_offset > 0);	if (!hbin)		return hbin_store(data, blob);	/* Get original size */	orig_size = -IVALS(hbin->data, rel_offset);	needed_size = blob.length + 4; /* Add int32 containing length */	needed_size = (needed_size + 7) & ~7; /* Align */	/* Fits into current allocated block */	if (orig_size >= needed_size) {		memcpy(hbin->data + rel_offset + 0x4, blob.data, blob.length);		/* If the difference in size is greater than 0x4, split the block		 * and free/merge it */		if (orig_size - needed_size > 0x4) {			SIVALS(hbin->data, rel_offset, -needed_size);			SIVALS(hbin->data, rel_offset + needed_size,			       needed_size-orig_size);			hbin_free(data, orig_offset + needed_size);		}		return orig_offset;	}	possible_size = orig_size;	/* Check if it can be combined with the next few free records */	for (i = rel_offset; i < hbin->offset_to_next - 0x20; i += my_size) {		if (IVALS(hbin->data, i) < 0) /* Used */			break;		my_size = IVALS(hbin->data, i);		if (my_size == 0x0) {			DEBUG(0, ("Invalid zero-length block! File is corrupt.\n"));			break;		} else {			possible_size += my_size;		}		if (possible_size >= blob.length) {			SIVAL(hbin->data, rel_offset, -possible_size);			memcpy(hbin->data + rel_offset + 0x4,			       blob.data, blob.length);			return orig_offset;		}	}	hbin_free(data, orig_offset);	return hbin_store(data, blob);}static uint32_t hbin_store_tdr_resize(struct regf_data *regf,				      tdr_push_fn_t push_fn,				      uint32_t orig_offset, void *p){	struct tdr_push *push = tdr_push_init(regf, regf->iconv_convenience);	uint32_t ret;	if (NT_STATUS_IS_ERR(push_fn(push, p))) {		DEBUG(0, ("Error during push\n"));		return -1;	}	ret = hbin_store_resize(regf, orig_offset, push->data);	talloc_free(push);	return ret;}static uint32_t regf_create_lh_hash(const char *name){	char *hash_name;	uint32_t ret = 0;	uint16_t i;	hash_name = strupper_talloc(NULL, name);	for (i = 0; *(hash_name + i) != 0; i++) {		ret *= 37;		ret += *(hash_name + i);	}	talloc_free(hash_name);	return ret;}static WERROR regf_get_info(TALLOC_CTX *mem_ctx,			    const struct hive_key *key,			    const char **classname,			    uint32_t *num_subkeys,			    uint32_t *num_values,			    NTTIME *last_mod_time,			    uint32_t *max_subkeynamelen,			    uint32_t *max_valnamelen,			    uint32_t *max_valbufsize){	const struct regf_key_data *private_data =		(const struct regf_key_data *)key;	if (num_subkeys != NULL)		*num_subkeys = private_data->nk->num_subkeys;	if (num_values != NULL)		*num_values = private_data->nk->num_values;	if (classname != NULL) {		if (private_data->nk->clsname_offset != -1) {			DATA_BLOB data = hbin_get(private_data->hive,						  private_data->nk->clsname_offset);			*classname = talloc_strndup(mem_ctx,						    (char*)data.data,						    private_data->nk->clsname_length);		} else			*classname = NULL;	}	/* TODO: Last mod time */	/* TODO: max valnamelen */		/* TODO: max valbufsize */	/* TODO: max subkeynamelen */	return WERR_OK;}static struct regf_key_data *regf_get_key(TALLOC_CTX *ctx,					  struct regf_data *regf,					  uint32_t offset){	struct nk_block *nk;	struct regf_key_data *ret;	ret = talloc_zero(ctx, struct regf_key_data);	ret->key.ops = &reg_backend_regf;	ret->hive = talloc_reference(ret, regf);	ret->offset = offset;	nk = talloc(ret, struct nk_block);	if (nk == NULL)		return NULL;	ret->nk = nk;	if (!hbin_get_tdr(regf, offset, nk,			  (tdr_pull_fn_t)tdr_pull_nk_block, nk)) {		DEBUG(0, ("Unable to find HBIN data for offset %d\n", offset));		return NULL;	}	if (strcmp(nk->header, "nk") != 0) {		DEBUG(0, ("Expected nk record, got %s\n", nk->header));		talloc_free(ret);		return NULL;	}	return ret;}static WERROR regf_get_value(TALLOC_CTX *ctx, struct hive_key *key,			     int idx, const char **name,			     uint32_t *data_type, DATA_BLOB *data){	const struct regf_key_data *private_data =			(const struct regf_key_data *)key;	struct vk_block *vk;	struct regf_data *regf = private_data->hive;	uint32_t vk_offset;	DATA_BLOB tmp;	if (idx >= private_data->nk->num_values)		return WERR_NO_MORE_ITEMS;	tmp = hbin_get(regf, private_data->nk->values_offset);	if (!tmp.data) {		DEBUG(0, ("Unable to find value list\n"));		return WERR_GENERAL_FAILURE;	}	if (tmp.length < private_data->nk->num_values * 4) {		DEBUG(1, ("Value counts mismatch\n"));	}	vk_offset = IVAL(tmp.data, idx * 4);	vk = talloc(NULL, struct vk_block);	W_ERROR_HAVE_NO_MEMORY(vk);	if (!hbin_get_tdr(regf, vk_offset, vk,			  (tdr_pull_fn_t)tdr_pull_vk_block, vk)) {		DEBUG(0, ("Unable to get VK block at %d\n", vk_offset));		talloc_free(vk);		return WERR_GENERAL_FAILURE;	}	/* FIXME: name character set ?*/	if (name != NULL)		*name = talloc_strndup(ctx, vk->data_name, vk->name_length);	if (data_type != NULL)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -