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
2011-07-06 14:09:52 +04:00
* Copyright ( C ) Michael Adam 2007 - 2011
* Copyright ( C ) Gregor Beck 2011
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"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-07-06 18:40:21 +04:00
# include "dbwrap/dbwrap_open.h"
2011-05-30 07:23:56 +04:00
# include "../libcli/security/secdesc.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 ) ;
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 ) ;
2011-07-04 18:23:08 +04:00
static WERROR regdb_store_subkey_list ( struct db_context * db , const char * parent ,
const char * key ) ;
2008-04-29 19:17:02 +04:00
2011-07-04 15:14:43 +04:00
static WERROR regdb_create_basekey ( struct db_context * db , const char * key ) ;
2011-07-04 15:19:13 +04:00
static WERROR regdb_create_subkey_internal ( struct db_context * db ,
const char * key ,
const char * subkey ) ;
2011-05-11 17:27:01 +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
} ;
2011-07-04 15:19:13 +04:00
static WERROR create_key_recursive ( struct db_context * db ,
char * path ,
const char * subkey )
{
WERROR werr ;
char * p ;
if ( subkey = = NULL ) {
return WERR_INVALID_PARAM ;
}
if ( path = = NULL ) {
return regdb_create_basekey ( db , subkey ) ;
}
p = strrchr_m ( path , ' \\ ' ) ;
if ( p = = NULL ) {
werr = create_key_recursive ( db , NULL , path ) ;
} else {
* p = ' \0 ' ;
werr = create_key_recursive ( db , path , p + 1 ) ;
* p = ' \\ ' ;
}
if ( ! W_ERROR_IS_OK ( werr ) ) {
goto done ;
}
werr = regdb_create_subkey_internal ( db , path , subkey ) ;
done :
return werr ;
}
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
{
2011-07-04 15:19:13 +04:00
char * subkey , * key ;
2008-04-13 15:38:44 +04:00
WERROR werr ;
2008-03-20 15:59:09 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-04 15:19:13 +04:00
if ( add_path = = NULL ) {
werr = WERR_INVALID_PARAM ;
goto done ;
2007-02-07 16:26:13 +03:00
}
2011-07-04 15:19:13 +04:00
key = talloc_strdup ( frame , add_path ) ;
subkey = strrchr_m ( key , ' \\ ' ) ;
if ( subkey = = NULL ) {
subkey = key ;
key = NULL ;
} else {
* subkey = ' \0 ' ;
subkey + + ;
2008-03-20 15:59:09 +03:00
}
2011-07-04 15:19:13 +04:00
werr = create_key_recursive ( db , key , subkey ) ;
2008-04-13 15:38:44 +04:00
2011-07-04 15:19:13 +04:00
done :
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 ;
2011-08-25 19:12:33 +04:00
struct db_context * db = ( struct db_context * ) private_data ;
2010-06-24 17:26:04 +04:00
if ( rec - > key . dptr = = NULL | | rec - > key . dsize = = 0 ) {
return 0 ;
}
2011-08-25 19:12:33 +04:00
if ( db = = NULL ) {
DEBUG ( 0 , ( " regdb_normalize_keynames_fn: ERROR: "
" NULL db context handed in via private_data \n " ) ) ;
return 1 ;
}
2010-06-24 17:26:04 +04:00
keyname = strchr ( ( const char * ) rec - > key . dptr , ' / ' ) ;
if ( keyname ) {
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 ) ) ;
/* 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 ;
}
2011-08-25 19:12:33 +04:00
status = dbwrap_store_bystring ( db , keyname , rec - > value ,
TDB_REPLACE ) ;
2010-06-24 17:26:04 +04:00
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 ;
}
2011-07-04 18:09:33 +04:00
static WERROR regdb_store_regdb_version ( struct db_context * db , uint32_t version )
2010-06-25 20:11:35 +04:00
{
NTSTATUS status ;
const char * version_keyname = " INFO/version " ;
2011-07-04 18:09:33 +04:00
if ( db = = NULL ) {
2010-06-25 20:11:35 +04:00
return WERR_CAN_NOT_COMPLETE ;
}
2011-07-04 18:09:33 +04:00
status = dbwrap_trans_store_int32 ( db , version_keyname , version ) ;
2010-06-25 20:11:35 +04:00
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 ;
}
}
2011-07-04 18:21:26 +04:00
static WERROR regdb_upgrade_v1_to_v2 ( struct db_context * db )
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 ( ) ;
2011-08-25 19:12:33 +04:00
rc = db - > traverse ( db , regdb_normalize_keynames_fn , db ) ;
2010-06-24 17:26:04 +04:00
2011-07-04 19:22:01 +04:00
talloc_free ( mem_ctx ) ;
2010-06-25 20:12:28 +04:00
2011-06-20 13:10:31 +04:00
if ( rc < 0 ) {
2010-06-25 20:12:28 +04:00
return WERR_REG_IO_FAILURE ;
}
2011-07-04 18:21:26 +04:00
werr = regdb_store_regdb_version ( db , REGVER_V2 ) ;
2010-06-25 20:12:28 +04:00
return werr ;
2010-06-24 17:26:04 +04:00
}
2011-07-04 18:23:08 +04:00
static int regdb_upgrade_v2_to_v3_fn ( struct db_record * rec , void * private_data )
{
const char * keyname ;
fstring subkeyname ;
NTSTATUS status ;
WERROR werr ;
uint8_t * buf ;
uint32_t buflen , len ;
uint32_t num_items ;
uint32_t i ;
2011-08-25 19:18:12 +04:00
struct db_context * db = ( struct db_context * ) private_data ;
2011-07-04 18:23:08 +04:00
if ( rec - > key . dptr = = NULL | | rec - > key . dsize = = 0 ) {
return 0 ;
}
2011-08-25 19:18:12 +04:00
if ( db = = NULL ) {
DEBUG ( 0 , ( " regdb_normalize_keynames_fn: ERROR: "
" NULL db context handed in via private_data \n " ) ) ;
return 1 ;
}
2011-07-04 18:23:08 +04:00
keyname = ( const char * ) rec - > key . dptr ;
if ( strncmp ( keyname , REG_SORTED_SUBKEYS_PREFIX ,
strlen ( REG_SORTED_SUBKEYS_PREFIX ) ) = = 0 )
{
/* Delete the deprecated sorted subkeys cache. */
2011-07-04 19:20:28 +04:00
DEBUG ( 10 , ( " regdb_upgrade_v2_to_v3: deleting [%s] \n " , keyname ) ) ;
2011-07-04 18:23:08 +04:00
status = rec - > delete_rec ( rec ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " regdb_upgrade_v2_to_v3: tdb_delete for [%s] "
" failed! \n " , keyname ) ) ;
return 1 ;
}
return 0 ;
}
if ( strncmp ( keyname , REG_VALUE_PREFIX , strlen ( REG_VALUE_PREFIX ) ) = = 0 ) {
2011-07-04 19:20:28 +04:00
DEBUG ( 10 , ( " regdb_upgrade_v2_to_v3: skipping [%s] \n " , keyname ) ) ;
2011-07-04 18:23:08 +04:00
return 0 ;
}
if ( strncmp ( keyname , REG_SECDESC_PREFIX ,
strlen ( REG_SECDESC_PREFIX ) ) = = 0 )
{
2011-07-04 19:20:28 +04:00
DEBUG ( 10 , ( " regdb_upgrade_v2_to_v3: skipping [%s] \n " , keyname ) ) ;
2011-07-04 18:23:08 +04:00
return 0 ;
}
/*
* Found a regular subkey list record .
* Walk the list and create the list record for those
* subkeys that don ' t already have one .
*/
2011-07-04 19:20:28 +04:00
DEBUG ( 10 , ( " regdb_upgrade_v2_to_v3: scanning subkey list of [%s] \n " ,
keyname ) ) ;
2011-07-04 18:23:08 +04:00
buf = rec - > value . dptr ;
buflen = rec - > value . dsize ;
len = tdb_unpack ( buf , buflen , " d " , & num_items ) ;
if ( len = = ( uint32_t ) - 1 ) {
/* invalid or empty - skip */
return 0 ;
}
for ( i = 0 ; i < num_items ; i + + ) {
len + = tdb_unpack ( buf + len , buflen - len , " f " , subkeyname ) ;
2011-07-04 19:20:28 +04:00
DEBUG ( 10 , ( " regdb_upgrade_v2_to_v3: "
" writing subkey list for [%s \\ %s] \n " ,
keyname , subkeyname ) ) ;
2011-08-25 19:18:12 +04:00
werr = regdb_store_subkey_list ( db , keyname , subkeyname ) ;
2011-07-04 18:23:08 +04:00
if ( ! W_ERROR_IS_OK ( werr ) ) {
return 1 ;
}
}
return 0 ;
}
static WERROR regdb_upgrade_v2_to_v3 ( struct db_context * db )
{
int rc ;
WERROR werr ;
2011-08-25 19:18:12 +04:00
rc = regdb - > traverse ( db , regdb_upgrade_v2_to_v3_fn , db ) ;
2011-07-04 18:23:08 +04:00
if ( rc < 0 ) {
werr = WERR_REG_IO_FAILURE ;
goto done ;
}
werr = regdb_store_regdb_version ( db , REGVER_V3 ) ;
done :
return werr ;
}
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
2011-07-04 18:23:08 +04:00
expected_version = REGVER_V3 ;
2010-06-25 16:34:04 +04:00
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 ) ) ;
2011-07-04 18:09:33 +04:00
werr = regdb_store_regdb_version ( regdb , expected_version ) ;
2010-06-25 20:13:06 +04:00
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 ;
}
2011-07-04 18:15:11 +04:00
if ( regdb - > transaction_start ( regdb ) ! = 0 ) {
return WERR_REG_IO_FAILURE ;
}
2010-06-25 16:34:04 +04:00
if ( vers_id = = REGVER_V1 ) {
2011-07-04 19:13:58 +04:00
DEBUG ( 10 , ( " regdb_init: upgrading registry fromversion %d "
" to %d \n " , REGVER_V1 , REGVER_V2 ) ) ;
2010-06-24 17:26:04 +04:00
2011-07-04 18:21:26 +04:00
werr = regdb_upgrade_v1_to_v2 ( regdb ) ;
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
vers_id = REGVER_V2 ;
2005-09-01 18:00:53 +04:00
}
2005-06-17 19:53:01 +04:00
2011-07-04 18:23:08 +04:00
if ( vers_id = = REGVER_V2 ) {
DEBUG ( 10 , ( " regdb_init: upgrading registry from version %d "
" to %d \n " , REGVER_V2 , REGVER_V3 ) ) ;
werr = regdb_upgrade_v2_to_v3 ( regdb ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
regdb - > transaction_cancel ( regdb ) ;
return werr ;
}
vers_id = REGVER_V3 ;
}
2010-06-25 16:34:04 +04:00
/* future upgrade code should go here */
2011-07-04 18:15:11 +04:00
if ( regdb - > transaction_commit ( regdb ) ! = 0 ) {
return WERR_REG_IO_FAILURE ;
}
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
2011-07-04 17:23:39 +04:00
/* treat "not found" as ok */
2009-02-26 03:16:07 +03:00
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
}
2011-06-30 16:36:35 +04: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 ) ) ;
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
}
2011-07-01 17:47:50 +04:00
/**
* Utility function to store a new empty list of
* subkeys of given key specified as parent and subkey name
* ( thereby creating the key ) .
2011-07-04 15:06:20 +04:00
* If the parent keyname is NULL , then the " subkey " is
* interpreted as a base key .
2011-07-01 17:47:50 +04:00
* If the subkey list does already exist , it is not modified .
*
* Must be called from within a transaction .
*/
static WERROR regdb_store_subkey_list ( struct db_context * db , const char * parent ,
const char * key )
{
WERROR werr ;
char * path = NULL ;
struct regsubkey_ctr * subkeys = NULL ;
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2011-07-04 15:06:20 +04:00
if ( parent = = NULL ) {
path = talloc_strdup ( frame , key ) ;
} else {
path = talloc_asprintf ( frame , " %s \\ %s " , parent , key ) ;
}
2011-07-01 17:47:50 +04:00
if ( ! path ) {
werr = WERR_NOMEM ;
goto done ;
}
werr = regsubkey_ctr_init ( frame , & subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
werr = regdb_fetch_keys_internal ( db , path , subkeys ) ;
if ( W_ERROR_IS_OK ( werr ) ) {
/* subkey list exists already - don't modify */
goto done ;
}
werr = regsubkey_ctr_reinit ( subkeys ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
/* create a record with 0 subkeys */
werr = regdb_store_keys_internal2 ( db , path , subkeys ) ;
if ( ! W_ERROR_IS_OK ( werr ) ) {
DEBUG ( 0 , ( " regdb_store_keys: Failed to store new record for "
" key [%s]: %s \n " , path , win_errstr ( werr ) ) ) ;
goto done ;
}
done :
talloc_free ( frame ) ;
return werr ;
}
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 ;
2011-07-01 17:47:50 +04:00
struct regsubkey_ctr * 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
2007-11-27 04:24:56 +03:00
for ( i = 0 ; i < num_subkeys ; i + + ) {
2011-07-01 17:47:50 +04:00
const char * subkey ;
2005-08-29 18:55:40 +04:00
2011-07-01 17:47:50 +04:00
subkey = regsubkey_ctr_specific_key ( store_ctx - > ctr , i ) ;
2005-08-29 18:55:40 +04:00
2011-07-01 17:47:50 +04:00
werr = regdb_store_subkey_list ( db , store_ctx - > key , subkey ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
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 ;
2011-07-01 16:23:19 +04:00
if ( ! 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
}
2011-07-01 17:50:05 +04:00
werr = regdb_store_subkey_list ( db , create_ctx - > key , create_ctx - > subkey ) ;
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
2011-07-04 15:09:31 +04:00
static WERROR regdb_create_subkey_internal ( struct db_context * db ,
const char * key ,
const char * subkey )
2009-07-09 12:41:59 +04:00
{
WERROR werr ;
struct regsubkey_ctr * subkeys ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
struct regdb_create_subkey_context create_ctx ;
2011-07-04 15:09:31 +04:00
if ( ! regdb_key_exists ( db , key ) ) {
2009-07-09 12:41:59 +04:00
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
2011-07-04 15:09:31 +04:00
werr = regdb_fetch_keys_internal ( db , key , subkeys ) ;
2009-07-15 14:45:43 +04:00
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
2011-07-04 15:09:31 +04:00
werr = ntstatus_to_werror ( dbwrap_trans_do ( db ,
2009-07-09 12:41:59 +04:00
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
2011-07-04 15:09:31 +04:00
static WERROR regdb_create_subkey ( const char * key , const char * subkey )
{
return regdb_create_subkey_internal ( regdb , key , subkey ) ;
}
2011-07-04 15:14:43 +04:00
/**
* create a base key
*/
struct regdb_create_basekey_context {
const char * key ;
} ;
static NTSTATUS regdb_create_basekey_action ( struct db_context * db ,
void * private_data )
{
WERROR werr ;
struct regdb_create_basekey_context * create_ctx ;
create_ctx = ( struct regdb_create_basekey_context * ) private_data ;
werr = regdb_store_subkey_list ( db , NULL , create_ctx - > key ) ;
return werror_to_ntstatus ( werr ) ;
}
static WERROR regdb_create_basekey ( struct db_context * db , const char * key )
{
WERROR werr ;
struct regdb_create_subkey_context create_ctx ;
create_ctx . key = key ;
werr = ntstatus_to_werror ( dbwrap_trans_do ( db ,
regdb_create_basekey_action ,
& create_ctx ) ) ;
return werr ;
}
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 ;
2011-08-01 17:27:46 +04:00
bool lazy ;
2009-07-09 13:04:20 +04:00
} ;
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 ) ;
2011-08-01 17:27:46 +04:00
if ( delete_ctx - > lazy ) {
goto done ;
}
2009-07-09 13:04:20 +04: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 , 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 ) ;
}
2011-08-01 17:27:46 +04:00
static WERROR regdb_delete_subkey ( const char * key , const char * subkey , bool lazy )
2009-07-09 13:04:20 +04:00
{
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 ( ) ;
2011-07-01 15:57:19 +04:00
if ( ! 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 ;
2011-08-01 17:27:46 +04:00
delete_ctx . lazy = lazy ;
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-06 12:05:20 +04:00
/**
* Check for the existence of a key .
*
2011-07-01 15:33:44 +04:00
* Existence of a key is authoritatively defined by
* the existence of the record that contains the list
* of its subkeys .
2011-08-15 03:30:32 +04:00
*
* Return false , if the record does not match the correct
* structure of an initial 4 - byte counter and then a
* list of the corresponding number of zero - terminated
* strings .
2008-05-06 12:05:20 +04:00
*/
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 ;
2011-07-01 15:18:51 +04:00
char * path ;
2011-08-15 03:30:32 +04:00
uint32_t buflen ;
const char * buf ;
uint32_t num_items , i ;
int32_t len ;
2008-05-06 12:05:20 +04:00
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
2011-07-01 15:18:51 +04:00
value = regdb_fetch_key_internal ( db , mem_ctx , path ) ;
2011-08-15 03:30:32 +04:00
if ( value . dptr = = NULL ) {
goto done ;
}
if ( value . dsize = = 0 ) {
DEBUG ( 10 , ( " regdb_key_exists: subkeylist-record for key "
" [%s] is empty: Could be a deleted record in a "
" clustered (ctdb) environment? \n " ,
path ) ) ;
goto done ;
}
len = tdb_unpack ( value . dptr , value . dsize , " d " , & num_items ) ;
if ( len = = ( int32_t ) - 1 ) {
DEBUG ( 1 , ( " regdb_key_exists: ERROR: subkeylist-record for key "
" [%s] is invalid: Could not parse initial 4-byte "
" counter. record data length is %u. \n " ,
path , ( unsigned int ) value . dsize ) ) ;
goto done ;
}
/*
* Note : the tdb_unpack check above implies that len < = value . dsize
*/
buflen = value . dsize - len ;
buf = ( const char * ) value . dptr + len ;
len = 0 ;
for ( i = 0 ; i < num_items ; i + + ) {
if ( buflen = = 0 ) {
break ;
}
len = strnlen ( buf , buflen ) + 1 ;
if ( buflen < len ) {
DEBUG ( 1 , ( " regdb_key_exists: ERROR: subkeylist-record "
" for key [%s] is corrupt: %u items expected, "
" item number %u is not zero terminated. \n " ,
path , num_items , i + 1 ) ) ;
goto done ;
}
buf + = len ;
buflen - = len ;
}
if ( buflen > 0 ) {
DEBUG ( 1 , ( " regdb_key_exists: ERROR: subkeylist-record for key "
" [%s] is corrupt: %u items expected and found, but "
" the record contains additional %u bytes \n " ,
path , num_items , buflen ) ) ;
goto done ;
}
if ( i < num_items ) {
DEBUG ( 1 , ( " regdb_key_exists: ERROR: subkeylist-record for key "
" [%s] is corrupt: %u items expected, but only %u "
" items found. \n " ,
path , num_items , i + 1 ) ) ;
goto done ;
}
ret = true ;
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
}
2011-07-13 18:51:54 +04:00
werr = regsubkey_ctr_reinit ( ctr ) ;
W_ERROR_NOT_OK_GOTO_DONE ( werr ) ;
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
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
2011-06-07 05:30:12 +04: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
} ;