2002-07-19 03:00:24 +04:00
/*
* Unix SMB / CIFS implementation .
2005-05-23 20:25:31 +04:00
* Virtual Windows Registry Layer
* Copyright ( C ) Gerald Carter 2002 - 2005
2002-07-19 03:00:24 +04:00
*
* 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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2002-07-19 03:00:24 +04:00
* ( 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
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2002-07-19 03:00:24 +04:00
*/
/* Implementation of internal registry database functions. */
# include "includes.h"
# undef DBGC_CLASS
2007-09-29 03:05:52 +04:00
# define DBGC_CLASS DBGC_REGISTRY
2002-07-19 03:00:24 +04:00
2008-03-17 01:07:15 +03:00
static struct db_context * regdb = NULL ;
2008-03-17 01:08:33 +03:00
static int regdb_refcount ;
2002-07-19 03:00:24 +04:00
2008-04-29 19:17:02 +04:00
static bool regdb_key_exists ( const char * key ) ;
2008-05-08 02:34:35 +04:00
static bool regdb_key_is_base_key ( const char * key ) ;
2008-04-29 19:17:02 +04:00
2005-05-23 20:25:31 +04:00
/* List the deepest path into the registry. All part components will be created.*/
2005-08-29 18:55:40 +04:00
/* If you want to have a part of the path controlled by the tdb and part by
2005-05-23 20:25:31 +04:00
a virtual registry db ( e . g . printing ) , then you have to list the deepest path .
For example , " HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Print "
allows the reg_db backend to handle everything up to
" HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion " and then we ' ll hook
the reg_printing backend onto the last component of the path ( see
KEY_PRINTING_2K in include / rpc_reg . h ) - - jerry */
static const char * builtin_registry_paths [ ] = {
2005-06-30 23:43:53 +04:00
KEY_PRINTING_2K ,
KEY_PRINTING_PORTS ,
KEY_PRINTING ,
KEY_SHARES ,
KEY_EVENTLOG ,
2006-11-30 10:38:40 +03:00
KEY_SMBCONF ,
2008-01-20 05:39:27 +03:00
KEY_PERFLIB ,
KEY_PERFLIB_009 ,
2008-03-18 23:30:34 +03:00
KEY_GROUP_POLICY ,
KEY_SAMBA_GROUP_POLICY ,
KEY_GP_MACHINE_POLICY ,
KEY_GP_MACHINE_WIN_POLICY ,
KEY_HKCU ,
KEY_GP_USER_POLICY ,
KEY_GP_USER_WIN_POLICY ,
KEY_WINLOGON_GPEXT_PATH ,
2005-07-02 02:24:00 +04:00
" HKLM \\ SYSTEM \\ CurrentControlSet \\ Control \\ Print \\ Monitors " ,
2008-01-18 18:15:43 +03:00
KEY_PROD_OPTIONS ,
2005-09-01 18:58:57 +04:00
" HKLM \\ SYSTEM \\ CurrentControlSet \\ Control \\ Terminal Server \\ DefaultUserConfiguration " ,
2008-01-20 01:46:13 +03:00
KEY_TCPIP_PARAMS ,
2008-01-18 18:13:01 +03:00
KEY_NETLOGON_PARAMS ,
2008-01-20 03:09:52 +03:00
KEY_HKU ,
KEY_HKCR ,
KEY_HKPD ,
KEY_HKPT ,
2005-05-23 20:25:31 +04:00
NULL } ;
2005-06-17 19:53:01 +04:00
2005-06-25 02:34:40 +04:00
struct builtin_regkey_value {
const char * path ;
const char * valuename ;
uint32 type ;
union {
const char * string ;
uint32 dw_value ;
} data ;
} ;
2005-06-25 21:31:40 +04:00
static struct builtin_regkey_value builtin_registry_values [ ] = {
2005-08-05 18:34:25 +04:00
{ KEY_PRINTING_PORTS ,
2005-07-04 20:52:29 +04:00
SAMBA_PRINTER_PORT_NAME , REG_SZ , { " " } } ,
2005-08-05 18:34:25 +04:00
{ KEY_PRINTING_2K ,
2005-07-04 20:52:29 +04:00
" DefaultSpoolDirectory " , REG_SZ , { " C: \\ Windows \\ System32 \\ Spool \\ Printers " } } ,
2005-08-05 18:34:25 +04:00
{ KEY_EVENTLOG ,
" DisplayName " , REG_SZ , { " Event Log " } } ,
{ KEY_EVENTLOG ,
" ErrorControl " , REG_DWORD , { ( char * ) 0x00000001 } } ,
2005-06-25 21:31:40 +04:00
{ NULL , NULL , 0 , { NULL } }
2005-06-25 02:34:40 +04:00
} ;
2008-03-20 15:59:09 +03:00
/**
* Initialize a key in the registry :
* create each component key of the specified path .
*/
2008-04-13 15:38:44 +04:00
static WERROR init_registry_key_internal ( const char * add_path )
2002-07-19 03:00:24 +04:00
{
2008-04-13 15:38:44 +04:00
WERROR werr ;
2008-03-20 15:59:09 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2007-11-27 04:24:56 +03:00
char * path = NULL ;
char * base = NULL ;
char * remaining = NULL ;
2007-12-08 04:32:32 +03:00
char * keyname ;
char * subkeyname ;
2009-02-24 17:19:18 +03:00
struct regsubkey_ctr * subkeys ;
2006-12-03 20:34:11 +03:00
const char * p , * p2 ;
2007-02-07 16:26:13 +03:00
2008-03-20 15:59:09 +03:00
DEBUG ( 6 , ( " init_registry_key: Adding [%s] \n " , add_path ) ) ;
2007-02-07 16:26:13 +03:00
2008-03-20 15:59:09 +03:00
path = talloc_strdup ( frame , add_path ) ;
base = talloc_strdup ( frame , " " ) ;
if ( ! path | | ! base ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2008-03-20 15:59:09 +03:00
goto fail ;
2007-02-07 16:26:13 +03:00
}
2008-03-20 15:59:09 +03:00
p = path ;
2007-11-27 04:24:56 +03:00
2008-03-20 15:59:09 +03:00
while ( next_token_talloc ( frame , & p , & keyname , " \\ " ) ) {
2006-12-03 20:34:11 +03:00
2008-03-20 15:59:09 +03:00
/* build up the registry path from the components */
2007-11-27 04:24:56 +03:00
2008-03-20 15:59:09 +03:00
if ( * base ) {
base = talloc_asprintf ( frame , " %s \\ " , base ) ;
2007-11-27 04:24:56 +03:00
if ( ! base ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2007-11-27 04:24:56 +03:00
goto fail ;
}
2008-03-20 15:59:09 +03:00
}
base = talloc_asprintf_append ( base , " %s " , keyname ) ;
if ( ! base ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2008-03-20 15:59:09 +03:00
goto fail ;
}
2007-11-27 04:24:56 +03:00
2008-03-20 15:59:09 +03:00
/* get the immediate subkeyname (if we have one ) */
2007-11-27 04:24:56 +03:00
2008-03-20 15:59:09 +03:00
subkeyname = talloc_strdup ( frame , " " ) ;
if ( ! subkeyname ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2008-03-20 15:59:09 +03:00
goto fail ;
}
if ( * p ) {
remaining = talloc_strdup ( frame , p ) ;
if ( ! remaining ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2007-12-08 04:32:32 +03:00
goto fail ;
}
2008-03-20 15:59:09 +03:00
p2 = remaining ;
if ( ! next_token_talloc ( frame , & p2 ,
& subkeyname , " \\ " ) )
{
subkeyname = talloc_strdup ( frame , p2 ) ;
if ( ! subkeyname ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2007-11-27 04:24:56 +03:00
goto fail ;
}
2006-12-03 20:34:11 +03:00
}
2008-03-20 15:59:09 +03:00
}
2006-12-03 20:34:11 +03:00
2008-03-20 15:59:09 +03:00
DEBUG ( 10 , ( " init_registry_key: Storing key [%s] with "
" subkey [%s] \n " , base ,
* subkeyname ? subkeyname : " NULL " ) ) ;
2007-11-27 04:24:56 +03:00
2008-03-20 15:59:09 +03:00
/* we don't really care if the lookup succeeds or not
* since we are about to update the record .
* We just want any subkeys already present */
2007-11-27 04:24:56 +03:00
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( frame , & subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-03-20 15:59:09 +03:00
DEBUG ( 0 , ( " talloc() failure! \n " ) ) ;
goto fail ;
}
2006-12-03 20:34:11 +03:00
2008-03-20 15:59:09 +03:00
regdb_fetch_keys ( base , subkeys ) ;
if ( * subkeyname ) {
2008-04-13 15:38:44 +04:00
werr = regsubkey_ctr_addkey ( subkeys , subkeyname ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
goto fail ;
}
2008-03-20 15:59:09 +03:00
}
if ( ! regdb_store_keys ( base , subkeys ) ) {
2008-04-13 15:38:44 +04:00
werr = WERR_CAN_NOT_COMPLETE ;
2008-03-20 15:59:09 +03:00
goto fail ;
2005-05-23 20:25:31 +04:00
}
2008-03-20 15:59:09 +03:00
}
2008-04-13 15:38:44 +04:00
werr = WERR_OK ;
2008-03-20 15:59:09 +03:00
fail :
TALLOC_FREE ( frame ) ;
2008-04-13 15:38:44 +04:00
return werr ;
2008-03-20 15:59:09 +03:00
}
2007-12-14 00:20:58 +03:00
2008-03-20 16:01:13 +03:00
/**
* Initialize a key in the registry :
* create each component key of the specified path ,
* wrapped in one db transaction .
*/
2008-04-13 15:38:44 +04:00
WERROR init_registry_key ( const char * add_path )
2008-03-20 16:01:13 +03:00
{
2008-04-13 15:38:44 +04:00
WERROR werr ;
2008-04-29 19:18:26 +04:00
if ( regdb_key_exists ( add_path ) ) {
return WERR_OK ;
}
2008-03-27 18:56:38 +03:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
2008-03-20 16:01:13 +03:00
DEBUG ( 0 , ( " init_registry_key: transaction_start failed \n " ) ) ;
2008-04-13 15:38:44 +04:00
return WERR_REG_IO_FAILURE ;
2008-03-20 16:01:13 +03:00
}
2008-04-13 15:38:44 +04:00
werr = init_registry_key_internal ( add_path ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-03-20 16:01:13 +03:00
goto fail ;
}
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_commit ( regdb ) ! = 0 ) {
2008-03-20 16:01:13 +03:00
DEBUG ( 0 , ( " init_registry_key: Could not commit transaction \n " ) ) ;
2008-04-13 15:38:44 +04:00
return WERR_REG_IO_FAILURE ;
2008-03-20 16:01:13 +03:00
}
2008-04-13 15:38:44 +04:00
return WERR_OK ;
2008-03-20 16:01:13 +03:00
fail :
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_cancel ( regdb ) ! = 0 ) {
2008-03-20 16:01:13 +03:00
smb_panic ( " init_registry_key: transaction_cancel failed \n " ) ;
}
2008-04-13 15:38:44 +04:00
return werr ;
2008-03-20 16:01:13 +03:00
}
2008-03-20 15:59:09 +03:00
/***********************************************************************
Open the registry data in the tdb
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-13 15:38:44 +04:00
WERROR init_registry_data ( void )
2008-03-20 15:59:09 +03:00
{
2008-04-13 15:38:44 +04:00
WERROR werr ;
2008-04-29 19:37:35 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-03-20 15:59:09 +03:00
REGVAL_CTR * values ;
int i ;
UNISTR2 data ;
2008-04-29 19:37:35 +04:00
/*
* First , check for the existence of the needed keys and values .
* If all do already exist , we can save the writes .
*/
for ( i = 0 ; builtin_registry_paths [ i ] ! = NULL ; i + + ) {
if ( ! regdb_key_exists ( builtin_registry_paths [ i ] ) ) {
goto do_init ;
}
}
for ( i = 0 ; builtin_registry_values [ i ] . path ! = NULL ; i + + ) {
values = TALLOC_ZERO_P ( frame , REGVAL_CTR ) ;
if ( values = = NULL ) {
werr = WERR_NOMEM ;
goto done ;
}
regdb_fetch_values ( builtin_registry_values [ i ] . path , values ) ;
if ( ! regval_ctr_key_exists ( values ,
builtin_registry_values [ i ] . valuename ) )
{
TALLOC_FREE ( values ) ;
goto do_init ;
}
TALLOC_FREE ( values ) ;
}
werr = WERR_OK ;
goto done ;
do_init :
2008-03-20 15:59:09 +03:00
/*
* There are potentially quite a few store operations which are all
* indiviually wrapped in tdb transactions . Wrapping them in a single
* transaction gives just a single transaction_commit ( ) to actually do
* its fsync ( ) s . See tdb / common / transaction . c for info about nested
* transaction behaviour .
*/
2008-03-27 18:56:38 +03:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
2008-03-20 15:59:09 +03:00
DEBUG ( 0 , ( " init_registry_data: tdb_transaction_start "
" failed \n " ) ) ;
2008-04-29 19:37:35 +04:00
werr = WERR_REG_IO_FAILURE ;
goto done ;
2008-03-20 15:59:09 +03:00
}
/* loop over all of the predefined paths and add each component */
for ( i = 0 ; builtin_registry_paths [ i ] ! = NULL ; i + + ) {
2008-04-29 19:41:03 +04:00
if ( regdb_key_exists ( builtin_registry_paths [ i ] ) ) {
continue ;
}
2008-04-13 15:38:44 +04:00
werr = init_registry_key_internal ( builtin_registry_paths [ i ] ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-03-20 15:59:09 +03:00
goto fail ;
}
2005-05-23 20:25:31 +04:00
}
2005-05-09 17:51:44 +04:00
2005-06-25 21:31:40 +04:00
/* loop over all of the predefined values and add each component */
2007-11-27 04:24:56 +03:00
for ( i = 0 ; builtin_registry_values [ i ] . path ! = NULL ; i + + ) {
2007-12-14 00:20:58 +03:00
2008-03-17 14:21:32 +03:00
values = TALLOC_ZERO_P ( frame , REGVAL_CTR ) ;
if ( values = = NULL ) {
2008-04-13 15:38:44 +04:00
werr = WERR_NOMEM ;
2007-02-07 16:26:13 +03:00
goto fail ;
2005-08-29 18:55:40 +04:00
}
2008-03-17 02:02:52 +03:00
regdb_fetch_values ( builtin_registry_values [ i ] . path , values ) ;
2006-12-03 20:34:11 +03:00
2008-03-17 02:02:52 +03:00
/* preserve existing values across restarts. Only add new ones */
2006-12-03 20:34:11 +03:00
2008-03-17 02:02:52 +03:00
if ( ! regval_ctr_key_exists ( values ,
builtin_registry_values [ i ] . valuename ) )
{
2007-11-27 04:24:56 +03:00
switch ( builtin_registry_values [ i ] . type ) {
2006-12-03 20:34:11 +03:00
case REG_DWORD :
2008-03-17 02:02:52 +03:00
regval_ctr_addvalue ( values ,
builtin_registry_values [ i ] . valuename ,
REG_DWORD ,
( char * ) & builtin_registry_values [ i ] . data . dw_value ,
sizeof ( uint32 ) ) ;
2006-12-03 20:34:11 +03:00
break ;
2007-11-27 04:24:56 +03:00
2006-12-03 20:34:11 +03:00
case REG_SZ :
2008-03-17 02:02:52 +03:00
init_unistr2 ( & data ,
builtin_registry_values [ i ] . data . string ,
UNI_STR_TERMINATE ) ;
regval_ctr_addvalue ( values ,
builtin_registry_values [ i ] . valuename ,
REG_SZ ,
( char * ) data . buffer ,
data . uni_str_len * sizeof ( uint16 ) ) ;
2006-12-03 20:34:11 +03:00
break ;
2007-11-27 04:24:56 +03:00
2006-12-03 20:34:11 +03:00
default :
2008-03-17 02:02:52 +03:00
DEBUG ( 0 , ( " init_registry_data: invalid value "
" type in builtin_registry_values "
" [%d] \n " ,
builtin_registry_values [ i ] . type ) ) ;
2006-12-03 20:34:11 +03:00
}
2008-03-17 02:02:52 +03:00
regdb_store_values ( builtin_registry_values [ i ] . path ,
values ) ;
2005-06-25 21:31:40 +04:00
}
2008-03-17 02:02:52 +03:00
TALLOC_FREE ( values ) ;
2005-06-25 21:31:40 +04:00
}
2007-11-27 04:24:56 +03:00
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_commit ( regdb ) ! = 0 ) {
2007-02-07 16:26:13 +03:00
DEBUG ( 0 , ( " init_registry_data: Could not commit "
" transaction \n " ) ) ;
2008-04-29 19:37:35 +04:00
werr = WERR_REG_IO_FAILURE ;
} else {
werr = WERR_OK ;
2007-02-07 16:26:13 +03:00
}
2008-04-29 19:37:35 +04:00
goto done ;
2007-12-14 00:20:58 +03:00
2008-04-29 19:37:35 +04:00
fail :
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_cancel ( regdb ) ! = 0 ) {
2007-02-07 16:26:13 +03:00
smb_panic ( " init_registry_data: tdb_transaction_cancel "
" failed \n " ) ;
}
2008-04-29 19:37:35 +04:00
done :
TALLOC_FREE ( frame ) ;
2008-04-13 15:38:44 +04:00
return werr ;
2002-07-19 03:00:24 +04:00
}
/***********************************************************************
Open the registry database
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-13 14:41:34 +04:00
WERROR regdb_init ( void )
2002-07-19 03:00:24 +04:00
{
2005-06-17 19:53:01 +04:00
const char * vstring = " INFO/version " ;
uint32 vers_id ;
2008-04-13 14:41:34 +04:00
WERROR werr ;
2002-07-19 03:00:24 +04:00
2008-03-20 16:26:42 +03:00
if ( regdb ) {
DEBUG ( 10 , ( " regdb_init: incrementing refcount (%d) \n " ,
regdb_refcount ) ) ;
2008-03-17 01:08:33 +03:00
regdb_refcount + + ;
2008-04-13 14:41:34 +04:00
return WERR_OK ;
2008-02-19 03:04:31 +03:00
}
2002-07-19 03:00:24 +04:00
2008-08-07 10:20:05 +04:00
regdb = db_open ( NULL , state_path ( " registry.tdb " ) , 0 ,
2008-03-27 18:57:51 +03:00
REG_TDB_FLAGS , O_RDWR , 0600 ) ;
2008-03-20 16:24:12 +03:00
if ( ! regdb ) {
2008-08-07 10:20:05 +04:00
regdb = db_open ( NULL , state_path ( " registry.tdb " ) , 0 ,
2008-03-27 18:57:51 +03:00
REG_TDB_FLAGS , O_RDWR | O_CREAT , 0600 ) ;
2008-03-20 16:26:42 +03:00
if ( ! regdb ) {
2008-04-13 14:41:34 +04:00
werr = ntstatus_to_werror ( map_nt_error_from_unix ( errno ) ) ;
2008-07-15 16:22:55 +04:00
DEBUG ( 1 , ( " regdb_init: Failed to open registry %s (%s) \n " ,
2007-11-01 22:53:44 +03:00
state_path ( " registry.tdb " ) , strerror ( errno ) ) ) ;
2008-04-13 14:41:34 +04:00
return werr ;
2002-07-19 03:00:24 +04:00
}
2005-10-07 16:14:25 +04:00
DEBUG ( 10 , ( " regdb_init: Successfully created registry tdb \n " ) ) ;
2005-05-23 20:25:31 +04:00
}
2005-10-07 16:14:25 +04:00
2008-03-17 01:08:33 +03:00
regdb_refcount = 1 ;
2005-05-23 20:25:31 +04:00
2008-03-17 01:07:15 +03:00
vers_id = dbwrap_fetch_int32 ( regdb , vstring ) ;
2005-06-17 19:53:01 +04:00
if ( vers_id ! = REGVER_V1 ) {
2008-03-28 13:53:00 +03:00
NTSTATUS status ;
2005-09-01 18:00:53 +04:00
/* any upgrade code here if needed */
2008-03-20 16:35:41 +03:00
DEBUG ( 10 , ( " regdb_init: got %s = %d != %d \n " , vstring ,
2007-06-16 01:38:10 +04:00
vers_id , REGVER_V1 ) ) ;
2008-03-28 13:53:00 +03:00
status = dbwrap_trans_store_int32 ( regdb , vstring , REGVER_V1 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-07-15 16:25:00 +04:00
DEBUG ( 1 , ( " regdb_init: error storing %s = %d: %s \n " ,
2008-03-28 13:53:00 +03:00
vstring , REGVER_V1 , nt_errstr ( status ) ) ) ;
2008-04-13 14:41:34 +04:00
return ntstatus_to_werror ( status ) ;
2008-03-20 16:33:43 +03:00
} else {
DEBUG ( 10 , ( " regdb_init: stored %s = %d \n " ,
vstring , REGVER_V1 ) ) ;
}
2005-09-01 18:00:53 +04:00
}
2005-06-17 19:53:01 +04:00
2008-04-13 14:41:34 +04:00
return WERR_OK ;
2002-07-19 03:00:24 +04:00
}
2005-10-07 16:14:25 +04:00
/***********************************************************************
Open the registry . Must already have been initialized by regdb_init ( )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
WERROR regdb_open ( void )
{
WERROR result = WERR_OK ;
2008-03-17 01:07:15 +03:00
if ( regdb ) {
2008-03-17 01:08:33 +03:00
DEBUG ( 10 , ( " regdb_open: incrementing refcount (%d) \n " , regdb_refcount ) ) ;
regdb_refcount + + ;
2005-10-07 16:14:25 +04:00
return WERR_OK ;
}
become_root ( ) ;
2008-08-07 10:20:05 +04:00
regdb = db_open ( NULL , state_path ( " registry.tdb " ) , 0 ,
2008-03-27 18:57:51 +03:00
REG_TDB_FLAGS , O_RDWR , 0600 ) ;
2008-03-17 01:07:15 +03:00
if ( ! regdb ) {
2005-10-07 16:14:25 +04:00
result = ntstatus_to_werror ( map_nt_error_from_unix ( errno ) ) ;
DEBUG ( 0 , ( " regdb_open: Failed to open %s! (%s) \n " ,
2007-11-01 22:53:44 +03:00
state_path ( " registry.tdb " ) , strerror ( errno ) ) ) ;
2005-10-07 16:14:25 +04:00
}
unbecome_root ( ) ;
2008-03-17 01:08:33 +03:00
regdb_refcount = 1 ;
DEBUG ( 10 , ( " regdb_open: refcount reset (%d) \n " , regdb_refcount ) ) ;
2005-10-07 16:14:25 +04:00
return result ;
}
/***********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int regdb_close ( void )
{
2008-03-17 01:08:33 +03:00
if ( regdb_refcount = = 0 ) {
2008-01-04 14:57:49 +03:00
return 0 ;
}
2008-03-17 01:08:33 +03:00
regdb_refcount - - ;
2005-10-07 16:14:25 +04:00
2008-03-17 01:08:33 +03:00
DEBUG ( 10 , ( " regdb_close: decrementing refcount (%d) \n " , regdb_refcount ) ) ;
2005-10-07 16:14:25 +04:00
2008-03-17 01:08:33 +03:00
if ( regdb_refcount > 0 )
2005-10-07 16:14:25 +04:00
return 0 ;
2008-03-17 01:08:33 +03:00
SMB_ASSERT ( regdb_refcount > = 0 ) ;
2005-10-07 16:14:25 +04:00
2008-03-17 01:07:15 +03:00
TALLOC_FREE ( regdb ) ;
2007-06-15 14:40:36 +04:00
return 0 ;
2005-10-07 16:14:25 +04:00
}
2009-02-24 12:44:48 +03:00
WERROR regdb_transaction_start ( void )
{
return ( regdb - > transaction_start ( regdb ) = = 0 ) ?
WERR_OK : WERR_REG_IO_FAILURE ;
}
WERROR regdb_transaction_commit ( void )
{
return ( regdb - > transaction_commit ( regdb ) = = 0 ) ?
WERR_OK : WERR_REG_IO_FAILURE ;
}
WERROR regdb_transaction_cancel ( void )
{
return ( regdb - > transaction_cancel ( regdb ) = = 0 ) ?
WERR_OK : WERR_REG_IO_FAILURE ;
}
2007-06-13 17:15:16 +04:00
/***********************************************************************
return the tdb sequence number of the registry tdb .
this is an indicator for the content of the registry
having changed . it will change upon regdb_init , too , though .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int regdb_get_seqnum ( void )
{
2008-03-17 01:07:15 +03:00
return regdb - > get_seqnum ( regdb ) ;
2007-06-13 17:15:16 +04:00
}
2009-02-26 03:16:07 +03:00
static WERROR regdb_delete_key_with_prefix ( const char * keyname ,
const char * prefix )
{
char * path ;
WERROR werr = WERR_NOMEM ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
if ( keyname = = NULL ) {
werr = WERR_INVALID_PARAM ;
goto done ;
}
if ( prefix = = NULL ) {
path = discard_const_p ( char , keyname ) ;
} else {
path = talloc_asprintf ( mem_ctx , " %s/%s " , prefix , keyname ) ;
if ( path = = NULL ) {
goto done ;
}
}
path = normalize_reg_path ( mem_ctx , path ) ;
if ( path = = NULL ) {
goto done ;
}
werr = ntstatus_to_werror ( dbwrap_delete_bystring ( regdb , path ) ) ;
/* treat "not" found" as ok */
if ( W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) ) {
werr = WERR_OK ;
}
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
static WERROR regdb_delete_values ( const char * keyname )
{
return regdb_delete_key_with_prefix ( keyname , REG_VALUE_PREFIX ) ;
}
static WERROR regdb_delete_secdesc ( const char * keyname )
{
return regdb_delete_key_with_prefix ( keyname , REG_SECDESC_PREFIX ) ;
}
static WERROR regdb_delete_subkeylist ( const char * keyname )
{
return regdb_delete_key_with_prefix ( keyname , NULL ) ;
}
2009-02-26 03:43:58 +03:00
static WERROR regdb_delete_key_lists ( const char * keyname )
{
WERROR werr ;
werr = regdb_delete_values ( keyname ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 1 , ( __location__ " Deleting %s/%s failed: %s \n " ,
REG_VALUE_PREFIX , keyname , win_errstr ( werr ) ) ) ;
goto done ;
}
werr = regdb_delete_secdesc ( keyname ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 1 , ( __location__ " Deleting %s/%s failed: %s \n " ,
REG_SECDESC_PREFIX , keyname , win_errstr ( werr ) ) ) ;
goto done ;
}
werr = regdb_delete_subkeylist ( keyname ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 1 , ( __location__ " Deleting %s failed: %s \n " ,
keyname , win_errstr ( werr ) ) ) ;
goto done ;
}
done :
return werr ;
}
2002-07-19 03:00:24 +04:00
/***********************************************************************
Add subkey strings to the registry tdb under a defined key
fmt is the same format as tdb_pack except this function only supports
fstrings
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-27 04:24:56 +03:00
2009-02-24 17:19:18 +03:00
static bool regdb_store_keys_internal ( const char * key , struct regsubkey_ctr * ctr )
2002-07-19 03:00:24 +04:00
{
2007-03-27 14:13:53 +04:00
TDB_DATA dbuf ;
2007-11-27 04:24:56 +03:00
uint8 * buffer = NULL ;
2002-07-19 03:00:24 +04:00
int i = 0 ;
uint32 len , buflen ;
2008-01-04 17:20:46 +03:00
bool ret = true ;
2007-11-27 04:24:56 +03:00
uint32 num_subkeys = regsubkey_ctr_numkeys ( ctr ) ;
char * keyname = NULL ;
2008-03-17 02:09:07 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
2008-03-17 01:03:34 +03:00
NTSTATUS status ;
2005-05-23 20:25:31 +04:00
2007-11-27 04:24:56 +03:00
if ( ! key ) {
return false ;
}
keyname = talloc_strdup ( ctx , key ) ;
if ( ! keyname ) {
return false ;
}
keyname = normalize_reg_path ( ctx , keyname ) ;
2005-06-17 22:57:37 +04:00
2002-07-19 03:00:24 +04:00
/* allocate some initial memory */
2007-11-27 04:24:56 +03:00
2008-03-17 02:22:12 +03:00
buffer = ( uint8 * ) SMB_MALLOC ( 1024 ) ;
if ( buffer = = NULL ) {
2008-01-04 17:20:46 +03:00
return false ;
2006-07-15 12:36:44 +04:00
}
2007-11-27 04:24:56 +03:00
buflen = 1024 ;
2002-07-19 03:00:24 +04:00
len = 0 ;
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
/* store the number of subkeys */
2007-11-27 04:24:56 +03:00
2008-03-17 02:22:12 +03:00
len + = tdb_pack ( buffer + len , buflen - len , " d " , num_subkeys ) ;
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
/* pack all the strings */
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
2009-02-19 16:16:44 +03:00
size_t thistime ;
thistime = tdb_pack ( buffer + len , buflen - len , " f " ,
regsubkey_ctr_specific_key ( ctr , i ) ) ;
if ( len + thistime > buflen ) {
size_t thistime2 ;
/*
* tdb_pack hasn ' t done anything because of the short
* buffer , allocate extra space .
*/
buffer = SMB_REALLOC_ARRAY ( buffer , uint8_t ,
( len + thistime ) * 2 ) ;
2008-03-17 02:22:12 +03:00
if ( buffer = = NULL ) {
DEBUG ( 0 , ( " regdb_store_keys: Failed to realloc "
2009-02-20 00:11:36 +03:00
" memory of size [%u] \n " ,
( unsigned int ) ( len + thistime ) * 2 ) ) ;
2009-02-19 16:16:44 +03:00
ret = false ;
goto done ;
}
buflen = ( len + thistime ) * 2 ;
thistime2 = tdb_pack (
buffer + len , buflen - len , " f " ,
regsubkey_ctr_specific_key ( ctr , i ) ) ;
if ( thistime2 ! = thistime ) {
DEBUG ( 0 , ( " tdb_pack failed \n " ) ) ;
2008-01-04 17:20:46 +03:00
ret = false ;
2002-07-19 03:00:24 +04:00
goto done ;
}
2007-11-27 04:24:56 +03:00
}
2009-02-19 16:16:44 +03:00
len + = thistime ;
2002-07-19 03:00:24 +04:00
}
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
/* finally write out the data */
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
dbuf . dptr = buffer ;
dbuf . dsize = len ;
2008-03-17 01:07:15 +03:00
status = dbwrap_store_bystring ( regdb , keyname , dbuf , TDB_REPLACE ) ;
2008-03-17 01:03:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-04 17:20:46 +03:00
ret = false ;
2002-07-19 03:00:24 +04:00
goto done ;
}
2009-02-20 08:01:16 +03:00
/*
* Delete a sorted subkey cache for regdb_key_exists , will be
* recreated automatically
*/
keyname = talloc_asprintf ( ctx , " %s/%s " , REG_SORTED_SUBKEYS_PREFIX ,
keyname ) ;
if ( keyname ! = NULL ) {
dbwrap_delete_bystring ( regdb , keyname ) ;
}
2007-11-27 04:24:56 +03:00
done :
2008-03-17 02:09:07 +03:00
TALLOC_FREE ( ctx ) ;
2008-03-17 02:22:12 +03:00
SAFE_FREE ( buffer ) ;
2002-07-19 03:00:24 +04:00
return ret ;
}
2005-06-17 19:35:31 +04:00
/***********************************************************************
2007-11-27 04:24:56 +03:00
Store the new subkey record and create any child key records that
2005-06-17 19:35:31 +04:00
do not currently exist
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-24 17:19:18 +03:00
bool regdb_store_keys ( const char * key , struct regsubkey_ctr * ctr )
2005-06-17 19:35:31 +04:00
{
2009-02-24 19:42:50 +03:00
int num_subkeys , old_num_subkeys , i ;
2007-11-27 04:24:56 +03:00
char * path = NULL ;
2009-02-24 17:19:18 +03:00
struct regsubkey_ctr * subkeys = NULL , * old_subkeys = NULL ;
2007-11-27 04:24:56 +03:00
char * oldkeyname = NULL ;
2008-03-17 02:41:59 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
2009-02-25 01:18:20 +03:00
WERROR werr ;
2007-11-27 04:24:56 +03:00
2008-05-07 16:01:49 +04:00
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( key ) ) {
goto fail ;
}
2007-10-06 00:42:14 +04:00
/*
* fetch a list of the old subkeys so we can determine if anything has
* changed
*/
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( ctx , & old_subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2007-10-06 00:42:14 +04:00
DEBUG ( 0 , ( " regdb_store_keys: talloc() failure! \n " ) ) ;
2007-11-27 04:24:56 +03:00
return false ;
2007-10-06 00:42:14 +04:00
}
2007-11-27 04:24:56 +03:00
regdb_fetch_keys ( key , old_subkeys ) ;
2007-10-06 00:42:14 +04:00
2009-02-24 19:42:50 +03:00
num_subkeys = regsubkey_ctr_numkeys ( ctr ) ;
old_num_subkeys = regsubkey_ctr_numkeys ( old_subkeys ) ;
if ( ( num_subkeys & & old_num_subkeys ) & &
( num_subkeys = = old_num_subkeys ) ) {
2007-10-06 00:42:14 +04:00
2009-02-24 19:42:50 +03:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
2009-02-25 00:16:40 +03:00
if ( strcmp ( regsubkey_ctr_specific_key ( ctr , i ) ,
regsubkey_ctr_specific_key ( old_subkeys , i ) )
! = 0 )
{
2007-10-06 00:42:14 +04:00
break ;
}
}
2009-02-24 19:42:50 +03:00
if ( i = = num_subkeys ) {
2007-10-06 00:42:14 +04:00
/*
* Nothing changed , no point to even start a tdb
* transaction
*/
TALLOC_FREE ( old_subkeys ) ;
2007-11-27 04:24:56 +03:00
return true ;
2007-10-06 00:42:14 +04:00
}
}
2008-03-17 02:43:56 +03:00
TALLOC_FREE ( old_subkeys ) ;
2008-03-27 18:56:38 +03:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
2008-03-17 01:03:34 +03:00
DEBUG ( 0 , ( " regdb_store_keys: transaction_start failed \n " ) ) ;
2008-03-17 03:00:40 +03:00
goto fail ;
2006-11-22 19:53:28 +03:00
}
2007-10-06 00:42:14 +04:00
/*
* Re - fetch the old keys inside the transaction
*/
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( ctx , & old_subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2005-08-29 18:55:40 +04:00
DEBUG ( 0 , ( " regdb_store_keys: talloc() failure! \n " ) ) ;
2008-03-17 03:00:40 +03:00
goto cancel ;
2005-08-29 18:55:40 +04:00
}
2007-11-27 04:24:56 +03:00
regdb_fetch_keys ( key , old_subkeys ) ;
2008-05-06 12:06:34 +04:00
/*
* Make the store operation as safe as possible without transactions :
*
* ( 1 ) For each subkey removed from ctr compared with old_subkeys :
*
* ( a ) First delete the value db entry .
*
* ( b ) Next delete the secdesc db record .
*
* ( c ) Then delete the subkey list entry .
*
* ( 2 ) Now write the list of subkeys of the parent key ,
* deleting removed entries and adding new ones .
*
* ( 3 ) Finally create the subkey list entries for the added keys .
*
* This way if we crash half - way in between deleting the subkeys
* and storing the parent ' s list of subkeys , no old data can pop up
* out of the blue when re - adding keys later on .
*/
2008-05-08 18:55:14 +04:00
/* (1) delete removed keys' lists (values/secdesc/subkeys) */
2006-11-22 19:53:28 +03:00
2007-11-27 04:24:56 +03:00
num_subkeys = regsubkey_ctr_numkeys ( old_subkeys ) ;
for ( i = 0 ; i < num_subkeys ; i + + ) {
oldkeyname = regsubkey_ctr_specific_key ( old_subkeys , i ) ;
if ( regsubkey_ctr_key_exists ( ctr , oldkeyname ) ) {
2006-11-22 19:53:28 +03:00
/*
* It ' s still around , don ' t delete
*/
continue ;
}
2009-02-26 03:16:07 +03:00
path = talloc_asprintf ( ctx , " %s/%s " , key , oldkeyname ) ;
2007-11-27 04:24:56 +03:00
if ( ! path ) {
2008-03-17 03:00:40 +03:00
goto cancel ;
2007-11-27 04:24:56 +03:00
}
2009-02-26 03:16:07 +03:00
2009-02-26 03:43:58 +03:00
werr = regdb_delete_key_lists ( path ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
2009-02-26 03:16:07 +03:00
2007-11-27 04:24:56 +03:00
TALLOC_FREE ( path ) ;
2005-06-17 22:57:37 +04:00
}
2005-06-27 07:40:03 +04:00
2007-11-27 04:24:56 +03:00
TALLOC_FREE ( old_subkeys ) ;
2008-05-08 16:33:02 +04:00
/* (2) store the subkey list for the parent */
if ( ! regdb_store_keys_internal ( key , ctr ) ) {
DEBUG ( 0 , ( " regdb_store_keys: Failed to store new subkey list "
" for parent [%s] \n " , key ) ) ;
goto cancel ;
}
2008-05-08 18:32:51 +04:00
/* (3) now create records for any subkeys that don't already exist */
2005-08-29 18:55:40 +04:00
2007-11-27 04:24:56 +03:00
num_subkeys = regsubkey_ctr_numkeys ( ctr ) ;
2008-03-01 02:32:36 +03:00
if ( num_subkeys = = 0 ) {
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( ctx , & subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-03-01 02:32:36 +03:00
DEBUG ( 0 , ( " regdb_store_keys: talloc() failure! \n " ) ) ;
2008-03-17 03:00:40 +03:00
goto cancel ;
2008-03-01 02:32:36 +03:00
}
if ( ! regdb_store_keys_internal ( key , subkeys ) ) {
DEBUG ( 0 , ( " regdb_store_keys: Failed to store "
" new record for key [%s] \n " , key ) ) ;
2008-03-17 03:00:40 +03:00
goto cancel ;
2008-03-01 02:32:36 +03:00
}
TALLOC_FREE ( subkeys ) ;
}
2007-11-27 04:24:56 +03:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
path = talloc_asprintf ( ctx , " %s/%s " ,
key ,
regsubkey_ctr_specific_key ( ctr , i ) ) ;
if ( ! path ) {
2008-03-17 03:00:40 +03:00
goto cancel ;
2007-11-27 04:24:56 +03:00
}
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( ctx , & subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2005-08-29 18:55:40 +04:00
DEBUG ( 0 , ( " regdb_store_keys: talloc() failure! \n " ) ) ;
2008-03-17 03:00:40 +03:00
goto cancel ;
2005-08-29 18:55:40 +04:00
}
2007-11-27 04:24:56 +03:00
if ( regdb_fetch_keys ( path , subkeys ) = = - 1 ) {
2005-06-17 19:35:31 +04:00
/* create a record with 0 subkeys */
2007-11-27 04:24:56 +03:00
if ( ! regdb_store_keys_internal ( path , subkeys ) ) {
2006-11-22 18:10:46 +03:00
DEBUG ( 0 , ( " regdb_store_keys: Failed to store "
2007-11-27 04:24:56 +03:00
" new record for key [%s] \n " , path ) ) ;
2008-03-17 03:00:40 +03:00
goto cancel ;
2005-06-17 19:35:31 +04:00
}
}
2005-08-29 18:55:40 +04:00
2007-11-27 04:24:56 +03:00
TALLOC_FREE ( subkeys ) ;
TALLOC_FREE ( path ) ;
2005-06-17 19:35:31 +04:00
}
2006-11-22 19:53:28 +03:00
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_commit ( regdb ) ! = 0 ) {
2006-11-22 19:53:28 +03:00
DEBUG ( 0 , ( " regdb_store_keys: Could not commit transaction \n " ) ) ;
2008-03-17 03:00:40 +03:00
goto fail ;
2006-11-22 19:53:28 +03:00
}
2008-03-17 03:05:48 +03:00
TALLOC_FREE ( ctx ) ;
2007-11-27 04:24:56 +03:00
return true ;
2006-11-22 19:53:28 +03:00
2008-03-17 03:00:40 +03:00
cancel :
2008-03-27 19:44:36 +03:00
if ( regdb - > transaction_cancel ( regdb ) ! = 0 ) {
2008-03-17 01:03:34 +03:00
smb_panic ( " regdb_store_keys: transaction_cancel failed \n " ) ;
2006-11-22 19:53:28 +03:00
}
2008-03-17 03:00:40 +03:00
fail :
TALLOC_FREE ( ctx ) ;
2007-11-27 04:24:56 +03:00
return false ;
2005-06-17 19:35:31 +04:00
}
2009-02-26 00:04:07 +03:00
static WERROR regdb_create_subkey ( const char * key , const char * subkey )
{
WERROR werr ;
struct regsubkey_ctr * subkeys ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( key ) ) {
werr = WERR_NOT_FOUND ;
goto done ;
}
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
if ( regdb_fetch_keys ( key , subkeys ) < 0 ) {
werr = WERR_REG_IO_FAILURE ;
goto done ;
}
if ( regsubkey_ctr_key_exists ( subkeys , subkey ) ) {
werr = WERR_OK ;
goto done ;
}
talloc_free ( subkeys ) ;
werr = regdb_transaction_start ( ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
if ( regdb_fetch_keys ( key , subkeys ) < 0 ) {
werr = WERR_REG_IO_FAILURE ;
goto cancel ;
}
werr = regsubkey_ctr_addkey ( subkeys , subkey ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
if ( ! regdb_store_keys_internal ( key , subkeys ) ) {
DEBUG ( 0 , ( __location__ " failed to store new subkey list for "
" parent key %s \n " , key ) ) ;
werr = WERR_REG_IO_FAILURE ;
goto cancel ;
}
werr = regdb_transaction_commit ( ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " failed to commit transaction: %s \n " ,
win_errstr ( werr ) ) ) ;
}
goto done ;
cancel :
werr = regdb_transaction_cancel ( ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " failed to cancel transaction: %s \n " ,
win_errstr ( werr ) ) ) ;
}
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
2005-06-17 19:35:31 +04:00
2009-02-26 04:56:00 +03:00
static WERROR regdb_delete_subkey ( const char * key , const char * subkey )
{
WERROR werr , werr2 ;
struct regsubkey_ctr * subkeys ;
char * path ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( key ) ) {
werr = WERR_NOT_FOUND ;
goto done ;
}
path = talloc_asprintf ( mem_ctx , " %s/%s " , key , subkey ) ;
if ( path = = NULL ) {
werr = WERR_NOMEM ;
goto done ;
}
if ( ! regdb_key_exists ( path ) ) {
werr = WERR_OK ;
goto done ;
}
werr = regdb_transaction_start ( ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regdb_delete_key_lists ( path ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
if ( regdb_fetch_keys ( key , subkeys ) < 0 ) {
werr = WERR_REG_IO_FAILURE ;
goto cancel ;
}
werr = regsubkey_ctr_delkey ( subkeys , subkey ) ;
W_ERROR_NOT_OK_GOTO ( werr , cancel ) ;
if ( ! regdb_store_keys_internal ( key , subkeys ) ) {
DEBUG ( 0 , ( __location__ " failed to store new subkey_list for "
" parent key %s \n " , key ) ) ;
werr = WERR_REG_IO_FAILURE ;
goto cancel ;
}
werr = regdb_transaction_commit ( ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " failed to commit transaction: %s \n " ,
win_errstr ( werr ) ) ) ;
}
goto done ;
cancel :
werr2 = regdb_transaction_cancel ( ) ;
if ( ! W_ERROR_IS_OK ( werr2 ) ) {
DEBUG ( 0 , ( __location__ " failed to cancel transaction: %s \n " ,
win_errstr ( werr2 ) ) ) ;
}
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
2008-05-06 19:09:57 +04:00
static TDB_DATA regdb_fetch_key_internal ( TALLOC_CTX * mem_ctx , const char * key )
2008-04-29 19:04:41 +04:00
{
char * path = NULL ;
2008-05-06 19:15:50 +04:00
TDB_DATA data ;
2008-04-29 19:04:41 +04:00
path = normalize_reg_path ( mem_ctx , key ) ;
if ( ! path ) {
return make_tdb_data ( NULL , 0 ) ;
}
2008-05-06 19:15:50 +04:00
data = dbwrap_fetch_bystring ( regdb , mem_ctx , path ) ;
TALLOC_FREE ( path ) ;
return data ;
2008-04-29 19:04:41 +04:00
}
2008-04-29 19:17:02 +04:00
2008-05-08 02:34:35 +04:00
/**
* check whether a given key name represents a base key ,
* i . e one without a subkey separator ( ' / ' or ' \ ' ) .
*/
static bool regdb_key_is_base_key ( const char * key )
{
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
bool ret = false ;
char * path ;
if ( key = = NULL ) {
goto done ;
}
path = normalize_reg_path ( mem_ctx , key ) ;
if ( path = = NULL ) {
DEBUG ( 0 , ( " out of memory! (talloc failed) \n " ) ) ;
goto done ;
}
if ( * path = = ' \0 ' ) {
goto done ;
}
ret = ( strrchr ( path , ' / ' ) = = NULL ) ;
done :
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2009-02-22 03:11:51 +03:00
/*
* regdb_key_exists ( ) is a very frequent operation . It can be quite
* time - consuming to fully fetch the parent ' s subkey list , talloc_strdup all
* subkeys and then compare the keyname linearly to all the parent ' s subkeys .
*
* The following code tries to make this operation as efficient as possible :
* Per registry key we create a list of subkeys that is very efficient to
* search for existence of a subkey . Its format is :
*
* 4 bytes num_subkeys
* 4 * num_subkey bytes offset into the string array
* then follows a sorted list of subkeys in uppercase
*
* This record is created by create_sorted_subkeys ( ) on demand if it does not
* exist . scan_parent_subkeys ( ) uses regdb - > parse_record to search the sorted
* list , the parsing code and the binary search can be found in
* parent_subkey_scanner . The code uses parse_record ( ) to avoid a memcpy of
* the potentially large subkey record .
*
* The sorted subkey record is deleted in regdb_store_keys_internal and
* recreated on demand .
*/
2009-02-20 08:01:16 +03:00
static int cmp_keynames ( const void * p1 , const void * p2 )
{
return StrCaseCmp ( * ( ( char * * ) p1 ) , * ( ( char * * ) p2 ) ) ;
}
static bool create_sorted_subkeys ( const char * key , const char * sorted_keyname )
{
char * * sorted_subkeys ;
2009-02-24 17:19:18 +03:00
struct regsubkey_ctr * ctr ;
2009-02-20 08:01:16 +03:00
bool result = false ;
NTSTATUS status ;
char * buf ;
char * p ;
int i , res ;
size_t len ;
2009-02-24 19:42:50 +03:00
int num_subkeys ;
2009-02-25 01:18:20 +03:00
WERROR werr ;
2009-02-20 08:01:16 +03:00
2009-02-22 12:11:29 +03:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
DEBUG ( 0 , ( " create_sorted_subkeys: transaction_start "
" failed \n " ) ) ;
return false ;
}
2009-02-25 01:18:20 +03:00
werr = regsubkey_ctr_init ( talloc_tos ( ) , & ctr ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2009-02-22 12:11:29 +03:00
goto fail ;
2009-02-20 08:01:16 +03:00
}
res = regdb_fetch_keys ( key , ctr ) ;
if ( res = = - 1 ) {
goto fail ;
}
2009-02-24 19:42:50 +03:00
num_subkeys = regsubkey_ctr_numkeys ( ctr ) ;
sorted_subkeys = talloc_array ( ctr , char * , num_subkeys ) ;
2009-02-20 08:01:16 +03:00
if ( sorted_subkeys = = NULL ) {
goto fail ;
}
2009-02-24 19:42:50 +03:00
len = 4 + 4 * num_subkeys ;
2009-02-20 08:01:16 +03:00
2009-02-24 19:42:50 +03:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
2009-02-20 08:01:16 +03:00
sorted_subkeys [ i ] = talloc_strdup_upper ( sorted_subkeys ,
2009-02-25 00:16:40 +03:00
regsubkey_ctr_specific_key ( ctr , i ) ) ;
2009-02-20 08:01:16 +03:00
if ( sorted_subkeys [ i ] = = NULL ) {
goto fail ;
}
len + = strlen ( sorted_subkeys [ i ] ) + 1 ;
}
2009-02-24 19:42:50 +03:00
qsort ( sorted_subkeys , num_subkeys , sizeof ( char * ) , cmp_keynames ) ;
2009-02-20 08:01:16 +03:00
buf = talloc_array ( ctr , char , len ) ;
if ( buf = = NULL ) {
goto fail ;
}
2009-02-24 19:42:50 +03:00
p = buf + 4 + 4 * num_subkeys ;
2009-02-20 08:01:16 +03:00
2009-02-24 19:42:50 +03:00
SIVAL ( buf , 0 , num_subkeys ) ;
2009-02-20 08:01:16 +03:00
2009-02-24 19:42:50 +03:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
2009-02-20 08:01:16 +03:00
ptrdiff_t offset = p - buf ;
SIVAL ( buf , 4 + 4 * i , offset ) ;
strlcpy ( p , sorted_subkeys [ i ] , len - offset ) ;
p + = strlen ( sorted_subkeys [ i ] ) + 1 ;
}
2009-02-22 12:11:29 +03:00
status = dbwrap_store_bystring (
2009-02-20 08:01:16 +03:00
regdb , sorted_keyname , make_tdb_data ( ( uint8_t * ) buf , len ) ,
TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-02-22 12:11:29 +03:00
/*
* Don ' t use a " goto fail; " here , this would commit the broken
* transaction . See below for an explanation .
*/
if ( regdb - > transaction_cancel ( regdb ) = = - 1 ) {
DEBUG ( 0 , ( " create_sorted_subkeys: transaction_cancel "
" failed \n " ) ) ;
}
TALLOC_FREE ( ctr ) ;
return false ;
2009-02-20 08:01:16 +03:00
}
result = true ;
fail :
2009-02-22 12:11:29 +03:00
/*
* We only get here via the " goto fail " when we did not write anything
* yet . Using transaction_commit even in a failure case is necessary
* because this ( disposable ) call might be nested in other
* transactions . Doing a cancel here would destroy the possibility of
* a transaction_commit for transactions that we might be wrapped in .
*/
if ( regdb - > transaction_commit ( regdb ) = = - 1 ) {
DEBUG ( 0 , ( " create_sorted_subkeys: transaction_start "
" failed \n " ) ) ;
goto fail ;
}
2009-02-20 08:01:16 +03:00
TALLOC_FREE ( ctr ) ;
return result ;
}
struct scan_subkey_state {
char * name ;
bool scanned ;
bool found ;
} ;
static int parent_subkey_scanner ( TDB_DATA key , TDB_DATA data ,
void * private_data )
{
struct scan_subkey_state * state =
( struct scan_subkey_state * ) private_data ;
uint32_t num_subkeys ;
uint32_t l , u ;
if ( data . dsize < sizeof ( uint32_t ) ) {
return - 1 ;
}
state - > scanned = true ;
state - > found = false ;
tdb_unpack ( data . dptr , data . dsize , " d " , & num_subkeys ) ;
l = 0 ;
u = num_subkeys ;
while ( l < u ) {
uint32_t idx = ( l + u ) / 2 ;
char * s = ( char * ) data . dptr + IVAL ( data . dptr , 4 + 4 * idx ) ;
int comparison = strcmp ( state - > name , s ) ;
if ( comparison < 0 ) {
u = idx ;
} else if ( comparison > 0 ) {
l = idx + 1 ;
} else {
state - > found = true ;
return 0 ;
}
}
return 0 ;
}
static bool scan_parent_subkeys ( const char * parent , const char * name )
{
char * path = NULL ;
char * key = NULL ;
struct scan_subkey_state state = { 0 , } ;
bool result = false ;
int res ;
state . name = NULL ;
path = normalize_reg_path ( talloc_tos ( ) , parent ) ;
if ( path = = NULL ) {
goto fail ;
}
key = talloc_asprintf ( talloc_tos ( ) , " %s/%s " ,
REG_SORTED_SUBKEYS_PREFIX , path ) ;
if ( key = = NULL ) {
goto fail ;
}
state . name = talloc_strdup_upper ( talloc_tos ( ) , name ) ;
if ( state . name = = NULL ) {
goto fail ;
}
state . scanned = false ;
res = regdb - > parse_record ( regdb , string_term_tdb_data ( key ) ,
parent_subkey_scanner , & state ) ;
if ( state . scanned ) {
result = state . found ;
} else {
if ( ! create_sorted_subkeys ( path , key ) ) {
goto fail ;
}
res = regdb - > parse_record ( regdb , string_term_tdb_data ( key ) ,
parent_subkey_scanner , & state ) ;
if ( ( res = = 0 ) & & ( state . scanned ) ) {
result = state . found ;
}
}
fail :
TALLOC_FREE ( path ) ;
TALLOC_FREE ( state . name ) ;
return result ;
}
2008-05-08 02:34:35 +04:00
2008-05-06 12:05:20 +04:00
/**
* Check for the existence of a key .
*
* Existence of a key is authoritatively defined by its
* existence in the list of subkeys of its parent key .
* The exeption of this are keys without a parent key ,
* i . e . the " base " keys ( HKLM , HKCU , . . . ) .
*/
2008-04-29 19:17:02 +04:00
static bool regdb_key_exists ( const char * key )
{
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
TDB_DATA value ;
2008-05-06 12:05:20 +04:00
bool ret = false ;
char * path , * p ;
if ( key = = NULL ) {
goto done ;
}
path = normalize_reg_path ( mem_ctx , key ) ;
if ( path = = NULL ) {
DEBUG ( 0 , ( " out of memory! (talloc failed) \n " ) ) ;
goto done ;
}
if ( * path = = ' \0 ' ) {
goto done ;
}
2008-04-29 19:17:02 +04:00
2008-05-06 12:05:20 +04:00
p = strrchr ( path , ' / ' ) ;
if ( p = = NULL ) {
/* this is a base key */
value = regdb_fetch_key_internal ( mem_ctx , path ) ;
ret = ( value . dptr ! = NULL ) ;
} else {
* p = ' \0 ' ;
2009-02-20 08:01:16 +03:00
ret = scan_parent_subkeys ( path , p + 1 ) ;
2008-05-06 12:05:20 +04:00
}
done :
2008-04-29 19:17:02 +04:00
TALLOC_FREE ( mem_ctx ) ;
return ret ;
}
2002-07-19 03:00:24 +04:00
/***********************************************************************
2007-11-27 04:24:56 +03:00
Retrieve an array of strings containing subkeys . Memory should be
released by the caller .
2002-07-19 03:00:24 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-02-24 17:19:18 +03:00
int regdb_fetch_keys ( const char * key , struct regsubkey_ctr * ctr )
2002-07-19 03:00:24 +04:00
{
2009-02-24 19:51:09 +03:00
WERROR werr ;
2002-07-19 03:00:24 +04:00
uint32 num_items ;
2007-03-29 13:35:51 +04:00
uint8 * buf ;
2002-07-19 03:00:24 +04:00
uint32 buflen , len ;
int i ;
2002-07-19 22:49:44 +04:00
fstring subkeyname ;
2007-12-14 00:20:58 +03:00
int ret = - 1 ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2008-04-01 14:38:54 +04:00
TDB_DATA value ;
2002-07-19 03:00:24 +04:00
2005-07-15 18:26:11 +04:00
DEBUG ( 11 , ( " regdb_fetch_keys: Enter key => [%s] \n " , key ? key : " NULL " ) ) ;
2007-11-27 04:24:56 +03:00
2008-05-07 15:42:48 +04:00
if ( ! regdb_key_exists ( key ) ) {
2008-07-08 19:10:01 +04:00
goto done ;
2008-05-07 15:42:48 +04:00
}
2009-02-25 01:19:08 +03:00
werr = regsubkey_ctr_set_seqnum ( ctr , regdb_get_seqnum ( ) ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
goto done ;
}
2008-04-01 14:48:08 +04:00
2008-05-06 19:09:57 +04:00
value = regdb_fetch_key_internal ( frame , key ) ;
2008-01-14 20:31:11 +03:00
2008-07-08 19:10:01 +04:00
if ( value . dptr = = NULL ) {
DEBUG ( 10 , ( " regdb_fetch_keys: no subkeys found for key [%s] \n " ,
key ) ) ;
ret = 0 ;
goto done ;
2002-07-19 03:00:24 +04:00
}
2007-11-27 04:24:56 +03:00
2008-07-08 19:10:01 +04:00
buf = value . dptr ;
buflen = value . dsize ;
2002-07-19 03:00:24 +04:00
len = tdb_unpack ( buf , buflen , " d " , & num_items ) ;
2007-11-27 04:24:56 +03:00
2002-07-19 03:00:24 +04:00
for ( i = 0 ; i < num_items ; i + + ) {
2007-11-27 04:24:56 +03:00
len + = tdb_unpack ( buf + len , buflen - len , " f " , subkeyname ) ;
2009-02-24 19:51:09 +03:00
werr = regsubkey_ctr_addkey ( ctr , subkeyname ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 5 , ( " regdb_fetch_keys: regsubkey_ctr_addkey "
" failed: %s \n " , win_errstr ( werr ) ) ) ;
2008-07-08 19:10:01 +04:00
goto done ;
2008-04-13 17:41:07 +04:00
}
2002-07-19 03:00:24 +04:00
}
2005-07-15 18:26:11 +04:00
DEBUG ( 11 , ( " regdb_fetch_keys: Exit [%d] items \n " , num_items ) ) ;
2007-11-27 04:24:56 +03:00
2007-12-14 00:20:58 +03:00
ret = num_items ;
2008-07-08 19:10:01 +04:00
done :
2007-12-14 00:20:58 +03:00
TALLOC_FREE ( frame ) ;
return ret ;
2002-07-19 03:00:24 +04:00
}
2005-06-25 21:31:40 +04:00
/****************************************************************************
Unpack a list of registry values frem the TDB
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-27 04:24:56 +03:00
2007-03-29 13:35:51 +04:00
static int regdb_unpack_values ( REGVAL_CTR * values , uint8 * buf , int buflen )
2005-06-25 21:31:40 +04:00
{
int len = 0 ;
uint32 type ;
2007-11-27 04:24:56 +03:00
fstring valuename ;
2005-06-29 20:35:32 +04:00
uint32 size ;
2005-06-25 21:31:40 +04:00
uint8 * data_p ;
uint32 num_values = 0 ;
int i ;
2007-11-27 04:24:56 +03:00
2005-06-25 21:31:40 +04:00
/* loop and unpack the rest of the registry values */
2007-11-27 04:24:56 +03:00
2005-06-25 21:31:40 +04:00
len + = tdb_unpack ( buf + len , buflen - len , " d " , & num_values ) ;
2007-11-27 04:24:56 +03:00
2005-06-25 21:31:40 +04:00
for ( i = 0 ; i < num_values ; i + + ) {
/* unpack the next regval */
2007-11-27 04:24:56 +03:00
2005-06-29 20:35:32 +04:00
type = REG_NONE ;
size = 0 ;
data_p = NULL ;
2007-11-27 04:24:56 +03:00
valuename [ 0 ] = ' \0 ' ;
2005-06-25 21:31:40 +04:00
len + = tdb_unpack ( buf + len , buflen - len , " fdB " ,
valuename ,
& type ,
& size ,
& data_p ) ;
2007-11-27 04:24:56 +03:00
2005-06-29 20:35:32 +04:00
/* add the new value. Paranoid protective code -- make sure data_p is valid */
2005-06-25 21:31:40 +04:00
2007-11-27 04:24:56 +03:00
if ( * valuename & & size & & data_p ) {
regval_ctr_addvalue ( values , valuename , type ,
( const char * ) data_p , size ) ;
2005-06-29 20:35:32 +04:00
}
2007-11-27 04:24:56 +03:00
SAFE_FREE ( data_p ) ; /* 'B' option to tdb_unpack does a malloc() */
2005-06-25 21:31:40 +04:00
DEBUG ( 8 , ( " specific: [%s], len: %d \n " , valuename , size ) ) ;
}
return len ;
}
/****************************************************************************
Pack all values in all printer keys
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-27 04:24:56 +03:00
2007-03-29 13:35:51 +04:00
static int regdb_pack_values ( REGVAL_CTR * values , uint8 * buf , int buflen )
2005-06-25 21:31:40 +04:00
{
int len = 0 ;
int i ;
REGISTRY_VALUE * val ;
2006-03-12 20:53:57 +03:00
int num_values ;
2005-06-25 21:31:40 +04:00
if ( ! values )
return 0 ;
2006-03-12 20:53:57 +03:00
num_values = regval_ctr_numvals ( values ) ;
2005-06-25 21:31:40 +04:00
/* pack the number of values first */
2007-11-27 04:24:56 +03:00
2005-06-25 21:31:40 +04:00
len + = tdb_pack ( buf + len , buflen - len , " d " , num_values ) ;
2007-11-27 04:24:56 +03:00
2005-06-25 21:31:40 +04:00
/* loop over all values */
2007-11-27 04:24:56 +03:00
for ( i = 0 ; i < num_values ; i + + ) {
2005-06-25 21:31:40 +04:00
val = regval_ctr_specific_value ( values , i ) ;
len + = tdb_pack ( buf + len , buflen - len , " fdB " ,
regval_name ( val ) ,
regval_type ( val ) ,
regval_size ( val ) ,
regval_data_p ( val ) ) ;
}
return len ;
}
2002-07-19 22:49:44 +04:00
2002-07-19 03:00:24 +04:00
/***********************************************************************
2007-11-27 04:24:56 +03:00
Retrieve an array of strings containing subkeys . Memory should be
2005-06-25 21:31:40 +04:00
released by the caller .
2002-07-19 03:00:24 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-30 06:59:29 +04:00
int regdb_fetch_values ( const char * key , REGVAL_CTR * values )
2002-07-19 03:00:24 +04:00
{
2007-11-27 04:24:56 +03:00
char * keystr = NULL ;
2008-03-17 01:03:34 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
int ret = 0 ;
2008-04-01 14:38:54 +04:00
TDB_DATA value ;
2005-05-09 17:51:44 +04:00
2005-06-30 06:59:29 +04:00
DEBUG ( 10 , ( " regdb_fetch_values: Looking for value of key [%s] \n " , key ) ) ;
2007-11-27 04:24:56 +03:00
2008-05-07 15:27:56 +04:00
if ( ! regdb_key_exists ( key ) ) {
goto done ;
}
2007-11-27 04:24:56 +03:00
keystr = talloc_asprintf ( ctx , " %s/%s " , REG_VALUE_PREFIX , key ) ;
if ( ! keystr ) {
2008-05-07 15:26:13 +04:00
goto done ;
2007-11-27 04:24:56 +03:00
}
2008-04-01 14:48:08 +04:00
values - > seqnum = regdb_get_seqnum ( ) ;
2008-05-06 19:09:57 +04:00
value = regdb_fetch_key_internal ( ctx , keystr ) ;
2008-01-14 20:31:11 +03:00
2008-04-01 14:38:54 +04:00
if ( ! value . dptr ) {
2005-06-27 07:40:03 +04:00
/* all keys have zero values by default */
2008-03-17 01:03:34 +03:00
goto done ;
2005-06-27 07:40:03 +04:00
}
2007-11-27 04:24:56 +03:00
2008-04-01 14:38:54 +04:00
regdb_unpack_values ( values , value . dptr , value . dsize ) ;
2008-03-17 01:03:34 +03:00
ret = regval_ctr_numvals ( values ) ;
2007-11-27 04:24:56 +03:00
2008-03-17 01:03:34 +03:00
done :
TALLOC_FREE ( ctx ) ;
return ret ;
2002-07-19 03:00:24 +04:00
}
2007-10-19 04:40:25 +04:00
bool regdb_store_values ( const char * key , REGVAL_CTR * values )
2002-07-19 03:00:24 +04:00
{
2007-10-06 00:42:14 +04:00
TDB_DATA old_data , data ;
2007-11-27 04:24:56 +03:00
char * keystr = NULL ;
2008-03-17 03:20:18 +03:00
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
2008-03-28 13:53:00 +03:00
int len ;
NTSTATUS status ;
2008-03-17 03:20:18 +03:00
bool result = false ;
2007-11-27 04:24:56 +03:00
2005-06-30 06:59:29 +04:00
DEBUG ( 10 , ( " regdb_store_values: Looking for value of key [%s] \n " , key ) ) ;
2007-11-27 04:24:56 +03:00
2008-05-07 15:45:02 +04:00
if ( ! regdb_key_exists ( key ) ) {
goto done ;
}
2007-11-27 04:24:56 +03:00
ZERO_STRUCT ( data ) ;
len = regdb_pack_values ( values , data . dptr , data . dsize ) ;
if ( len < = 0 ) {
2005-06-30 06:59:29 +04:00
DEBUG ( 0 , ( " regdb_store_values: unable to pack values. len <= 0 \n " ) ) ;
2008-03-17 03:20:18 +03:00
goto done ;
2005-06-25 21:31:40 +04:00
}
2007-11-27 04:24:56 +03:00
2008-03-17 03:26:35 +03:00
data . dptr = TALLOC_ARRAY ( ctx , uint8 , len ) ;
2005-06-25 21:31:40 +04:00
data . dsize = len ;
2007-11-27 04:24:56 +03:00
len = regdb_pack_values ( values , data . dptr , data . dsize ) ;
2005-06-25 21:31:40 +04:00
SMB_ASSERT ( len = = data . dsize ) ;
2007-11-27 04:24:56 +03:00
keystr = talloc_asprintf ( ctx , " %s/%s " , REG_VALUE_PREFIX , key ) ;
if ( ! keystr ) {
2008-03-17 03:20:18 +03:00
goto done ;
2007-11-27 04:24:56 +03:00
}
keystr = normalize_reg_path ( ctx , keystr ) ;
if ( ! keystr ) {
2008-03-17 03:20:18 +03:00
goto done ;
2007-11-27 04:24:56 +03:00
}
2008-03-17 01:07:15 +03:00
old_data = dbwrap_fetch_bystring ( regdb , ctx , keystr ) ;
2007-10-06 00:42:14 +04:00
if ( ( old_data . dptr ! = NULL )
& & ( old_data . dsize = = data . dsize )
2008-03-17 03:20:18 +03:00
& & ( memcmp ( old_data . dptr , data . dptr , data . dsize ) = = 0 ) )
{
result = true ;
goto done ;
2007-10-06 00:42:14 +04:00
}
2008-08-05 01:30:16 +04:00
status = dbwrap_trans_store_bystring ( regdb , keystr , data , TDB_REPLACE ) ;
2008-03-28 13:53:00 +03:00
result = NT_STATUS_IS_OK ( status ) ;
2007-11-27 04:24:56 +03:00
2008-03-17 03:20:18 +03:00
done :
TALLOC_FREE ( ctx ) ;
return result ;
2002-07-19 03:00:24 +04:00
}
2006-11-30 10:38:40 +03:00
static WERROR regdb_get_secdesc ( TALLOC_CTX * mem_ctx , const char * key ,
struct security_descriptor * * psecdesc )
{
char * tdbkey ;
TDB_DATA data ;
NTSTATUS status ;
2008-03-17 01:03:34 +03:00
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2008-03-17 03:39:16 +03:00
WERROR err = WERR_OK ;
2006-11-30 10:38:40 +03:00
DEBUG ( 10 , ( " regdb_get_secdesc: Getting secdesc of key [%s] \n " , key ) ) ;
2008-05-07 15:48:28 +04:00
if ( ! regdb_key_exists ( key ) ) {
err = WERR_BADFILE ;
goto done ;
}
2008-03-17 03:39:16 +03:00
tdbkey = talloc_asprintf ( tmp_ctx , " %s/%s " , REG_SECDESC_PREFIX , key ) ;
if ( tdbkey = = NULL ) {
err = WERR_NOMEM ;
goto done ;
2006-11-30 10:38:40 +03:00
}
normalize_dbkey ( tdbkey ) ;
2008-03-17 01:07:15 +03:00
data = dbwrap_fetch_bystring ( regdb , tmp_ctx , tdbkey ) ;
2006-11-30 10:38:40 +03:00
if ( data . dptr = = NULL ) {
2008-03-17 03:39:16 +03:00
err = WERR_BADFILE ;
goto done ;
2006-11-30 10:38:40 +03:00
}
status = unmarshall_sec_desc ( mem_ctx , ( uint8 * ) data . dptr , data . dsize ,
psecdesc ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NO_MEMORY ) ) {
2008-03-17 03:39:16 +03:00
err = WERR_NOMEM ;
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
err = WERR_REG_CORRUPT ;
2006-11-30 10:38:40 +03:00
}
2008-03-17 03:39:16 +03:00
done :
TALLOC_FREE ( tmp_ctx ) ;
return err ;
2006-11-30 10:38:40 +03:00
}
static WERROR regdb_set_secdesc ( const char * key ,
struct security_descriptor * secdesc )
{
2008-03-17 03:27:27 +03:00
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2006-11-30 10:38:40 +03:00
char * tdbkey ;
WERROR err = WERR_NOMEM ;
TDB_DATA tdbdata ;
2008-03-17 03:31:47 +03:00
2008-05-07 15:50:01 +04:00
if ( ! regdb_key_exists ( key ) ) {
err = WERR_BADFILE ;
goto done ;
}
2008-03-17 03:31:47 +03:00
tdbkey = talloc_asprintf ( mem_ctx , " %s/%s " , REG_SECDESC_PREFIX , key ) ;
if ( tdbkey = = NULL ) {
2006-11-30 10:38:40 +03:00
goto done ;
}
normalize_dbkey ( tdbkey ) ;
2007-11-06 02:50:47 +03:00
if ( secdesc = = NULL ) {
/* assuming a delete */
2009-02-26 03:22:03 +03:00
err = ntstatus_to_werror ( dbwrap_trans_delete_bystring ( regdb ,
tdbkey ) ) ;
2007-11-06 02:50:47 +03:00
goto done ;
}
2007-03-27 14:05:20 +04:00
err = ntstatus_to_werror ( marshall_sec_desc ( mem_ctx , secdesc ,
2007-06-13 14:07:05 +04:00
& tdbdata . dptr ,
2006-11-30 10:38:40 +03:00
& tdbdata . dsize ) ) ;
2009-02-26 03:22:03 +03:00
W_ERROR_NOT_OK_GOTO_DONE ( err ) ;
2006-11-30 10:38:40 +03:00
2009-02-26 03:22:03 +03:00
err = ntstatus_to_werror ( dbwrap_trans_store_bystring ( regdb , tdbkey ,
tdbdata , 0 ) ) ;
2006-11-30 10:38:40 +03:00
done :
TALLOC_FREE ( mem_ctx ) ;
return err ;
}
2002-07-19 22:49:44 +04:00
2009-02-24 17:19:18 +03:00
bool regdb_subkeys_need_update ( struct regsubkey_ctr * subkeys )
2008-01-14 20:31:11 +03:00
{
2009-02-25 01:19:35 +03:00
return ( regdb_get_seqnum ( ) ! = regsubkey_ctr_get_seqnum ( subkeys ) ) ;
2008-01-14 20:31:11 +03:00
}
bool regdb_values_need_update ( REGVAL_CTR * values )
{
return ( regdb_get_seqnum ( ) ! = values - > seqnum ) ;
}
2002-07-19 22:49:44 +04:00
/*
* Table of function pointers for default access
*/
REGISTRY_OPS regdb_ops = {
2008-03-17 03:44:26 +03:00
. fetch_subkeys = regdb_fetch_keys ,
. fetch_values = regdb_fetch_values ,
. store_subkeys = regdb_store_keys ,
. store_values = regdb_store_values ,
2009-02-26 00:04:07 +03:00
. create_subkey = regdb_create_subkey ,
2009-02-26 04:56:00 +03:00
. delete_subkey = regdb_delete_subkey ,
2008-03-17 03:44:26 +03:00
. get_secdesc = regdb_get_secdesc ,
. set_secdesc = regdb_set_secdesc ,
. subkeys_need_update = regdb_subkeys_need_update ,
. values_need_update = regdb_values_need_update
2002-07-19 22:49:44 +04:00
} ;