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
2009-07-07 19:16:21 +04:00
* Copyright ( C ) Michael Adam 2007 - 2009
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"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2009-10-02 02:17:06 +04:00
# include "registry.h"
# include "reg_db.h"
2010-05-25 02:04:13 +04:00
# include "reg_util_internal.h"
2010-05-25 00:42:00 +04:00
# include "reg_backend_db.h"
2010-05-25 03:00:37 +04:00
# include "reg_objects.h"
2010-07-31 02:47:20 +04:00
# include "nt_printing.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2010-08-18 20:59:23 +04:00
# include "dbwrap.h"
2002-07-19 03:00:24 +04:00
# 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
2009-07-03 19:39:17 +04:00
static bool regdb_key_exists ( struct db_context * db , const char * key ) ;
2008-05-08 02:34:35 +04:00
static bool regdb_key_is_base_key ( const char * key ) ;
2009-07-15 14:45:43 +04:00
static WERROR regdb_fetch_keys_internal ( struct db_context * db , const char * key ,
struct regsubkey_ctr * ctr ) ;
2009-07-07 13:31:28 +04:00
static bool regdb_store_keys_internal ( struct db_context * db , const char * key ,
struct regsubkey_ctr * ctr ) ;
2009-07-08 14:32:48 +04:00
static int regdb_fetch_values_internal ( struct db_context * db , const char * key ,
struct regval_ctr * values ) ;
2009-07-08 14:38:41 +04:00
static bool regdb_store_values_internal ( struct db_context * db , const char * key ,
struct regval_ctr * values ) ;
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 ,
2010-04-08 13:26:40 +04:00
KEY_PRINTING " \\ Forms " ,
KEY_PRINTING " \\ Printers " ,
2010-06-08 15:03:22 +04:00
KEY_PRINTING " \\ Environments \\ Windows NT x86 \\ Print Processors \\ winprint " ,
2005-06-30 23:43:53 +04:00
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 ,
2010-05-10 02:07:10 +04:00
" HKLM \\ Software \\ Microsoft \\ Windows NT \\ CurrentVersion \\ Winlogon \\ GPExtensions " ,
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 ,
2010-10-12 17:32:16 +04:00
" DisplayName " , REG_SZ , { " Event Log " } } ,
2005-08-05 18:34:25 +04:00
{ 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 .
*/
2009-07-08 01:03:46 +04:00
static WERROR init_registry_key_internal ( struct db_context * db ,
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
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , base , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) & &
! W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) )
{
goto fail ;
}
2008-03-20 15:59:09 +03:00
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
}
2009-07-08 01:03:46 +04:00
if ( ! regdb_store_keys_internal ( db , 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
2009-07-08 01:58:03 +04:00
struct init_registry_key_context {
const char * add_path ;
} ;
static NTSTATUS init_registry_key_action ( struct db_context * db ,
void * private_data )
{
struct init_registry_key_context * init_ctx =
( struct init_registry_key_context * ) private_data ;
return werror_to_ntstatus ( init_registry_key_internal (
db , init_ctx - > add_path ) ) ;
}
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
{
2009-07-08 01:58:03 +04:00
struct init_registry_key_context init_ctx ;
2008-04-13 15:38:44 +04:00
2009-07-03 19:39:17 +04:00
if ( regdb_key_exists ( regdb , add_path ) ) {
2008-04-29 19:18:26 +04:00
return WERR_OK ;
}
2009-07-08 01:58:03 +04:00
init_ctx . add_path = add_path ;
2008-03-20 16:01:13 +03:00
2009-07-08 01:58:03 +04:00
return ntstatus_to_werror ( dbwrap_trans_do ( regdb ,
init_registry_key_action ,
& init_ctx ) ) ;
2008-03-20 16:01:13 +03:00
}
2008-03-20 15:59:09 +03:00
/***********************************************************************
Open the registry data in the tdb
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-08 15:58:52 +04:00
static void regdb_ctr_add_value ( struct regval_ctr * ctr ,
struct builtin_regkey_value * value )
{
switch ( value - > type ) {
case REG_DWORD :
regval_ctr_addvalue ( ctr , value - > valuename , REG_DWORD ,
2010-05-25 00:19:17 +04:00
( uint8_t * ) & value - > data . dw_value ,
2009-07-08 15:58:52 +04:00
sizeof ( uint32 ) ) ;
break ;
case REG_SZ :
2009-09-24 17:01:32 +04:00
regval_ctr_addvalue_sz ( ctr , value - > valuename ,
value - > data . string ) ;
2009-07-08 15:58:52 +04:00
break ;
default :
DEBUG ( 0 , ( " regdb_ctr_add_value: invalid value type in "
" registry values [%d] \n " , value - > type ) ) ;
}
}
2009-07-08 15:10:37 +04:00
static NTSTATUS init_registry_data_action ( struct db_context * db ,
void * private_data )
2008-03-20 15:59:09 +03:00
{
2009-07-08 15:10:37 +04:00
NTSTATUS status ;
2008-04-29 19:37:35 +04:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2009-03-23 20:14:17 +03:00
struct regval_ctr * values ;
2008-03-20 15:59:09 +03:00
int i ;
/* loop over all of the predefined paths and add each component */
for ( i = 0 ; builtin_registry_paths [ i ] ! = NULL ; i + + ) {
2009-07-08 15:10:37 +04:00
if ( regdb_key_exists ( db , builtin_registry_paths [ i ] ) ) {
2008-04-29 19:41:03 +04:00
continue ;
}
2009-07-08 15:10:37 +04:00
status = werror_to_ntstatus ( init_registry_key_internal ( db ,
builtin_registry_paths [ i ] ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto done ;
2008-03-20 15:59:09 +03:00
}
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 + + ) {
2010-05-24 01:58:28 +04:00
WERROR werr ;
2007-12-14 00:20:58 +03:00
2010-05-24 01:58:28 +04:00
werr = regval_ctr_init ( frame , & values ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
status = werror_to_ntstatus ( werr ) ;
2009-07-08 15:10:37 +04:00
goto done ;
2005-08-29 18:55:40 +04:00
}
2009-07-08 15:10:37 +04:00
regdb_fetch_values_internal ( db ,
2009-07-08 14:32:48 +04:00
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 ) )
{
2009-07-08 15:58:52 +04:00
regdb_ctr_add_value ( values ,
& builtin_registry_values [ i ] ) ;
2009-07-08 15:10:37 +04:00
regdb_store_values_internal ( db ,
2009-07-08 14:38:41 +04:00
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
2009-07-08 15:10:37 +04:00
status = NT_STATUS_OK ;
done :
TALLOC_FREE ( frame ) ;
return status ;
}
WERROR init_registry_data ( void )
{
WERROR werr ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
struct regval_ctr * values ;
int i ;
/*
* 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 ( regdb , builtin_registry_paths [ i ] ) ) {
goto do_init ;
}
2007-02-07 16:26:13 +03:00
}
2009-07-08 15:10:37 +04:00
for ( i = 0 ; builtin_registry_values [ i ] . path ! = NULL ; i + + ) {
2010-05-24 01:58:28 +04:00
werr = regval_ctr_init ( frame , & values ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2007-12-14 00:20:58 +03:00
2009-07-08 15:10:37 +04:00
regdb_fetch_values_internal ( regdb ,
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 ) ;
2007-02-07 16:26:13 +03:00
}
2009-07-08 15:10:37 +04:00
werr = WERR_OK ;
goto done ;
do_init :
/*
* 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 .
*/
werr = ntstatus_to_werror ( dbwrap_trans_do ( regdb ,
init_registry_data_action ,
NULL ) ) ;
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
}
2010-06-24 17:26:04 +04:00
static int regdb_normalize_keynames_fn ( struct db_record * rec ,
void * private_data )
{
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
const char * keyname ;
NTSTATUS status ;
if ( rec - > key . dptr = = NULL | | rec - > key . dsize = = 0 ) {
return 0 ;
}
keyname = strchr ( ( const char * ) rec - > key . dptr , ' / ' ) ;
if ( keyname ) {
struct db_record new_rec ;
keyname = talloc_string_sub ( mem_ctx ,
( const char * ) rec - > key . dptr ,
" / " ,
" \\ " ) ;
DEBUG ( 2 , ( " regdb_normalize_keynames_fn: Convert %s to %s \n " ,
( const char * ) rec - > key . dptr ,
keyname ) ) ;
2010-10-28 17:41:30 +04:00
new_rec . value = rec - > value ;
new_rec . key = string_term_tdb_data ( keyname ) ;
2010-06-24 17:26:04 +04:00
new_rec . private_data = rec - > private_data ;
/* Delete the original record and store the normalized key */
status = rec - > delete_rec ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " regdb_normalize_keynames_fn: "
" tdb_delete for [%s] failed! \n " ,
rec - > key . dptr ) ) ;
return 1 ;
}
status = rec - > store ( & new_rec , new_rec . value , TDB_REPLACE ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " regdb_normalize_keynames_fn: "
" failed to store new record for [%s]! \n " ,
keyname ) ) ;
return 1 ;
}
}
return 0 ;
}
2010-06-25 20:11:35 +04:00
static WERROR regdb_store_regdb_version ( uint32_t version )
{
NTSTATUS status ;
const char * version_keyname = " INFO/version " ;
if ( ! regdb ) {
return WERR_CAN_NOT_COMPLETE ;
}
status = dbwrap_trans_store_int32 ( regdb , version_keyname , version ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-01-24 19:37:33 +03:00
DEBUG ( 1 , ( " regdb_store_regdb_version: error storing %s = %d: %s \n " ,
2010-06-25 20:11:35 +04:00
version_keyname , version , nt_errstr ( status ) ) ) ;
return ntstatus_to_werror ( status ) ;
} else {
2011-01-24 19:37:33 +03:00
DEBUG ( 10 , ( " regdb_store_regdb_version: stored %s = %d \n " ,
2010-06-25 20:11:35 +04:00
version_keyname , version ) ) ;
return WERR_OK ;
}
}
2010-06-25 20:04:52 +04:00
static WERROR regdb_upgrade_v1_to_v2 ( void )
2010-06-24 17:26:04 +04:00
{
TALLOC_CTX * mem_ctx ;
int rc ;
2010-06-25 20:12:28 +04:00
WERROR werr ;
2010-06-24 17:26:04 +04:00
mem_ctx = talloc_stackframe ( ) ;
if ( mem_ctx = = NULL ) {
return WERR_NOMEM ;
}
rc = regdb - > traverse ( regdb , regdb_normalize_keynames_fn , mem_ctx ) ;
talloc_destroy ( mem_ctx ) ;
2010-06-25 20:12:28 +04:00
if ( rc = = - 1 ) {
return WERR_REG_IO_FAILURE ;
}
werr = regdb_store_regdb_version ( REGVER_V2 ) ;
return werr ;
2010-06-24 17:26:04 +04:00
}
2002-07-19 03:00:24 +04:00
/***********************************************************************
Open the registry database
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-06-24 17:26:04 +04:00
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 " ;
2010-06-25 16:34:04 +04:00
uint32 vers_id , expected_version ;
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 ) {
2010-10-22 14:16:20 +04:00
DEBUG ( 10 , ( " regdb_init: incrementing refcount (%d->%d) \n " ,
regdb_refcount , regdb_refcount + 1 ) ) ;
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
}
2010-10-12 17:32:16 +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 ;
2010-10-22 14:16:20 +04:00
DEBUG ( 10 , ( " regdb_init: registry db openend. refcount reset (%d) \n " ,
regdb_refcount ) ) ;
2005-05-23 20:25:31 +04:00
2010-06-25 16:34:04 +04:00
expected_version = REGVER_V2 ;
2008-03-17 01:07:15 +03:00
vers_id = dbwrap_fetch_int32 ( regdb , vstring ) ;
2010-06-24 17:26:04 +04:00
if ( vers_id = = - 1 ) {
2010-06-25 16:34:04 +04:00
DEBUG ( 10 , ( " regdb_init: registry version uninitialized "
" (got %d), initializing to version %d \n " ,
vers_id , expected_version ) ) ;
2010-06-25 20:13:06 +04:00
werr = regdb_store_regdb_version ( expected_version ) ;
return werr ;
2010-06-24 17:26:04 +04:00
}
2010-06-25 16:34:04 +04:00
if ( vers_id > expected_version | | vers_id = = 0 ) {
DEBUG ( 1 , ( " regdb_init: unknown registry version %d "
" (code version = %d), refusing initialization \n " ,
vers_id , expected_version ) ) ;
return WERR_CAN_NOT_COMPLETE ;
}
if ( vers_id = = REGVER_V1 ) {
DEBUG ( 10 , ( " regdb_init: got registry db version %d, upgrading "
" to version %d \n " , REGVER_V1 , REGVER_V2 ) ) ;
2010-06-24 17:26:04 +04:00
2010-06-25 16:34:04 +04:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
return WERR_REG_IO_FAILURE ;
}
2010-06-24 17:26:04 +04:00
2010-06-25 20:04:52 +04:00
werr = regdb_upgrade_v1_to_v2 ( ) ;
2010-06-25 16:34:04 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
regdb - > transaction_cancel ( regdb ) ;
return werr ;
}
2010-06-24 17:26:04 +04:00
2010-06-25 16:34:04 +04:00
if ( regdb - > transaction_commit ( regdb ) ! = 0 ) {
return WERR_REG_IO_FAILURE ;
2010-06-24 17:26:04 +04:00
}
2010-06-25 16:34:04 +04:00
vers_id = REGVER_V2 ;
2005-09-01 18:00:53 +04:00
}
2005-06-17 19:53:01 +04:00
2010-06-25 16:34:04 +04:00
/* future upgrade code should go here */
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 ) {
2010-10-22 14:16:20 +04:00
DEBUG ( 10 , ( " regdb_open: incrementing refcount (%d->%d) \n " ,
regdb_refcount , regdb_refcount + 1 ) ) ;
2008-03-17 01:08:33 +03:00
regdb_refcount + + ;
2005-10-07 16:14:25 +04:00
return WERR_OK ;
}
2010-10-12 17:32:16 +04:00
2005-10-07 16:14:25 +04:00
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 ) ) ;
2010-10-12 17:32:16 +04:00
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 ;
2010-10-22 14:16:20 +04:00
DEBUG ( 10 , ( " regdb_open: registry db opened. 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
2010-10-22 14:16:20 +04:00
DEBUG ( 10 , ( " regdb_close: decrementing refcount (%d->%d) \n " ,
regdb_refcount + 1 , 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
2009-07-03 18:40:43 +04:00
static WERROR regdb_delete_key_with_prefix ( struct db_context * db ,
const char * keyname ,
2009-02-26 03:16:07 +03:00
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 {
2010-06-24 18:33:37 +04:00
path = talloc_asprintf ( mem_ctx , " %s \\ %s " , prefix , keyname ) ;
2009-02-26 03:16:07 +03:00
if ( path = = NULL ) {
goto done ;
}
}
path = normalize_reg_path ( mem_ctx , path ) ;
if ( path = = NULL ) {
goto done ;
}
2009-07-03 18:40:43 +04:00
werr = ntstatus_to_werror ( dbwrap_delete_bystring ( db , path ) ) ;
2009-02-26 03:16:07 +03:00
/* treat "not" found" as ok */
if ( W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) ) {
werr = WERR_OK ;
}
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
2009-07-03 18:42:20 +04:00
static WERROR regdb_delete_values ( struct db_context * db , const char * keyname )
2009-02-26 03:16:07 +03:00
{
2009-07-03 18:42:20 +04:00
return regdb_delete_key_with_prefix ( db , keyname , REG_VALUE_PREFIX ) ;
2009-02-26 03:16:07 +03:00
}
2009-07-03 18:44:20 +04:00
static WERROR regdb_delete_secdesc ( struct db_context * db , const char * keyname )
2009-02-26 03:16:07 +03:00
{
2009-07-03 18:44:20 +04:00
return regdb_delete_key_with_prefix ( db , keyname , REG_SECDESC_PREFIX ) ;
2009-02-26 03:16:07 +03:00
}
2009-07-03 18:48:36 +04:00
static WERROR regdb_delete_subkeylist ( struct db_context * db , const char * keyname )
2009-02-26 03:16:07 +03:00
{
2009-07-03 18:48:36 +04:00
return regdb_delete_key_with_prefix ( db , keyname , NULL ) ;
2009-02-26 03:16:07 +03:00
}
2009-07-03 18:51:26 +04:00
static WERROR regdb_delete_key_lists ( struct db_context * db , const char * keyname )
2009-02-26 03:43:58 +03:00
{
WERROR werr ;
2009-07-03 18:51:26 +04:00
werr = regdb_delete_values ( db , keyname ) ;
2009-02-26 03:43:58 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2010-06-24 18:33:37 +04:00
DEBUG ( 1 , ( __location__ " Deleting %s \\ %s failed: %s \n " ,
2009-02-26 03:43:58 +03:00
REG_VALUE_PREFIX , keyname , win_errstr ( werr ) ) ) ;
goto done ;
}
2009-07-03 18:51:26 +04:00
werr = regdb_delete_secdesc ( db , keyname ) ;
2009-02-26 03:43:58 +03:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2010-06-24 18:33:37 +04:00
DEBUG ( 1 , ( __location__ " Deleting %s \\ %s failed: %s \n " ,
2009-02-26 03:43:58 +03:00
REG_SECDESC_PREFIX , keyname , win_errstr ( werr ) ) ) ;
goto done ;
}
2009-07-03 18:51:26 +04:00
werr = regdb_delete_subkeylist ( db , keyname ) ;
2009-02-26 03:43:58 +03:00
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-07-08 19:26:06 +04:00
static WERROR regdb_store_keys_internal2 ( struct db_context * db ,
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 ;
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 ( ) ;
2009-07-08 19:26:06 +04:00
WERROR werr ;
2005-05-23 20:25:31 +04:00
2007-11-27 04:24:56 +03:00
if ( ! key ) {
2009-07-09 02:21:46 +04:00
werr = WERR_INVALID_PARAM ;
goto done ;
2007-11-27 04:24:56 +03:00
}
keyname = talloc_strdup ( ctx , key ) ;
if ( ! keyname ) {
2009-07-09 02:21:46 +04:00
werr = WERR_NOMEM ;
goto done ;
2007-11-27 04:24:56 +03:00
}
2009-07-09 02:21:46 +04:00
2007-11-27 04:24:56 +03:00
keyname = normalize_reg_path ( ctx , keyname ) ;
2009-07-09 02:21:46 +04:00
if ( ! keyname ) {
werr = WERR_NOMEM ;
goto done ;
}
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 ) {
2009-07-08 19:26:06 +04:00
werr = WERR_NOMEM ;
goto done ;
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-07-08 19:26:06 +04:00
werr = WERR_NOMEM ;
2009-02-19 16:16:44 +03:00
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 " ) ) ;
2009-07-08 19:26:06 +04:00
werr = WERR_CAN_NOT_COMPLETE ;
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 ;
2009-07-08 19:26:06 +04:00
werr = ntstatus_to_werror ( dbwrap_store_bystring ( db , keyname , dbuf ,
TDB_REPLACE ) ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2002-07-19 03:00:24 +04:00
2009-02-20 08:01:16 +03:00
/*
* Delete a sorted subkey cache for regdb_key_exists , will be
* recreated automatically
*/
2010-06-24 18:33:37 +04:00
keyname = talloc_asprintf ( ctx , " %s \\ %s " , REG_SORTED_SUBKEYS_PREFIX ,
2009-02-20 08:01:16 +03:00
keyname ) ;
2009-07-08 19:26:06 +04:00
if ( keyname = = NULL ) {
werr = WERR_NOMEM ;
goto done ;
}
werr = ntstatus_to_werror ( dbwrap_delete_bystring ( db , keyname ) ) ;
/* don't treat WERR_NOT_FOUND as an error here */
if ( W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) ) {
werr = WERR_OK ;
2009-02-20 08:01:16 +03:00
}
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 ) ;
2009-07-08 19:26:06 +04:00
return werr ;
2002-07-19 03:00:24 +04:00
}
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-07-09 12:28:29 +04:00
struct regdb_store_keys_context {
const char * key ;
struct regsubkey_ctr * ctr ;
} ;
static NTSTATUS regdb_store_keys_action ( struct db_context * db ,
void * private_data )
2005-06-17 19:35:31 +04:00
{
2009-07-09 12:28:29 +04:00
struct regdb_store_keys_context * store_ctx ;
WERROR werr ;
int 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 ;
2009-07-09 12:28:29 +04:00
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2008-03-17 02:43:56 +03:00
2009-07-09 12:28:29 +04:00
store_ctx = ( struct regdb_store_keys_context * ) private_data ;
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-07-09 12:28:29 +04:00
werr = regsubkey_ctr_init ( mem_ctx , & old_subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2005-08-29 18:55:40 +04:00
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , store_ctx - > key , old_subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) & &
! W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) )
{
goto done ;
}
2007-11-27 04:24:56 +03:00
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 ) ;
2009-07-09 12:28:29 +04:00
if ( regsubkey_ctr_key_exists ( store_ctx - > ctr , oldkeyname ) ) {
2006-11-22 19:53:28 +03:00
/*
* It ' s still around , don ' t delete
*/
continue ;
}
2010-06-24 18:33:37 +04:00
path = talloc_asprintf ( mem_ctx , " %s \\ %s " , store_ctx - > key ,
2009-07-09 12:28:29 +04:00
oldkeyname ) ;
2007-11-27 04:24:56 +03:00
if ( ! path ) {
2009-07-09 12:28:29 +04:00
werr = WERR_NOMEM ;
goto done ;
2007-11-27 04:24:56 +03:00
}
2009-02-26 03:16:07 +03:00
2009-07-07 13:31:28 +04:00
werr = regdb_delete_key_lists ( db , path ) ;
2009-07-09 12:28:29 +04:00
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
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 */
2009-07-09 12:28:29 +04:00
werr = regdb_store_keys_internal2 ( db , store_ctx - > key , store_ctx - > ctr ) ;
2009-07-08 19:26:06 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-05-08 16:33:02 +04:00
DEBUG ( 0 , ( " regdb_store_keys: Failed to store new subkey list "
2009-07-09 12:28:29 +04:00
" for parent [%s]: %s \n " , store_ctx - > key ,
win_errstr ( werr ) ) ) ;
goto done ;
2008-05-08 16:33:02 +04:00
}
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
2009-07-09 12:28:29 +04:00
num_subkeys = regsubkey_ctr_numkeys ( store_ctx - > ctr ) ;
2008-03-01 02:32:36 +03:00
if ( num_subkeys = = 0 ) {
2009-07-09 12:28:29 +04:00
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2008-03-01 02:32:36 +03:00
2009-07-09 12:28:29 +04:00
werr = regdb_store_keys_internal2 ( db , store_ctx - > key , subkeys ) ;
2009-07-08 19:26:06 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
2008-03-01 02:32:36 +03:00
DEBUG ( 0 , ( " regdb_store_keys: Failed to store "
2009-07-09 12:28:29 +04:00
" new record for key [%s]: %s \n " ,
store_ctx - > key , win_errstr ( werr ) ) ) ;
goto done ;
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 + + ) {
2010-06-24 18:33:37 +04:00
path = talloc_asprintf ( mem_ctx , " %s \\ %s " , store_ctx - > key ,
2009-07-09 12:28:29 +04:00
regsubkey_ctr_specific_key ( store_ctx - > ctr , i ) ) ;
2007-11-27 04:24:56 +03:00
if ( ! path ) {
2009-07-09 12:28:29 +04:00
werr = WERR_NOMEM ;
goto done ;
2005-08-29 18:55:40 +04:00
}
2009-07-09 12:28:29 +04:00
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2005-08-29 18:55:40 +04:00
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , path , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2005-06-17 19:35:31 +04:00
/* create a record with 0 subkeys */
2009-07-08 19:26:06 +04:00
werr = regdb_store_keys_internal2 ( db , path , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
2006-11-22 18:10:46 +03:00
DEBUG ( 0 , ( " regdb_store_keys: Failed to store "
2009-07-08 19:26:06 +04:00
" new record for key [%s]: %s \n " , path ,
win_errstr ( werr ) ) ) ;
2009-07-09 12:28:29 +04:00
goto done ;
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
2009-07-09 12:28:29 +04:00
werr = WERR_OK ;
done :
talloc_free ( mem_ctx ) ;
return werror_to_ntstatus ( werr ) ;
}
static bool regdb_store_keys_internal ( struct db_context * db , const char * key ,
struct regsubkey_ctr * ctr )
{
int num_subkeys , old_num_subkeys , i ;
struct regsubkey_ctr * old_subkeys = NULL ;
TALLOC_CTX * ctx = talloc_stackframe ( ) ;
WERROR werr ;
bool ret = false ;
struct regdb_store_keys_context store_ctx ;
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( db , key ) ) {
2009-07-09 02:10:08 +04:00
goto done ;
2006-11-22 19:53:28 +03:00
}
2009-07-09 12:28:29 +04:00
/*
* fetch a list of the old subkeys so we can determine if anything has
* changed
*/
2006-11-22 19:53:28 +03:00
2009-07-09 12:28:29 +04:00
werr = regsubkey_ctr_init ( ctx , & old_subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( " regdb_store_keys: talloc() failure! \n " ) ) ;
goto done ;
}
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , key , old_subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) & &
! W_ERROR_EQUAL ( werr , WERR_NOT_FOUND ) )
{
goto done ;
}
2009-07-09 12:28:29 +04: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 ) ) {
for ( i = 0 ; i < num_subkeys ; i + + ) {
if ( strcmp ( regsubkey_ctr_specific_key ( ctr , i ) ,
regsubkey_ctr_specific_key ( old_subkeys , i ) )
! = 0 )
{
break ;
}
}
if ( i = = num_subkeys ) {
/*
* Nothing changed , no point to even start a tdb
* transaction
*/
ret = true ;
goto done ;
}
2006-11-22 19:53:28 +03:00
}
2009-07-09 12:28:29 +04:00
TALLOC_FREE ( old_subkeys ) ;
store_ctx . key = key ;
store_ctx . ctr = ctr ;
werr = ntstatus_to_werror ( dbwrap_trans_do ( db ,
regdb_store_keys_action ,
& store_ctx ) ) ;
ret = W_ERROR_IS_OK ( werr ) ;
2009-07-09 02:10:08 +04:00
done :
2008-03-17 03:00:40 +03:00
TALLOC_FREE ( ctx ) ;
2009-07-09 02:10:08 +04:00
return ret ;
2005-06-17 19:35:31 +04:00
}
2009-07-07 13:31:28 +04:00
bool regdb_store_keys ( const char * key , struct regsubkey_ctr * ctr )
{
return regdb_store_keys_internal ( regdb , key , ctr ) ;
}
2009-07-09 12:52:40 +04:00
/**
* create a subkey of a given key
*/
2009-07-09 12:41:59 +04:00
struct regdb_create_subkey_context {
const char * key ;
const char * subkey ;
} ;
static NTSTATUS regdb_create_subkey_action ( struct db_context * db ,
void * private_data )
2009-02-26 00:04:07 +03:00
{
WERROR werr ;
2009-07-09 12:41:59 +04:00
struct regdb_create_subkey_context * create_ctx ;
2009-02-26 00:04:07 +03:00
struct regsubkey_ctr * subkeys ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2009-07-09 12:41:59 +04:00
create_ctx = ( struct regdb_create_subkey_context * ) private_data ;
2009-02-26 00:04:07 +03:00
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , create_ctx - > key , subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-02-26 00:04:07 +03:00
2009-07-09 12:41:59 +04:00
werr = regsubkey_ctr_addkey ( subkeys , create_ctx - > subkey ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regdb_store_keys_internal2 ( db , create_ctx - > key , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " failed to store new subkey list for "
" parent key %s: %s \n " , create_ctx - > key ,
win_errstr ( werr ) ) ) ;
2009-02-26 00:04:07 +03:00
}
2009-07-09 12:41:59 +04:00
done :
talloc_free ( mem_ctx ) ;
return werror_to_ntstatus ( werr ) ;
}
2009-02-26 00:04:07 +03:00
2009-07-09 12:41:59 +04:00
static WERROR regdb_create_subkey ( const char * key , const char * subkey )
{
WERROR werr ;
struct regsubkey_ctr * subkeys ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
struct regdb_create_subkey_context create_ctx ;
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( regdb , key ) ) {
werr = WERR_NOT_FOUND ;
2009-07-07 13:41:08 +04:00
goto done ;
}
2009-02-26 00:04:07 +03:00
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
2009-07-09 12:41:59 +04:00
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-02-26 00:04:07 +03:00
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( regdb , key , subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-02-26 00:04:07 +03:00
2009-07-09 12:41:59 +04:00
if ( regsubkey_ctr_key_exists ( subkeys , subkey ) ) {
werr = WERR_OK ;
goto done ;
2009-02-26 00:04:07 +03:00
}
2009-07-09 12:41:59 +04:00
talloc_free ( subkeys ) ;
2009-02-26 00:04:07 +03:00
2009-07-09 12:41:59 +04:00
create_ctx . key = key ;
create_ctx . subkey = subkey ;
2009-02-26 00:04:07 +03:00
2009-07-09 12:41:59 +04:00
werr = ntstatus_to_werror ( dbwrap_trans_do ( regdb ,
regdb_create_subkey_action ,
& create_ctx ) ) ;
2009-02-26 00:04:07 +03:00
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
2005-06-17 19:35:31 +04:00
2009-07-09 12:54:18 +04:00
/**
* create a subkey of a given key
*/
2009-07-09 13:04:20 +04:00
struct regdb_delete_subkey_context {
const char * key ;
const char * subkey ;
const char * path ;
} ;
static NTSTATUS regdb_delete_subkey_action ( struct db_context * db ,
void * private_data )
2009-02-26 04:56:00 +03:00
{
2009-07-07 14:27:26 +04:00
WERROR werr ;
2009-07-09 13:04:20 +04:00
struct regdb_delete_subkey_context * delete_ctx ;
2009-02-26 04:56:00 +03:00
struct regsubkey_ctr * subkeys ;
2009-07-09 13:04:20 +04:00
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
delete_ctx = ( struct regdb_delete_subkey_context * ) private_data ;
werr = regdb_delete_key_lists ( db , delete_ctx - > path ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regsubkey_ctr_init ( mem_ctx , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-07-15 14:45:43 +04:00
werr = regdb_fetch_keys_internal ( db , delete_ctx - > key , subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2009-07-09 13:04:20 +04:00
werr = regsubkey_ctr_delkey ( subkeys , delete_ctx - > subkey ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regdb_store_keys_internal2 ( db , delete_ctx - > key , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( __location__ " failed to store new subkey_list for "
" parent key %s: %s \n " , delete_ctx - > key ,
win_errstr ( werr ) ) ) ;
}
done :
talloc_free ( mem_ctx ) ;
return werror_to_ntstatus ( werr ) ;
}
static WERROR regdb_delete_subkey ( const char * key , const char * subkey )
{
WERROR werr ;
2009-02-26 04:56:00 +03:00
char * path ;
2009-07-09 13:04:20 +04:00
struct regdb_delete_subkey_context delete_ctx ;
2009-02-26 04:56:00 +03:00
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2009-07-03 19:39:17 +04:00
if ( ! regdb_key_is_base_key ( key ) & & ! regdb_key_exists ( regdb , key ) ) {
2009-02-26 04:56:00 +03:00
werr = WERR_NOT_FOUND ;
goto done ;
}
2010-06-24 18:33:37 +04:00
path = talloc_asprintf ( mem_ctx , " %s \\ %s " , key , subkey ) ;
2009-02-26 04:56:00 +03:00
if ( path = = NULL ) {
werr = WERR_NOMEM ;
goto done ;
}
2009-07-03 19:39:17 +04:00
if ( ! regdb_key_exists ( regdb , path ) ) {
2009-02-26 04:56:00 +03:00
werr = WERR_OK ;
goto done ;
}
2009-07-09 13:04:20 +04:00
delete_ctx . key = key ;
delete_ctx . subkey = subkey ;
delete_ctx . path = path ;
2009-02-26 04:56:00 +03:00
2009-07-09 13:04:20 +04:00
werr = ntstatus_to_werror ( dbwrap_trans_do ( regdb ,
regdb_delete_subkey_action ,
& delete_ctx ) ) ;
2009-02-26 04:56:00 +03:00
done :
talloc_free ( mem_ctx ) ;
return werr ;
}
2009-07-03 19:10:09 +04:00
static TDB_DATA regdb_fetch_key_internal ( struct db_context * db ,
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 ) ;
}
2009-07-03 19:10:09 +04:00
data = dbwrap_fetch_bystring ( db , mem_ctx , path ) ;
2008-05-06 19:15:50 +04:00
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 ,
2010-06-24 18:33:37 +04:00
* i . e one without a subkey separator ( ' \ ' ) .
2008-05-08 02:34:35 +04:00
*/
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 ;
}
2010-06-24 18:33:37 +04:00
ret = ( strrchr ( path , ' \\ ' ) = = NULL ) ;
2008-05-08 02:34:35 +04:00
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 .
*
2009-07-07 13:11:10 +04:00
* The sorted subkey record is deleted in regdb_store_keys_internal2 and
2009-02-22 03:11:51 +03:00
* recreated on demand .
*/
2010-02-14 02:02:19 +03:00
static int cmp_keynames ( char * * p1 , char * * p2 )
2009-02-20 08:01:16 +03:00
{
2010-02-14 02:02:19 +03:00
return StrCaseCmp ( * p1 , * p2 ) ;
2009-02-20 08:01:16 +03:00
}
2009-07-13 19:15:14 +04:00
struct create_sorted_subkeys_context {
const char * key ;
const char * sorted_keyname ;
} ;
static NTSTATUS create_sorted_subkeys_action ( struct db_context * db ,
void * private_data )
2009-02-20 08:01:16 +03:00
{
char * * sorted_subkeys ;
2009-02-24 17:19:18 +03:00
struct regsubkey_ctr * ctr ;
2009-02-20 08:01:16 +03:00
NTSTATUS status ;
char * buf ;
char * p ;
2009-07-15 14:45:43 +04:00
int i ;
2009-02-20 08:01:16 +03:00
size_t len ;
2009-02-24 19:42:50 +03:00
int num_subkeys ;
2009-07-13 19:15:14 +04:00
struct create_sorted_subkeys_context * sorted_ctx ;
2009-02-20 08:01:16 +03:00
2009-07-13 19:15:14 +04:00
sorted_ctx = ( struct create_sorted_subkeys_context * ) private_data ;
2009-02-22 12:11:29 +03:00
2009-07-13 19:15:14 +04:00
/*
* In this function , we only treat failing of the actual write to
* the db as a real error . All preliminary errors , at a stage when
* nothing has been written to the DB yet are treated as success
* to be committed ( as an empty transaction ) .
*
* The reason is that 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 .
*/
status = werror_to_ntstatus ( regsubkey_ctr_init ( talloc_tos ( ) , & ctr ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* don't treat this as an error */
status = NT_STATUS_OK ;
goto done ;
2009-02-20 08:01:16 +03:00
}
2009-07-15 14:45:43 +04:00
status = werror_to_ntstatus ( regdb_fetch_keys_internal ( db ,
sorted_ctx - > key ,
ctr ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-07-13 19:15:14 +04:00
/* don't treat this as an error */
2009-07-15 14:45:43 +04:00
status = NT_STATUS_OK ;
2009-07-13 19:15:14 +04:00
goto done ;
2009-02-20 08:01:16 +03:00
}
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 ) {
2009-07-13 19:15:14 +04:00
/* don't treat this as an error */
goto done ;
2009-02-20 08:01:16 +03:00
}
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 ) {
2009-07-13 19:15:14 +04:00
/* don't treat this as an error */
goto done ;
2009-02-20 08:01:16 +03:00
}
len + = strlen ( sorted_subkeys [ i ] ) + 1 ;
}
2010-02-14 02:02:19 +03:00
TYPESAFE_QSORT ( sorted_subkeys , num_subkeys , cmp_keynames ) ;
2009-02-20 08:01:16 +03:00
buf = talloc_array ( ctr , char , len ) ;
if ( buf = = NULL ) {
2009-07-13 19:15:14 +04:00
/* don't treat this as an error */
goto done ;
2009-02-20 08:01:16 +03:00
}
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-07-13 19:15:14 +04:00
db , sorted_ctx - > sorted_keyname , make_tdb_data ( ( uint8_t * ) buf ,
len ) ,
2009-02-20 08:01:16 +03:00
TDB_REPLACE ) ;
2009-07-13 19:15:14 +04:00
done :
talloc_free ( ctr ) ;
return status ;
}
2009-07-09 14:54:16 +04:00
2011-05-11 16:49:10 +04:00
static bool create_sorted_subkeys_internal ( const char * key ,
const char * sorted_keyname )
2009-07-13 19:15:14 +04:00
{
NTSTATUS status ;
struct create_sorted_subkeys_context sorted_ctx ;
2009-07-09 14:54:16 +04:00
2009-07-13 19:15:14 +04:00
sorted_ctx . key = key ;
sorted_ctx . sorted_keyname = sorted_keyname ;
2009-02-22 12:11:29 +03:00
2009-07-13 19:15:14 +04:00
status = dbwrap_trans_do ( regdb ,
create_sorted_subkeys_action ,
& sorted_ctx ) ;
return NT_STATUS_IS_OK ( status ) ;
2009-02-20 08:01:16 +03:00
}
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 ;
}
2009-07-03 19:18:19 +04:00
static bool scan_parent_subkeys ( struct db_context * db , const char * parent ,
const char * name )
2009-02-20 08:01:16 +03:00
{
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 ;
}
2010-06-24 18:33:37 +04:00
key = talloc_asprintf ( talloc_tos ( ) , " %s \\ %s " ,
2009-02-20 08:01:16 +03:00
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 ;
2009-07-03 19:18:19 +04:00
res = db - > parse_record ( db , string_term_tdb_data ( key ) ,
parent_subkey_scanner , & state ) ;
2009-02-20 08:01:16 +03:00
if ( state . scanned ) {
result = state . found ;
} else {
2010-02-08 13:01:47 +03:00
res = db - > transaction_start ( db ) ;
if ( res ! = 0 ) {
2011-05-11 16:17:21 +04:00
DEBUG ( 0 , ( " error starting transaction \n " ) ) ;
2010-02-08 13:01:47 +03:00
goto fail ;
}
2011-05-11 16:49:10 +04:00
if ( ! create_sorted_subkeys_internal ( path , key ) ) {
2010-02-08 13:01:47 +03:00
res = db - > transaction_cancel ( db ) ;
if ( res ! = 0 ) {
smb_panic ( " Failed to cancel transaction. " ) ;
}
2009-02-20 08:01:16 +03:00
goto fail ;
}
2010-02-08 13:01:47 +03:00
2009-07-03 19:18:19 +04:00
res = db - > parse_record ( db , string_term_tdb_data ( key ) ,
parent_subkey_scanner , & state ) ;
2009-02-20 08:01:16 +03:00
if ( ( res = = 0 ) & & ( state . scanned ) ) {
result = state . found ;
}
2010-02-08 13:01:47 +03:00
res = db - > transaction_commit ( db ) ;
if ( res ! = 0 ) {
DEBUG ( 0 , ( " error committing transaction \n " ) ) ;
result = false ;
}
2009-02-20 08:01:16 +03:00
}
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 , . . . ) .
*/
2009-07-03 19:39:17 +04:00
static bool regdb_key_exists ( struct db_context * db , const char * key )
2008-04-29 19:17:02 +04:00
{
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
2010-06-24 18:33:37 +04:00
p = strrchr ( path , ' \\ ' ) ;
2008-05-06 12:05:20 +04:00
if ( p = = NULL ) {
/* this is a base key */
2009-07-03 19:39:17 +04:00
value = regdb_fetch_key_internal ( db , mem_ctx , path ) ;
2008-05-06 12:05:20 +04:00
ret = ( value . dptr ! = NULL ) ;
} else {
* p = ' \0 ' ;
2009-07-03 19:39:17 +04:00
ret = scan_parent_subkeys ( db , 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-07-15 14:45:43 +04:00
static WERROR regdb_fetch_keys_internal ( struct db_context * db , 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 ;
2009-07-15 14:45:43 +04:00
uint32_t 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
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
2009-07-03 19:39:17 +04:00
if ( ! regdb_key_exists ( db , key ) ) {
2009-07-15 14:45:43 +04:00
DEBUG ( 10 , ( " key [%s] not found \n " , key ) ) ;
werr = WERR_NOT_FOUND ;
2008-07-08 19:10:01 +04:00
goto done ;
2008-05-07 15:42:48 +04:00
}
2009-07-03 19:39:17 +04:00
werr = regsubkey_ctr_set_seqnum ( ctr , db - > get_seqnum ( db ) ) ;
2009-07-15 14:45:43 +04:00
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2008-04-01 14:48:08 +04:00
2009-07-03 19:39:17 +04:00
value = regdb_fetch_key_internal ( db , frame , key ) ;
2008-01-14 20:31:11 +03:00
2009-11-03 02:51:27 +03:00
if ( value . dsize = = 0 | | value . dptr = = NULL ) {
2008-07-08 19:10:01 +04:00
DEBUG ( 10 , ( " regdb_fetch_keys: no subkeys found for key [%s] \n " ,
key ) ) ;
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 ) ;
2009-11-03 02:47:37 +03:00
if ( len = = ( uint32_t ) - 1 ) {
werr = WERR_NOT_FOUND ;
goto done ;
}
2007-11-27 04:24:56 +03:00
2009-07-15 14:50:55 +04:00
werr = regsubkey_ctr_reinit ( ctr ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
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 ) ) ) ;
2009-07-15 14:45:43 +04:00
num_items = 0 ;
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
2008-07-08 19:10:01 +04:00
done :
2007-12-14 00:20:58 +03:00
TALLOC_FREE ( frame ) ;
2009-07-15 14:45:43 +04:00
return werr ;
2002-07-19 03:00:24 +04:00
}
2009-07-03 19:39:17 +04:00
int regdb_fetch_keys ( const char * key , struct regsubkey_ctr * ctr )
{
2009-07-15 14:45:43 +04:00
WERROR werr ;
werr = regdb_fetch_keys_internal ( regdb , key , ctr ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
return - 1 ;
}
return regsubkey_ctr_numkeys ( ctr ) ;
2009-07-03 19:39:17 +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
2009-03-23 20:14:17 +03:00
static int regdb_unpack_values ( struct 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
2010-07-01 17:50:58 +04:00
regval_ctr_addvalue ( values , valuename , type ,
( uint8_t * ) data_p , size ) ;
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
2009-03-23 20:14:17 +03:00
static int regdb_pack_values ( struct regval_ctr * values , uint8 * buf , int buflen )
2005-06-25 21:31:40 +04:00
{
int len = 0 ;
int i ;
2009-03-24 00:27:59 +03:00
struct regval_blob * 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-08 14:32:48 +04:00
static int regdb_fetch_values_internal ( struct db_context * db , const char * key ,
struct 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 ;
2010-05-24 01:58:28 +04:00
WERROR werr ;
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
2009-07-08 14:32:48 +04:00
if ( ! regdb_key_exists ( db , key ) ) {
2008-05-07 15:27:56 +04:00
goto done ;
}
2010-06-24 18:33:37 +04:00
keystr = talloc_asprintf ( ctx , " %s \\ %s " , REG_VALUE_PREFIX , key ) ;
2007-11-27 04:24:56 +03:00
if ( ! keystr ) {
2008-05-07 15:26:13 +04:00
goto done ;
2007-11-27 04:24:56 +03:00
}
2010-05-24 01:58:28 +04:00
werr = regval_ctr_set_seqnum ( values , db - > get_seqnum ( db ) ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
2008-04-01 14:48:08 +04:00
2009-07-08 14:32:48 +04:00
value = regdb_fetch_key_internal ( db , 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
}
2009-07-08 14:32:48 +04:00
int regdb_fetch_values ( const char * key , struct regval_ctr * values )
{
return regdb_fetch_values_internal ( regdb , key , values ) ;
}
2009-07-08 14:38:41 +04:00
static bool regdb_store_values_internal ( struct db_context * db , const char * key ,
struct 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
2009-07-08 14:38:41 +04:00
if ( ! regdb_key_exists ( db , key ) ) {
2008-05-07 15:45:02 +04:00
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
2010-06-24 18:33:37 +04:00
keystr = talloc_asprintf ( ctx , " %s \\ %s " , REG_VALUE_PREFIX , key ) ;
2007-11-27 04:24:56 +03:00
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
}
2009-07-08 14:38:41 +04:00
old_data = dbwrap_fetch_bystring ( db , 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
}
2009-07-08 14:38:41 +04:00
status = dbwrap_trans_store_bystring ( db , 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
}
2009-07-08 14:38:41 +04:00
bool regdb_store_values ( const char * key , struct regval_ctr * values )
{
return regdb_store_values_internal ( regdb , key , values ) ;
}
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 ) ) ;
2009-07-03 19:39:17 +04:00
if ( ! regdb_key_exists ( regdb , key ) ) {
2008-05-07 15:48:28 +04:00
err = WERR_BADFILE ;
goto done ;
}
2010-06-24 18:33:37 +04:00
tdbkey = talloc_asprintf ( tmp_ctx , " %s \\ %s " , REG_SECDESC_PREFIX , key ) ;
2008-03-17 03:39:16 +03:00
if ( tdbkey = = NULL ) {
err = WERR_NOMEM ;
goto done ;
2006-11-30 10:38:40 +03:00
}
2010-06-24 17:30:31 +04:00
tdbkey = normalize_reg_path ( tmp_ctx , tdbkey ) ;
if ( tdbkey = = NULL ) {
err = WERR_NOMEM ;
goto done ;
}
2006-11-30 10:38:40 +03:00
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
2009-07-03 19:39:17 +04:00
if ( ! regdb_key_exists ( regdb , key ) ) {
2008-05-07 15:50:01 +04:00
err = WERR_BADFILE ;
goto done ;
}
2010-06-24 18:33:37 +04:00
tdbkey = talloc_asprintf ( mem_ctx , " %s \\ %s " , REG_SECDESC_PREFIX , key ) ;
2008-03-17 03:31:47 +03:00
if ( tdbkey = = NULL ) {
2006-11-30 10:38:40 +03:00
goto done ;
}
2010-06-24 17:31:06 +04:00
tdbkey = normalize_reg_path ( mem_ctx , tdbkey ) ;
if ( tdbkey = = NULL ) {
err = WERR_NOMEM ;
goto done ;
}
2006-11-30 10:38:40 +03:00
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
}
2009-03-23 20:14:17 +03:00
bool regdb_values_need_update ( struct regval_ctr * values )
2008-01-14 20:31:11 +03:00
{
2010-05-24 01:58:28 +04:00
return ( regdb_get_seqnum ( ) ! = regval_ctr_get_seqnum ( values ) ) ;
2008-01-14 20:31:11 +03:00
}
2010-10-12 17:32:16 +04:00
/*
2002-07-19 22:49:44 +04:00
* Table of function pointers for default access
*/
2010-10-12 17:32:16 +04:00
2009-03-24 01:14:45 +03:00
struct 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
} ;