2007-08-26 15:16:40 +00:00
/*
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 .
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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 .
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>. */
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
# 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"
2008-04-02 13:59:48 +02:00
# include "lib/registry/registry.h"
2008-04-14 22:52:51 +02:00
# include "libcli/security/security.h"
2007-08-26 15:16:40 +00:00
static struct hive_operations reg_backend_regf ;
/**
2007-10-06 00:17:44 +00:00
* There are several places on the web where the REGF format is explained ;
2007-08-26 15:16:40 +00:00
*
* 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 ;
2007-12-13 22:46:47 +01:00
struct smb_iconv_convenience * iconv_convenience ;
2007-08-26 15:16:40 +00:00
} ;
static WERROR regf_save_hbin ( struct regf_data * data ) ;
struct regf_key_data {
struct hive_key key ;
2007-10-06 00:17:44 +00:00
struct regf_data * hive ;
2007-08-26 15:16:40 +00:00
uint32_t offset ;
struct nk_block * nk ;
} ;
2007-10-06 00:17:44 +00:00
static struct hbin_block * hbin_by_offset ( const struct regf_data * data ,
uint32_t offset , uint32_t * rel_offset )
2007-08-26 15:16:40 +00:00
{
int i ;
for ( i = 0 ; data - > hbins [ i ] ; i + + ) {
2007-10-06 00:17:44 +00:00
if ( offset > = data - > hbins [ i ] - > offset_from_first & &
2007-08-26 15:16:40 +00:00
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 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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... */
2007-10-06 00:17:44 +00:00
ret . data = hbin - > data +
2007-08-26 15:16:40 +00:00
( offset - hbin - > offset_from_first - 0x20 ) + 4 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
return ret ;
}
2007-10-06 00:17:44 +00:00
static bool hbin_get_tdr ( struct regf_data * regf , uint32_t offset ,
TALLOC_CTX * ctx , tdr_pull_fn_t pull_fn , void * p )
2007-08-26 15:16:40 +00:00
{
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = hbin_get ( regf , offset ) ;
if ( ! pull - > data . data ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 1 , ( " Unable to get data at 0x%04x \n " , offset ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return false ;
}
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( pull_fn ( pull , ctx , p ) ) ) {
2007-10-06 00:17:44 +00:00
DEBUG ( 1 , ( " Error parsing record at 0x%04x using tdr \n " ,
offset ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return false ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return true ;
}
/* Allocate some new data */
2007-10-06 00:17:44 +00:00
static DATA_BLOB hbin_alloc ( struct regf_data * data , uint32_t size ,
uint32_t * offset )
2007-08-26 15:16:40 +00:00
{
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 ;
2007-10-06 00:17:44 +00:00
DEBUG ( 4 , ( " Found free block of exact size %d in middle of HBIN \n " ,
size ) ) ;
2007-08-26 15:16:40 +00:00
break ;
} else if ( my_size > size ) { /* data will remain */
rel_offset = j ;
/* Split this block and mark the next block as free */
2007-10-06 00:17:44 +00:00
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 ) ) ;
2007-08-26 15:16:40 +00:00
break ;
}
}
if ( rel_offset ! = - 1 )
break ;
}
2007-10-06 00:17:44 +00:00
/* No space available in previous hbins,
2007-08-26 15:16:40 +00:00
* allocate new one */
2007-10-06 00:17:44 +00:00
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 ) ;
2007-08-26 15:16:40 +00:00
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 ) ;
2009-10-08 12:36:30 +02:00
/* Make sure that we have no tailing garbage in the block */
if ( dest . length > blob . length ) {
memset ( dest . data + blob . length , 0 , dest . length - blob . length ) ;
}
2007-08-26 15:16:40 +00:00
return ret ;
}
2007-10-06 00:17:44 +00:00
static uint32_t hbin_store_tdr ( struct regf_data * data ,
tdr_push_fn_t push_fn , void * p )
2007-08-26 15:16:40 +00:00
{
2007-12-13 22:46:47 +01:00
struct tdr_push * push = tdr_push_init ( data , data - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint32_t ret ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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 ;
2007-10-06 00:17:44 +00:00
int32_t next_size ;
2007-08-26 15:16:40 +00:00
struct hbin_block * hbin ;
SMB_ASSERT ( offset > 0 ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
hbin = hbin_by_offset ( data , offset , & rel_offset ) ;
if ( hbin = = NULL )
return ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Get original size */
size = IVALS ( hbin - > data , rel_offset ) ;
if ( size > 0 ) {
2007-10-06 00:17:44 +00:00
DEBUG ( 1 , ( " Trying to free already freed block at 0x%04x \n " ,
offset ) ) ;
2007-08-26 15:16:40 +00:00
return ;
}
/* Mark as unused */
size = - size ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* 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
2007-10-06 00:17:44 +00:00
* Will try to save it at the current location if possible , otherwise
2007-08-26 15:16:40 +00:00
* does a free + store */
2007-10-06 00:17:44 +00:00
static uint32_t hbin_store_resize ( struct regf_data * data ,
uint32_t orig_offset , DATA_BLOB blob )
2007-08-26 15:16:40 +00:00
{
uint32_t rel_offset ;
2007-10-06 00:17:44 +00:00
struct hbin_block * hbin = hbin_by_offset ( data , orig_offset ,
& rel_offset ) ;
2007-08-26 15:16:40 +00:00
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 ) ;
2007-10-06 00:17:44 +00:00
SIVALS ( hbin - > data , rel_offset + needed_size ,
needed_size - orig_size ) ;
2007-08-26 15:16:40 +00:00
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 ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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 ) ;
2007-10-06 00:17:44 +00:00
memcpy ( hbin - > data + rel_offset + 0x4 ,
blob . data , blob . length ) ;
2007-08-26 15:16:40 +00:00
return orig_offset ;
}
}
hbin_free ( data , orig_offset ) ;
return hbin_store ( data , blob ) ;
}
2007-10-06 00:17:44 +00:00
static uint32_t hbin_store_tdr_resize ( struct regf_data * regf ,
tdr_push_fn_t push_fn ,
uint32_t orig_offset , void * p )
2007-08-26 15:16:40 +00:00
{
2007-12-13 22:46:47 +01:00
struct tdr_push * push = tdr_push_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint32_t ret ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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 ;
}
2007-10-06 00:17:44 +00:00
static uint32_t regf_create_lh_hash ( const char * name )
2007-08-26 15:16:40 +00:00
{
char * hash_name ;
uint32_t ret = 0 ;
uint16_t i ;
2007-10-06 00:17:44 +00:00
hash_name = strupper_talloc ( NULL , name ) ;
2007-08-26 15:16:40 +00:00
for ( i = 0 ; * ( hash_name + i ) ! = 0 ; i + + ) {
ret * = 37 ;
ret + = * ( hash_name + i ) ;
}
talloc_free ( hash_name ) ;
return ret ;
}
2007-10-06 00:17:44 +00:00
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 ,
2008-01-07 14:11:29 -06:00
NTTIME * last_mod_time ,
uint32_t * max_subkeynamelen ,
uint32_t * max_valnamelen ,
uint32_t * max_valbufsize )
2007-08-26 15:16:40 +00:00
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( 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 ) {
2007-10-06 00:17:44 +00:00
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
2007-08-26 15:16:40 +00:00
* classname = NULL ;
}
/* TODO: Last mod time */
2007-10-06 00:17:44 +00:00
2008-01-07 14:11:29 -06:00
/* TODO: max valnamelen */
/* TODO: max valbufsize */
/* TODO: max subkeynamelen */
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static struct regf_key_data * regf_get_key ( TALLOC_CTX * ctx ,
struct regf_data * regf ,
uint32_t offset )
2007-08-26 15:16:40 +00:00
{
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 ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , offset , nk ,
( tdr_pull_fn_t ) tdr_pull_nk_block , nk ) ) {
2007-08-26 15:16:40 +00:00
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 ;
}
2007-12-14 10:38:26 +01:00
static WERROR regf_get_value ( TALLOC_CTX * ctx , struct hive_key * key ,
2007-10-06 00:17:44 +00:00
int idx , const char * * name ,
uint32_t * data_type , DATA_BLOB * data )
2007-08-26 15:16:40 +00:00
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( 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 ) ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , vk_offset , vk ,
( tdr_pull_fn_t ) tdr_pull_vk_block , vk ) ) {
2007-08-26 15:16:40 +00:00
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 )
* data_type = vk - > data_type ;
2007-10-06 00:17:44 +00:00
if ( vk - > data_length & 0x80000000 ) {
2007-08-26 15:16:40 +00:00
vk - > data_length & = ~ 0x80000000 ;
2009-02-05 09:39:03 +01:00
data - > data = ( uint8_t * ) talloc_memdup ( ctx , ( uint8_t * ) & vk - > data_offset , vk - > data_length ) ;
2007-08-26 15:16:40 +00:00
data - > length = vk - > data_length ;
} else {
* data = hbin_get ( regf , vk - > data_offset ) ;
}
if ( data - > length < vk - > data_length ) {
DEBUG ( 1 , ( " Read data less than indicated data length! \n " ) ) ;
}
talloc_free ( vk ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_get_value_by_name ( TALLOC_CTX * mem_ctx ,
struct hive_key * key , const char * name ,
uint32_t * type , DATA_BLOB * data )
2007-08-26 15:16:40 +00:00
{
int i ;
const char * vname ;
WERROR error ;
/* FIXME: Do binary search? Is this list sorted at all? */
2007-10-06 00:17:44 +00:00
for ( i = 0 ; W_ERROR_IS_OK ( error = regf_get_value ( mem_ctx , key , i ,
& vname , type , data ) ) ;
i + + ) {
2007-08-26 15:16:40 +00:00
if ( ! strcmp ( vname , name ) )
return WERR_OK ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
if ( W_ERROR_EQUAL ( error , WERR_NO_MORE_ITEMS ) )
2008-01-18 02:45:00 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
return error ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_get_subkey_by_index ( TALLOC_CTX * ctx ,
const struct hive_key * key ,
uint32_t idx , const char * * name ,
const char * * classname ,
NTTIME * last_mod_time )
2007-08-26 15:16:40 +00:00
{
DATA_BLOB data ;
struct regf_key_data * ret ;
const struct regf_key_data * private_data = ( const struct regf_key_data * ) key ;
struct nk_block * nk = private_data - > nk ;
uint32_t key_off = 0 ;
if ( idx > = nk - > num_subkeys )
return WERR_NO_MORE_ITEMS ;
data = hbin_get ( private_data - > hive , 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 ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( private_data - > hive , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull , nk , & li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 ] ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
} else if ( ! strncmp ( ( char * ) data . data , " lf " , 2 ) ) {
struct lf_block lf ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( private_data - > hive , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lf_block ( pull , nk , & lf ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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_offset ;
} else if ( ! strncmp ( ( char * ) data . data , " lh " , 2 ) ) {
struct lh_block lh ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( private_data - > hive , private_data - > hive - > iconv_convenience ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull , nk , & lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( lh . header , " lh " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
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 ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
uint16_t sublist_count = 0 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in RI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_ri_block ( pull , nk , & ri ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing RI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
SMB_ASSERT ( ! strncmp ( ri . header , " ri " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
for ( i = 0 ; i < ri . key_count ; i + + ) {
DATA_BLOB list_data ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Get sublist data blob */
list_data = hbin_get ( private_data - > hive , ri . offset [ i ] ) ;
if ( ! list_data . data ) {
DEBUG ( 0 , ( " Error getting RI list. " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = list_data ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
if ( ! strncmp ( ( char * ) list_data . data , " li " , 2 ) ) {
struct li_block li ;
DEBUG ( 10 , ( " Subkeys in RI->LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull ,
2007-10-06 00:17:44 +00:00
nk ,
& li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list from RI \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
SMB_ASSERT ( ! strncmp ( li . header , " li " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* 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 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in RI->LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull ,
2007-10-06 00:17:44 +00:00
nk ,
& lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LH list from RI \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
if ( idx > sublist_count ) {
return WERR_NO_MORE_ITEMS ;
}
} else {
2007-10-06 00:17:44 +00:00
DEBUG ( 0 , ( " Unknown type for subkey list (0x%04x): %c%c \n " ,
2007-08-26 15:16:40 +00:00
nk - > subkeys_offset , data . data [ 0 ] , data . data [ 1 ] ) ) ;
return WERR_GENERAL_FAILURE ;
}
ret = regf_get_key ( ctx , private_data - > hive , key_off ) ;
if ( classname ! = NULL ) {
if ( ret - > nk - > clsname_offset ! = - 1 ) {
2007-10-06 00:17:44 +00:00
DATA_BLOB db = hbin_get ( ret - > hive ,
ret - > nk - > clsname_offset ) ;
* classname = talloc_strndup ( ctx ,
( char * ) db . data ,
ret - > nk - > clsname_length ) ;
} else
2007-08-26 15:16:40 +00:00
* classname = NULL ;
}
if ( last_mod_time ! = NULL )
* last_mod_time = ret - > nk - > last_change ;
if ( name ! = NULL )
* name = talloc_steal ( ctx , ret - > nk - > key_name ) ;
talloc_free ( ret ) ;
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_match_subkey_by_name ( TALLOC_CTX * ctx ,
const struct hive_key * key ,
uint32_t offset ,
const char * name , uint32_t * ret )
2007-08-26 15:16:40 +00:00
{
DATA_BLOB subkey_data ;
struct nk_block subkey ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull ;
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) key ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
subkey_data = hbin_get ( private_data - > hive , offset ) ;
if ( ! subkey_data . data ) {
DEBUG ( 0 , ( " Unable to retrieve subkey HBIN \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
pull - > data = subkey_data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_nk_block ( pull , ctx , & subkey ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing NK structure. \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_get_subkey_by_name ( TALLOC_CTX * ctx ,
const struct hive_key * key ,
const char * name ,
struct hive_key * * ret )
2007-08-26 15:16:40 +00:00
{
DATA_BLOB data ;
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) key ;
struct nk_block * nk = private_data - > nk ;
uint32_t key_off = 0 ;
data = hbin_get ( private_data - > hive , 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 ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
DEBUG ( 10 , ( " Subkeys in LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull , nk , & li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
for ( i = 0 ; i < li . key_count ; i + + ) {
2007-10-06 00:17:44 +00:00
W_ERROR_NOT_OK_RETURN ( regf_match_subkey_by_name ( nk , key ,
li . nk_offset [ i ] ,
name ,
& key_off ) ) ;
2007-08-26 15:16:40 +00:00
if ( key_off ! = 0 )
break ;
}
if ( key_off = = 0 )
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
} else if ( ! strncmp ( ( char * ) data . data , " lf " , 2 ) ) {
struct lf_block lf ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
DEBUG ( 10 , ( " Subkeys in LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lf_block ( pull , nk , & lf ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
for ( i = 0 ; i < lf . key_count ; i + + ) {
if ( strncmp ( lf . hr [ i ] . hash , name , 4 ) ) {
continue ;
}
2007-10-06 00:17:44 +00:00
W_ERROR_NOT_OK_RETURN ( regf_match_subkey_by_name ( nk ,
key ,
lf . hr [ i ] . nk_offset ,
name ,
& key_off ) ) ;
2007-08-26 15:16:40 +00:00
if ( key_off ! = 0 )
break ;
}
if ( key_off = = 0 )
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
} else if ( ! strncmp ( ( char * ) data . data , " lh " , 2 ) ) {
struct lh_block lh ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
uint32_t hash ;
DEBUG ( 10 , ( " Subkeys in LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull , nk , & lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
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 ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
hash = regf_create_lh_hash ( name ) ;
for ( i = 0 ; i < lh . key_count ; i + + ) {
if ( lh . hr [ i ] . base37 ! = hash ) {
continue ;
}
2007-10-06 00:17:44 +00:00
W_ERROR_NOT_OK_RETURN ( regf_match_subkey_by_name ( nk ,
key ,
lh . hr [ i ] . nk_offset ,
name ,
& key_off ) ) ;
2007-08-26 15:16:40 +00:00
if ( key_off ! = 0 )
break ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
if ( key_off = = 0 )
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
} else if ( ! strncmp ( ( char * ) data . data , " ri " , 2 ) ) {
struct ri_block ri ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( ctx , private_data - > hive - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i , j ;
DEBUG ( 10 , ( " Subkeys in RI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_ri_block ( pull , nk , & ri ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing RI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
SMB_ASSERT ( ! strncmp ( ri . header , " ri " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
for ( i = 0 ; i < ri . key_count ; i + + ) {
DATA_BLOB list_data ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Get sublist data blob */
list_data = hbin_get ( private_data - > hive , ri . offset [ i ] ) ;
if ( list_data . data = = NULL ) {
DEBUG ( 0 , ( " Error getting RI list. " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = list_data ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
if ( ! strncmp ( ( char * ) list_data . data , " li " , 2 ) ) {
struct li_block li ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull ,
2007-10-06 00:17:44 +00:00
nk ,
& li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list from RI \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
SMB_ASSERT ( ! strncmp ( li . header , " li " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
for ( j = 0 ; j < li . key_count ; j + + ) {
2007-10-06 00:17:44 +00:00
W_ERROR_NOT_OK_RETURN ( regf_match_subkey_by_name ( nk , key ,
li . nk_offset [ j ] ,
name ,
& key_off ) ) ;
2007-08-26 15:16:40 +00:00
if ( key_off )
break ;
}
} else if ( ! strncmp ( ( char * ) list_data . data , " lh " , 2 ) ) {
struct lh_block lh ;
uint32_t hash ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull ,
2007-10-06 00:17:44 +00:00
nk ,
& lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LH list from RI \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
SMB_ASSERT ( ! strncmp ( lh . header , " lh " , 2 ) ) ;
hash = regf_create_lh_hash ( name ) ;
for ( j = 0 ; j < lh . key_count ; j + + ) {
if ( lh . hr [ j ] . base37 ! = hash ) {
continue ;
}
2007-10-06 00:17:44 +00:00
W_ERROR_NOT_OK_RETURN ( regf_match_subkey_by_name ( nk , key ,
lh . hr [ j ] . nk_offset ,
name ,
& key_off ) ) ;
2007-08-26 15:16:40 +00:00
if ( key_off )
break ;
}
}
if ( key_off )
break ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
if ( ! key_off )
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
} else {
DEBUG ( 0 , ( " Unknown subkey list type. \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
* ret = ( struct hive_key * ) regf_get_key ( ctx , private_data - > hive ,
key_off ) ;
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_set_sec_desc ( struct hive_key * key ,
const struct security_descriptor * sec_desc )
2007-08-26 15:16:40 +00:00
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) key ;
struct sk_block cur_sk , sk , new_sk ;
struct regf_data * regf = private_data - > hive ;
struct nk_block root ;
DATA_BLOB data ;
uint32_t sk_offset , cur_sk_offset ;
bool update_cur_sk = false ;
/* Get the root nk */
2007-10-06 00:17:44 +00:00
hbin_get_tdr ( regf , regf - > header - > data_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_nk_block , & root ) ;
2007-08-26 15:16:40 +00:00
/* Push the security descriptor to a blob */
2008-01-01 22:05:05 -06:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_push_struct_blob ( & data , regf , NULL ,
sec_desc , ( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to push security descriptor \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
/* Get the current security descriptor for the key */
if ( ! hbin_get_tdr ( regf , private_data - > nk - > sk_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & cur_sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find security descriptor for current key \n " ) ) ;
return WERR_BADFILE ;
}
/* If there's no change, change nothing. */
2007-10-06 00:17:44 +00:00
if ( memcmp ( data . data , cur_sk . sec_desc ,
MIN ( data . length , cur_sk . rec_size ) ) = = 0 ) {
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
/* Delete the current sk if only this key is using it */
2007-08-26 15:16:40 +00:00
if ( cur_sk . ref_cnt = = 1 ) {
2007-10-06 00:17:44 +00:00
/* Get the previous security descriptor for the key */
if ( ! hbin_get_tdr ( regf , cur_sk . prev_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find prev security descriptor for current key \n " ) ) ;
return WERR_BADFILE ;
}
/* Change and store the previous security descriptor */
sk . next_offset = cur_sk . next_offset ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf , ( tdr_push_fn_t ) tdr_push_sk_block ,
cur_sk . prev_offset , & sk ) ;
/* Get the next security descriptor for the key */
if ( ! hbin_get_tdr ( regf , cur_sk . next_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find next security descriptor for current key \n " ) ) ;
return WERR_BADFILE ;
}
/* Change and store the next security descriptor */
sk . prev_offset = cur_sk . prev_offset ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf , ( tdr_push_fn_t ) tdr_push_sk_block ,
cur_sk . next_offset , & sk ) ;
2007-08-26 15:16:40 +00:00
hbin_free ( regf , private_data - > nk - > sk_offset ) ;
} else {
/* This key will no longer be referring to this sk */
cur_sk . ref_cnt - - ;
update_cur_sk = true ;
}
sk_offset = root . sk_offset ;
do {
cur_sk_offset = sk_offset ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , sk_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find security descriptor \n " ) ) ;
return WERR_BADFILE ;
}
if ( memcmp ( data . data , sk . sec_desc , MIN ( data . length , sk . rec_size ) ) = = 0 ) {
private_data - > nk - > sk_offset = sk_offset ;
sk . ref_cnt + + ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
sk_offset , & sk ) ;
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_nk_block ,
private_data - > offset ,
private_data - > nk ) ;
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
sk_offset = sk . next_offset ;
} while ( sk_offset ! = root . sk_offset ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
ZERO_STRUCT ( new_sk ) ;
new_sk . header = " sk " ;
new_sk . prev_offset = cur_sk_offset ;
new_sk . next_offset = root . sk_offset ;
new_sk . ref_cnt = 1 ;
new_sk . rec_size = data . length ;
new_sk . sec_desc = data . data ;
2007-10-06 00:17:44 +00:00
sk_offset = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
& new_sk ) ;
2007-08-26 15:16:40 +00:00
if ( sk_offset = = - 1 ) {
DEBUG ( 0 , ( " Error storing sk block \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
private_data - > nk - > sk_offset = sk_offset ;
if ( update_cur_sk ) {
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
private_data - > nk - > sk_offset , & cur_sk ) ;
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
/* Get the previous security descriptor for the key */
if ( ! hbin_get_tdr ( regf , new_sk . prev_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find security descriptor for previous key \n " ) ) ;
return WERR_BADFILE ;
}
/* Change and store the previous security descriptor */
sk . next_offset = sk_offset ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
cur_sk . prev_offset , & sk ) ;
/* Get the next security descriptor for the key (always root, as we append) */
if ( ! hbin_get_tdr ( regf , new_sk . next_offset , regf ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find security descriptor for current key \n " ) ) ;
return WERR_BADFILE ;
}
/* Change and store the next security descriptor (always root, as we append) */
sk . prev_offset = sk_offset ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
root . sk_offset , & sk ) ;
2007-08-26 15:16:40 +00:00
/* Store the nk. */
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
private_data - > offset , private_data - > nk ) ;
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_get_sec_desc ( TALLOC_CTX * ctx , const struct hive_key * key ,
struct security_descriptor * * sd )
2007-08-26 15:16:40 +00:00
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) key ;
struct sk_block sk ;
struct regf_data * regf = private_data - > hive ;
DATA_BLOB data ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , private_data - > nk - > sk_offset , ctx ,
( tdr_pull_fn_t ) tdr_pull_sk_block , & sk ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Unable to find security descriptor \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
if ( strcmp ( sk . header , " sk " ) ! = 0 ) {
DEBUG ( 0 , ( " Expected 'sk', got '%s' \n " , sk . header ) ) ;
return WERR_GENERAL_FAILURE ;
}
* sd = talloc ( ctx , struct security_descriptor ) ;
W_ERROR_HAVE_NO_MEMORY ( * sd ) ;
data . data = sk . sec_desc ;
data . length = sk . rec_size ;
2008-01-01 22:05:13 -06:00
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_pull_struct_blob ( & data , ctx , NULL , * sd ,
2007-10-06 00:17:44 +00:00
( ndr_pull_flags_fn_t ) ndr_pull_security_descriptor ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing security descriptor \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_sl_add_entry ( struct regf_data * regf , uint32_t list_offset ,
const char * name ,
uint32_t key_offset , uint32_t * ret )
2007-08-26 15:16:40 +00:00
{
DATA_BLOB data ;
/* Create a new key if necessary */
2007-10-06 00:17:44 +00:00
if ( list_offset = = - 1 ) {
2007-08-26 15:16:40 +00:00
if ( regf - > header - > version . major ! = 1 ) {
DEBUG ( 0 , ( " Can't store keys in unknown registry format \n " ) ) ;
return WERR_NOT_SUPPORTED ;
}
2007-10-06 00:17:44 +00:00
if ( regf - > header - > version . minor < 3 ) {
2007-08-26 15:16:40 +00:00
/* Store LI */
struct li_block li ;
ZERO_STRUCT ( li ) ;
li . header = " li " ;
2007-10-06 00:17:44 +00:00
li . key_count = 1 ;
2007-08-26 15:16:40 +00:00
li . nk_offset = talloc_array ( regf , uint32_t , 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( li . nk_offset ) ;
li . nk_offset [ 0 ] = key_offset ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_li_block ,
& li ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( li . nk_offset ) ;
2007-10-06 00:17:44 +00:00
} else if ( regf - > header - > version . minor = = 3 | |
regf - > header - > version . minor = = 4 ) {
2007-08-26 15:16:40 +00:00
/* Store LF */
struct lf_block lf ;
ZERO_STRUCT ( lf ) ;
lf . header = " lf " ;
lf . key_count = 1 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
lf . hr = talloc_array ( regf , struct hash_record , 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( lf . hr ) ;
lf . hr [ 0 ] . nk_offset = key_offset ;
lf . hr [ 0 ] . hash = talloc_strndup ( lf . hr , name , 4 ) ;
W_ERROR_HAVE_NO_MEMORY ( lf . hr [ 0 ] . hash ) ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_lf_block ,
& lf ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( lf . hr ) ;
} else if ( regf - > header - > version . minor = = 5 ) {
/* Store LH */
struct lh_block lh ;
ZERO_STRUCT ( lh ) ;
lh . header = " lh " ;
lh . key_count = 1 ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
lh . hr = talloc_array ( regf , struct lh_hash , 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( lh . hr ) ;
lh . hr [ 0 ] . nk_offset = key_offset ;
lh . hr [ 0 ] . base37 = regf_create_lh_hash ( name ) ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_lh_block ,
& lh ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( lh . hr ) ;
}
return WERR_OK ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
data = hbin_get ( regf , list_offset ) ;
if ( ! data . data ) {
DEBUG ( 0 , ( " Unable to find subkey list \n " ) ) ;
return WERR_BADFILE ;
}
if ( ! strncmp ( ( char * ) data . data , " li " , 2 ) ) {
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
struct li_block li ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull , regf , & li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
if ( strncmp ( li . header , " li " , 2 ) ! = 0 ) {
abort ( ) ;
DEBUG ( 0 , ( " LI header corrupt \n " ) ) ;
return WERR_BADFILE ;
}
2007-10-06 00:17:44 +00:00
li . nk_offset = talloc_realloc ( regf , li . nk_offset ,
uint32_t , li . key_count + 1 ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( li . nk_offset ) ;
li . nk_offset [ li . key_count ] = key_offset ;
li . key_count + + ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_li_block ,
list_offset , & li ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( li . nk_offset ) ;
} else if ( ! strncmp ( ( char * ) data . data , " lf " , 2 ) ) {
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
struct lf_block lf ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lf_block ( pull , regf , & lf ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( lf . header , " lf " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
lf . hr = talloc_realloc ( regf , lf . hr , struct hash_record ,
lf . key_count + 1 ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( lf . hr ) ;
lf . hr [ lf . key_count ] . nk_offset = key_offset ;
lf . hr [ lf . key_count ] . hash = talloc_strndup ( lf . hr , name , 4 ) ;
W_ERROR_HAVE_NO_MEMORY ( lf . hr [ lf . key_count ] . hash ) ;
lf . key_count + + ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_lf_block ,
list_offset , & lf ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( lf . hr ) ;
} else if ( ! strncmp ( ( char * ) data . data , " lh " , 2 ) ) {
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
struct lh_block lh ;
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull , regf , & lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LH list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( lh . header , " lh " , 2 ) ) ;
2007-10-06 00:17:44 +00:00
lh . hr = talloc_realloc ( regf , lh . hr , struct lh_hash ,
lh . key_count + 1 ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( lh . hr ) ;
lh . hr [ lh . key_count ] . nk_offset = key_offset ;
lh . hr [ lh . key_count ] . base37 = regf_create_lh_hash ( name ) ;
lh . key_count + + ;
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_lh_block ,
list_offset , & lh ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( lh . hr ) ;
} else if ( ! strncmp ( ( char * ) data . data , " ri " , 2 ) ) {
/* FIXME */
DEBUG ( 0 , ( " Adding to 'ri' subkey list is not supported yet. \n " ) ) ;
return WERR_NOT_SUPPORTED ;
} else {
DEBUG ( 0 , ( " Cannot add to unknown subkey list \n " ) ) ;
return WERR_BADFILE ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_sl_del_entry ( struct regf_data * regf , uint32_t list_offset ,
uint32_t key_offset , uint32_t * ret )
2007-08-26 15:16:40 +00:00
{
DATA_BLOB data ;
data = hbin_get ( regf , list_offset ) ;
if ( ! data . data ) {
DEBUG ( 0 , ( " Unable to find subkey list \n " ) ) ;
return WERR_BADFILE ;
}
if ( strncmp ( ( char * ) data . data , " li " , 2 ) = = 0 ) {
struct li_block li ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
bool found_offset = false ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LI list \n " ) ) ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_li_block ( pull , regf , & li ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LI list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( li . header , " li " , 2 ) ) ;
for ( i = 0 ; i < li . key_count ; i + + ) {
if ( found_offset ) {
li . nk_offset [ i - 1 ] = li . nk_offset [ i ] ;
}
if ( li . nk_offset [ i ] = = key_offset ) {
found_offset = true ;
continue ;
}
}
if ( ! found_offset ) {
2007-08-26 22:12:02 +00:00
DEBUG ( 2 , ( " Subkey not found \n " ) ) ;
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
li . key_count - - ;
/* If the there are no entries left, free the subkey list */
if ( li . key_count = = 0 ) {
hbin_free ( regf , list_offset ) ;
* ret = - 1 ;
}
/* Store li block */
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_li_block ,
list_offset , & li ) ;
2007-08-26 15:16:40 +00:00
} else if ( strncmp ( ( char * ) data . data , " lf " , 2 ) = = 0 ) {
struct lf_block lf ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
bool found_offset = false ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LF list \n " ) ) ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lf_block ( pull , regf , & lf ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( lf . header , " lf " , 2 ) ) ;
for ( i = 0 ; i < lf . key_count ; i + + ) {
if ( found_offset ) {
lf . hr [ i - 1 ] = lf . hr [ i ] ;
continue ;
}
if ( lf . hr [ i ] . nk_offset = = key_offset ) {
found_offset = 1 ;
continue ;
}
}
if ( ! found_offset ) {
2007-08-26 22:12:02 +00:00
DEBUG ( 2 , ( " Subkey not found \n " ) ) ;
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
lf . key_count - - ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* If the there are no entries left, free the subkey list */
if ( lf . key_count = = 0 ) {
hbin_free ( regf , list_offset ) ;
* ret = - 1 ;
return WERR_OK ;
}
/* Store lf block */
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_lf_block ,
list_offset , & lf ) ;
2007-08-26 15:16:40 +00:00
} else if ( strncmp ( ( char * ) data . data , " lh " , 2 ) = = 0 ) {
struct lh_block lh ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
uint16_t i ;
bool found_offset = false ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
DEBUG ( 10 , ( " Subkeys in LH list \n " ) ) ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
pull - > data = data ;
2007-10-06 00:17:44 +00:00
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_lh_block ( pull , regf , & lh ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error parsing LF list \n " ) ) ;
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
}
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
SMB_ASSERT ( ! strncmp ( lh . header , " lh " , 2 ) ) ;
for ( i = 0 ; i < lh . key_count ; i + + ) {
if ( found_offset ) {
lh . hr [ i - 1 ] = lh . hr [ i ] ;
continue ;
}
if ( lh . hr [ i ] . nk_offset = = key_offset ) {
found_offset = 1 ;
continue ;
}
}
if ( ! found_offset ) {
DEBUG ( 0 , ( " Subkey not found \n " ) ) ;
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
lh . key_count - - ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* If the there are no entries left, free the subkey list */
if ( lh . key_count = = 0 ) {
hbin_free ( regf , list_offset ) ;
* ret = - 1 ;
return WERR_OK ;
}
/* Store lh block */
2007-10-06 00:17:44 +00:00
* ret = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_lh_block ,
list_offset , & lh ) ;
2007-08-26 15:16:40 +00:00
} else if ( strncmp ( ( char * ) data . data , " ri " , 2 ) = = 0 ) {
/* FIXME */
DEBUG ( 0 , ( " Sorry, deletion from ri block is not supported yet. \n " ) ) ;
return WERR_NOT_SUPPORTED ;
} else {
DEBUG ( 0 , ( " Unknown header found in subkey list. \n " ) ) ;
return WERR_BADFILE ;
}
return WERR_OK ;
}
static WERROR regf_del_value ( struct hive_key * key , const char * name )
{
2007-12-14 10:38:26 +01:00
struct regf_key_data * private_data = ( struct regf_key_data * ) key ;
2007-08-26 15:16:40 +00:00
struct regf_data * regf = private_data - > hive ;
struct nk_block * nk = private_data - > nk ;
struct vk_block vk ;
uint32_t vk_offset ;
bool found_offset = false ;
DATA_BLOB values ;
uint32_t i ;
if ( nk - > values_offset = = - 1 ) {
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
values = hbin_get ( regf , nk - > values_offset ) ;
for ( i = 0 ; i < nk - > num_values ; i + + ) {
if ( found_offset ) {
( ( uint32_t * ) values . data ) [ i - 1 ] = ( ( uint32_t * ) values . data ) [ i ] ;
} else {
vk_offset = IVAL ( values . data , i * 4 ) ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , vk_offset , private_data ,
( tdr_pull_fn_t ) tdr_pull_vk_block ,
& vk ) ) {
DEBUG ( 0 , ( " Unable to get VK block at %d \n " ,
vk_offset ) ) ;
2007-08-26 15:16:40 +00:00
return WERR_BADFILE ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
if ( strcmp ( vk . data_name , name ) = = 0 ) {
hbin_free ( regf , vk_offset ) ;
found_offset = true ;
}
}
}
if ( ! found_offset ) {
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
} else {
nk - > num_values - - ;
values . length = ( nk - > num_values ) * 4 ;
}
/* Store values list and nk */
if ( nk - > num_values = = 0 ) {
hbin_free ( regf , nk - > values_offset ) ;
nk - > values_offset = - 1 ;
2007-10-06 00:17:44 +00:00
} else {
nk - > values_offset = hbin_store_resize ( regf ,
nk - > values_offset ,
values ) ;
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf , ( tdr_push_fn_t ) tdr_push_nk_block ,
private_data - > offset , nk ) ;
2007-08-26 15:16:40 +00:00
return regf_save_hbin ( private_data - > hive ) ;
}
static WERROR regf_del_key ( const struct hive_key * parent , const char * name )
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) parent ;
struct regf_key_data * key ;
struct nk_block * parent_nk ;
WERROR error ;
SMB_ASSERT ( private_data ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
parent_nk = private_data - > nk ;
if ( parent_nk - > subkeys_offset = = - 1 ) {
DEBUG ( 4 , ( " Subkey list is empty, this key cannot contain subkeys. \n " ) ) ;
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
/* Find the key */
2007-10-06 00:17:44 +00:00
if ( ! W_ERROR_IS_OK ( regf_get_subkey_by_name ( parent_nk , parent , name ,
( struct hive_key * * ) & key ) ) ) {
2007-08-26 22:12:02 +00:00
DEBUG ( 2 , ( " Key '%s' not found \n " , name ) ) ;
2008-01-18 03:37:06 +01:00
return WERR_BADFILE ;
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
2008-02-16 15:19:00 -06:00
if ( key - > nk - > subkeys_offset ! = - 1 ) {
char * sk_name ;
struct hive_key * sk = ( struct hive_key * ) key ;
int i = key - > nk - > num_subkeys ;
while ( i - - ) {
/* Get subkey information. */
error = regf_get_subkey_by_index ( parent_nk , sk , 0 ,
( const char * * ) & sk_name ,
NULL , NULL ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Can't retrieve subkey by index. \n " ) ) ;
return error ;
}
/* Delete subkey. */
error = regf_del_key ( sk , sk_name ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Can't delete key '%s'. \n " , sk_name ) ) ;
return error ;
}
talloc_free ( sk_name ) ;
}
}
if ( key - > nk - > values_offset ! = - 1 ) {
char * val_name ;
struct hive_key * sk = ( struct hive_key * ) key ;
DATA_BLOB data ;
int i = key - > nk - > num_values ;
while ( i - - ) {
/* Get value information. */
error = regf_get_value ( parent_nk , sk , 0 ,
( const char * * ) & val_name ,
NULL , & data ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Can't retrieve value by index. \n " ) ) ;
return error ;
}
/* Delete value. */
error = regf_del_value ( sk , val_name ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Can't delete value '%s'. \n " , val_name ) ) ;
return error ;
}
talloc_free ( val_name ) ;
}
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Delete it from the subkey list. */
2007-10-06 00:17:44 +00:00
error = regf_sl_del_entry ( private_data - > hive , parent_nk - > subkeys_offset ,
key - > offset , & parent_nk - > subkeys_offset ) ;
2007-08-26 15:16:40 +00:00
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Can't store new subkey list for parent key. Won't delete. \n " ) ) ;
return error ;
}
/* Re-store parent key */
parent_nk - > num_subkeys - - ;
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( private_data - > hive ,
( tdr_push_fn_t ) tdr_push_nk_block ,
private_data - > offset , parent_nk ) ;
2007-08-26 15:16:40 +00:00
if ( key - > nk - > clsname_offset ! = - 1 ) {
hbin_free ( private_data - > hive , key - > nk - > clsname_offset ) ;
}
hbin_free ( private_data - > hive , key - > offset ) ;
return regf_save_hbin ( private_data - > hive ) ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_add_key ( TALLOC_CTX * ctx , const struct hive_key * parent ,
const char * name , const char * classname ,
struct security_descriptor * sec_desc ,
struct hive_key * * ret )
2007-08-26 15:16:40 +00:00
{
2007-10-06 00:17:44 +00:00
const struct regf_key_data * private_data =
2007-08-26 15:16:40 +00:00
( const struct regf_key_data * ) parent ;
struct nk_block * parent_nk = private_data - > nk , nk ;
struct nk_block * root ;
struct regf_data * regf = private_data - > hive ;
uint32_t offset ;
WERROR error ;
nk . header = " nk " ;
nk . type = REG_SUB_KEY ;
unix_to_nt_time ( & nk . last_change , time ( NULL ) ) ;
nk . uk1 = 0 ;
nk . parent_offset = private_data - > offset ;
nk . num_subkeys = 0 ;
nk . uk2 = 0 ;
nk . subkeys_offset = - 1 ;
nk . unknown_offset = - 1 ;
nk . num_values = 0 ;
nk . values_offset = - 1 ;
memset ( nk . unk3 , 0 , 5 ) ;
nk . clsname_offset = - 1 ; /* FIXME: fill in */
nk . clsname_length = 0 ;
nk . key_name = name ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Get the security descriptor of the root key */
root = talloc_zero ( ctx , struct nk_block ) ;
W_ERROR_HAVE_NO_MEMORY ( root ) ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , regf - > header - > data_offset , root ,
( tdr_pull_fn_t ) tdr_pull_nk_block , root ) ) {
2009-06-18 11:16:16 +02:00
DEBUG ( 0 , ( " Unable to find HBIN data for offset %d \n " ,
regf - > header - > data_offset ) ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
nk . sk_offset = root - > sk_offset ;
talloc_free ( root ) ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Store the new nk key */
offset = hbin_store_tdr ( regf , ( tdr_push_fn_t ) tdr_push_nk_block , & nk ) ;
2007-10-06 00:17:44 +00:00
error = regf_sl_add_entry ( regf , parent_nk - > subkeys_offset , name , offset ,
& parent_nk - > subkeys_offset ) ;
2007-08-26 15:16:40 +00:00
if ( ! W_ERROR_IS_OK ( error ) ) {
hbin_free ( regf , offset ) ;
return error ;
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
parent_nk - > num_subkeys + + ;
/* Since the subkey offset of the parent can change, store it again */
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf , ( tdr_push_fn_t ) tdr_push_nk_block ,
2007-08-26 15:16:40 +00:00
nk . parent_offset , parent_nk ) ;
* ret = ( struct hive_key * ) regf_get_key ( ctx , regf , offset ) ;
return regf_save_hbin ( private_data - > hive ) ;
}
2007-10-06 00:17:44 +00:00
static WERROR regf_set_value ( struct hive_key * key , const char * name ,
uint32_t type , const DATA_BLOB data )
2007-08-26 15:16:40 +00:00
{
2007-12-14 10:38:26 +01:00
struct regf_key_data * private_data = ( struct regf_key_data * ) key ;
2007-08-26 15:16:40 +00:00
struct regf_data * regf = private_data - > hive ;
struct nk_block * nk = private_data - > nk ;
struct vk_block vk ;
uint32_t i ;
uint32_t tmp_vk_offset , vk_offset , old_vk_offset = - 1 ;
DATA_BLOB values ;
ZERO_STRUCT ( vk ) ;
/* find the value offset, if it exists */
if ( nk - > values_offset ! = - 1 ) {
values = hbin_get ( regf , nk - > values_offset ) ;
for ( i = 0 ; i < nk - > num_values ; i + + ) {
tmp_vk_offset = IVAL ( values . data , i * 4 ) ;
2007-10-06 00:17:44 +00:00
if ( ! hbin_get_tdr ( regf , tmp_vk_offset , private_data ,
( tdr_pull_fn_t ) tdr_pull_vk_block ,
& vk ) ) {
DEBUG ( 0 , ( " Unable to get VK block at %d \n " ,
tmp_vk_offset ) ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
if ( strcmp ( vk . data_name , name ) = = 0 ) {
old_vk_offset = tmp_vk_offset ;
break ;
}
}
/* Free data, if any */
if ( ! ( vk . data_length & 0x80000000 ) ) {
2007-10-06 00:17:44 +00:00
hbin_free ( regf , vk . data_offset ) ;
2007-08-26 15:16:40 +00:00
}
}
if ( old_vk_offset = = - 1 ) {
vk . header = " vk " ;
vk . name_length = strlen ( name ) ;
if ( name ! = NULL & & name [ 0 ] ! = 0 ) {
vk . flag = 1 ;
vk . data_name = name ;
} else {
vk . data_name = NULL ;
vk . flag = 0 ;
}
}
/* Set the type and data */
vk . data_length = data . length ;
vk . data_type = type ;
if ( type = = REG_DWORD ) {
vk . data_length | = 0x80000000 ;
vk . data_offset = * ( uint32_t * ) data . data ;
} else {
/* Store data somewhere */
vk . data_offset = hbin_store ( regf , data ) ;
}
if ( old_vk_offset = = - 1 ) {
/* Store new vk */
2007-10-06 00:17:44 +00:00
vk_offset = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_vk_block ,
& vk ) ;
2007-08-26 15:16:40 +00:00
} else {
/* Store vk at offset */
2007-10-06 00:17:44 +00:00
vk_offset = hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_vk_block ,
old_vk_offset , & vk ) ;
2007-08-26 15:16:40 +00:00
}
/* Re-allocate the value list */
if ( nk - > values_offset = = - 1 ) {
2007-10-06 00:17:44 +00:00
nk - > values_offset = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_uint32 ,
& vk_offset ) ;
2007-08-26 15:16:40 +00:00
nk - > num_values = 1 ;
} else {
/* Change if we're changing, otherwise we're adding the value */
if ( old_vk_offset ! = - 1 ) {
/* Find and overwrite the offset. */
for ( i = 0 ; i < nk - > num_values ; i + + ) {
if ( IVAL ( values . data , i * 4 ) = = old_vk_offset ) {
SIVAL ( values . data , i * 4 , vk_offset ) ;
break ;
}
}
} else {
/* Create a new value list */
DATA_BLOB value_list ;
value_list . length = ( nk - > num_values + 1 ) * 4 ;
2007-10-06 00:17:44 +00:00
value_list . data = ( uint8_t * ) talloc_array ( private_data ,
uint32_t ,
nk - > num_values + 1 ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( value_list . data ) ;
memcpy ( value_list . data , values . data , nk - > num_values * 4 ) ;
SIVAL ( value_list . data , nk - > num_values * 4 , vk_offset ) ;
nk - > num_values + + ;
2007-10-06 00:17:44 +00:00
nk - > values_offset = hbin_store_resize ( regf ,
nk - > values_offset ,
value_list ) ;
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
}
2007-10-06 00:17:44 +00:00
hbin_store_tdr_resize ( regf ,
( tdr_push_fn_t ) tdr_push_nk_block ,
private_data - > offset , nk ) ;
2007-08-26 15:16:40 +00:00
return regf_save_hbin ( private_data - > hive ) ;
}
static WERROR regf_save_hbin ( struct regf_data * regf )
{
2007-12-13 22:46:47 +01:00
struct tdr_push * push = tdr_push_init ( regf , regf - > iconv_convenience ) ;
2007-08-26 15:16:40 +00:00
int i ;
W_ERROR_HAVE_NO_MEMORY ( push ) ;
if ( lseek ( regf - > fd , 0 , SEEK_SET ) = = - 1 ) {
DEBUG ( 0 , ( " Error lseeking in regf file \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
/* Recompute checksum */
if ( NT_STATUS_IS_ERR ( tdr_push_regf_hdr ( push , regf - > header ) ) ) {
DEBUG ( 0 , ( " Failed to push regf header \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
regf - > header - > chksum = regf_hdr_checksum ( push - > data . data ) ;
talloc_free ( push ) ;
2007-12-13 22:46:47 +01:00
if ( NT_STATUS_IS_ERR ( tdr_push_to_fd ( regf - > fd , regf - > iconv_convenience ,
2007-10-06 00:17:44 +00:00
( tdr_push_fn_t ) tdr_push_regf_hdr ,
regf - > header ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error writing registry file header \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
if ( lseek ( regf - > fd , 0x1000 , SEEK_SET ) = = - 1 ) {
DEBUG ( 0 , ( " Error lseeking to 0x1000 in regf file \n " ) ) ;
return WERR_GENERAL_FAILURE ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
for ( i = 0 ; regf - > hbins [ i ] ; i + + ) {
2007-12-13 22:46:47 +01:00
if ( NT_STATUS_IS_ERR ( tdr_push_to_fd ( regf - > fd , regf - > iconv_convenience ,
2007-10-06 00:17:44 +00:00
( tdr_push_fn_t ) tdr_push_hbin_block ,
regf - > hbins [ i ] ) ) ) {
DEBUG ( 0 , ( " Error writing HBIN block \n " ) ) ;
2007-08-26 15:16:40 +00:00
return WERR_GENERAL_FAILURE ;
}
}
return WERR_OK ;
}
2008-02-21 17:17:37 +01:00
WERROR reg_create_regf_file ( TALLOC_CTX * parent_ctx ,
struct smb_iconv_convenience * iconv_convenience ,
const char * location ,
2007-10-06 00:17:44 +00:00
int minor_version , struct hive_key * * key )
2007-08-26 15:16:40 +00:00
{
struct regf_data * regf ;
struct regf_hdr * regf_hdr ;
struct nk_block nk ;
2008-04-14 22:52:51 +02:00
struct sk_block sk ;
2007-08-26 15:16:40 +00:00
WERROR error ;
2008-04-14 22:52:51 +02:00
DATA_BLOB data ;
struct security_descriptor * sd ;
uint32_t sk_offset ;
2007-08-26 15:16:40 +00:00
regf = ( struct regf_data * ) talloc_zero ( NULL , struct regf_data ) ;
2008-02-21 17:17:37 +01:00
regf - > iconv_convenience = iconv_convenience ;
2007-12-13 22:46:47 +01:00
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( regf ) ;
DEBUG ( 5 , ( " Attempting to create registry file \n " ) ) ;
/* Get the header */
regf - > fd = creat ( location , 0644 ) ;
if ( regf - > fd = = - 1 ) {
DEBUG ( 0 , ( " Could not create file: %s, %s \n " , location ,
strerror ( errno ) ) ) ;
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
regf_hdr = talloc_zero ( regf , struct regf_hdr ) ;
W_ERROR_HAVE_NO_MEMORY ( regf_hdr ) ;
regf_hdr - > REGF_ID = " regf " ;
unix_to_nt_time ( & regf_hdr - > modtime , time ( NULL ) ) ;
regf_hdr - > version . major = 1 ;
regf_hdr - > version . minor = minor_version ;
regf_hdr - > last_block = 0x1000 ; /* Block size */
2007-10-06 00:17:44 +00:00
regf_hdr - > description = talloc_strdup ( regf_hdr ,
2008-04-14 22:52:51 +02:00
" Registry created by Samba 4 " ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( regf_hdr - > description ) ;
regf_hdr - > chksum = 0 ;
regf - > header = regf_hdr ;
/* Create all hbin blocks */
regf - > hbins = talloc_array ( regf , struct hbin_block * , 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( regf - > hbins ) ;
regf - > hbins [ 0 ] = NULL ;
nk . header = " nk " ;
nk . type = REG_SUB_KEY ;
unix_to_nt_time ( & nk . last_change , time ( NULL ) ) ;
nk . uk1 = 0 ;
nk . parent_offset = - 1 ;
nk . num_subkeys = 0 ;
nk . uk2 = 0 ;
nk . subkeys_offset = - 1 ;
nk . unknown_offset = - 1 ;
nk . num_values = 0 ;
nk . values_offset = - 1 ;
memset ( nk . unk3 , 0 , 5 ) ;
2008-04-14 22:52:51 +02:00
nk . clsname_offset = - 1 ;
2007-08-26 15:16:40 +00:00
nk . clsname_length = 0 ;
2008-04-14 22:52:51 +02:00
nk . sk_offset = 0x80 ;
nk . key_name = " SambaRootKey " ;
/*
* It should be noted that changing the key_name to something shorter
* creates a shorter nk block , which makes the position of the sk block
* change . All Windows registries I ' ve seen have the sk at 0x80 .
* I therefore recommend that our regf files share that offset - - Wilco
*/
/* Create a security descriptor. */
sd = security_descriptor_dacl_create ( regf ,
0 ,
NULL , NULL ,
SID_NT_AUTHENTICATED_USERS ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_GENERIC_ALL ,
SEC_ACE_FLAG_OBJECT_INHERIT ,
NULL ) ;
/* Push the security descriptor to a blob */
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_push_struct_blob ( & data , regf , NULL ,
sd , ( ndr_push_flags_fn_t ) ndr_push_security_descriptor ) ) ) {
DEBUG ( 0 , ( " Unable to push security descriptor \n " ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
2008-04-14 22:52:51 +02:00
ZERO_STRUCT ( sk ) ;
sk . header = " sk " ;
sk . prev_offset = 0x80 ;
sk . next_offset = 0x80 ;
sk . ref_cnt = 1 ;
sk . rec_size = data . length ;
sk . sec_desc = data . data ;
2007-10-06 00:17:44 +00:00
2007-08-26 15:16:40 +00:00
/* Store the new nk key */
2007-10-06 00:17:44 +00:00
regf - > header - > data_offset = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_nk_block ,
& nk ) ;
2008-04-14 22:52:51 +02:00
/* Store the sk block */
sk_offset = hbin_store_tdr ( regf ,
( tdr_push_fn_t ) tdr_push_sk_block ,
& sk ) ;
if ( sk_offset ! = 0x80 ) {
DEBUG ( 0 , ( " Error storing sk block, should be at 0x80, stored at 0x%x \n " , nk . sk_offset ) ) ;
return WERR_GENERAL_FAILURE ;
}
2007-10-06 00:17:44 +00:00
* key = ( struct hive_key * ) regf_get_key ( parent_ctx , regf ,
regf - > header - > data_offset ) ;
2007-08-26 15:16:40 +00:00
error = regf_save_hbin ( regf ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
return error ;
}
2008-04-14 22:52:51 +02:00
/* We can drop our own reference now that *key will have created one */
talloc_free ( regf ) ;
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
2007-12-14 00:27:31 +01:00
WERROR reg_open_regf_file ( TALLOC_CTX * parent_ctx , const char * location ,
2008-02-21 17:17:37 +01:00
struct smb_iconv_convenience * iconv_convenience , struct hive_key * * key )
2007-08-26 15:16:40 +00:00
{
struct regf_data * regf ;
struct regf_hdr * regf_hdr ;
2007-12-13 22:46:51 +01:00
struct tdr_pull * pull ;
2007-08-26 15:16:40 +00:00
int i ;
2009-01-02 22:41:04 +11:00
regf = ( struct regf_data * ) talloc_zero ( parent_ctx , struct regf_data ) ;
2007-08-26 15:16:40 +00:00
2008-02-21 17:17:37 +01:00
regf - > iconv_convenience = iconv_convenience ;
2007-12-13 22:46:47 +01:00
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( regf ) ;
DEBUG ( 5 , ( " Attempting to load registry file \n " ) ) ;
/* Get the header */
regf - > fd = open ( location , O_RDWR ) ;
if ( regf - > fd = = - 1 ) {
DEBUG ( 0 , ( " Could not load file: %s, %s \n " , location ,
strerror ( errno ) ) ) ;
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
pull = tdr_pull_init ( regf , regf - > iconv_convenience ) ;
2008-10-12 17:34:43 +02:00
pull - > data . data = ( uint8_t * ) fd_load ( regf - > fd , & pull - > data . length , 0 , regf ) ;
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
if ( pull - > data . data = = NULL ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Error reading data \n " ) ) ;
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
regf_hdr = talloc ( regf , struct regf_hdr ) ;
W_ERROR_HAVE_NO_MEMORY ( regf_hdr ) ;
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_regf_hdr ( pull , regf_hdr , regf_hdr ) ) ) {
2007-08-26 15:16:40 +00:00
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
regf - > header = regf_hdr ;
if ( strcmp ( regf_hdr - > REGF_ID , " regf " ) ! = 0 ) {
DEBUG ( 0 , ( " Unrecognized NT registry header id: %s, %s \n " ,
2007-10-06 00:17:44 +00:00
regf_hdr - > REGF_ID , location ) ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
/* Validate the header ... */
2007-12-13 22:46:51 +01:00
if ( regf_hdr_checksum ( pull - > data . data ) ! = regf_hdr - > chksum ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " Registry file checksum error: %s: %d,%d \n " ,
2007-10-06 00:17:44 +00:00
location , regf_hdr - > chksum ,
2007-12-13 22:46:51 +01:00
regf_hdr_checksum ( pull - > data . data ) ) ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( regf ) ;
return WERR_GENERAL_FAILURE ;
}
2007-12-13 22:46:51 +01:00
pull - > offset = 0x1000 ;
2007-08-26 15:16:40 +00:00
i = 0 ;
/* Read in all hbin blocks */
regf - > hbins = talloc_array ( regf , struct hbin_block * , 1 ) ;
W_ERROR_HAVE_NO_MEMORY ( regf - > hbins ) ;
regf - > hbins [ 0 ] = NULL ;
2007-12-13 22:46:51 +01:00
while ( pull - > offset < pull - > data . length & &
pull - > offset < = regf - > header - > last_block ) {
2007-10-06 00:17:44 +00:00
struct hbin_block * hbin = talloc ( regf - > hbins ,
struct hbin_block ) ;
2007-08-26 15:16:40 +00:00
W_ERROR_HAVE_NO_MEMORY ( hbin ) ;
2007-12-13 22:46:51 +01:00
if ( NT_STATUS_IS_ERR ( tdr_pull_hbin_block ( pull , hbin , hbin ) ) ) {
2007-08-26 15:16:40 +00:00
DEBUG ( 0 , ( " [%d] Error parsing HBIN block \n " , i ) ) ;
talloc_free ( regf ) ;
return WERR_FOOBAR ;
}
if ( strcmp ( hbin - > HBIN_ID , " hbin " ) ! = 0 ) {
2007-10-06 00:17:44 +00:00
DEBUG ( 0 , ( " [%d] Expected 'hbin', got '%s' \n " ,
i , hbin - > HBIN_ID ) ) ;
2007-08-26 15:16:40 +00:00
talloc_free ( regf ) ;
return WERR_FOOBAR ;
}
regf - > hbins [ i ] = hbin ;
i + + ;
2007-10-06 00:17:44 +00:00
regf - > hbins = talloc_realloc ( regf , regf - > hbins ,
struct hbin_block * , i + 2 ) ;
2007-08-26 15:16:40 +00:00
regf - > hbins [ i ] = NULL ;
2007-10-06 00:17:44 +00:00
}
2007-08-26 15:16:40 +00:00
2007-12-13 22:46:51 +01:00
talloc_free ( pull ) ;
2007-08-26 15:16:40 +00:00
DEBUG ( 1 , ( " %d HBIN blocks read \n " , i ) ) ;
2007-10-06 00:17:44 +00:00
* key = ( struct hive_key * ) regf_get_key ( parent_ctx , regf ,
regf - > header - > data_offset ) ;
2007-08-26 15:16:40 +00:00
/* We can drop our own reference now that *key will have created one */
2009-09-26 15:41:22 +02:00
talloc_unlink ( parent_ctx , regf ) ;
2007-08-26 15:16:40 +00:00
return WERR_OK ;
}
static struct hive_operations reg_backend_regf = {
. name = " regf " ,
. get_key_info = regf_get_info ,
. enum_key = regf_get_subkey_by_index ,
. get_key_by_name = regf_get_subkey_by_name ,
. get_value_by_name = regf_get_value_by_name ,
. enum_value = regf_get_value ,
. get_sec_desc = regf_get_sec_desc ,
. set_sec_desc = regf_set_sec_desc ,
. add_key = regf_add_key ,
. set_value = regf_set_value ,
. del_key = regf_del_key ,
. delete_value = regf_del_value ,
} ;