2007-10-06 04:17:44 +04:00
/*
2004-04-04 20:24:08 +04:00
Unix SMB / CIFS implementation .
Transparent registry backend handling
2007-08-26 19:16:40 +04:00
Copyright ( C ) Jelmer Vernooij 2003 - 2007.
2004-04-04 20:24:08 +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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2004-04-04 20:24:08 +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 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-04-04 20:24:08 +04:00
*/
# include "includes.h"
2005-09-04 18:47:19 +04:00
# include "lib/registry/registry.h"
2005-08-23 07:22:25 +04:00
# include "librpc/gen_ndr/winreg.h"
2004-04-04 20:24:08 +04:00
2006-03-06 13:09:53 +03:00
/**
* @ file
* @ brief Registry utility functions
*/
2004-12-15 03:16:54 +03:00
static const struct {
2005-01-31 18:58:54 +03:00
uint32_t id ;
2004-12-15 03:16:54 +03:00
const char * name ;
} reg_value_types [ ] = {
2010-03-11 16:27:45 +03:00
{ REG_NONE , " REG_NONE " } ,
2004-12-15 03:16:54 +03:00
{ REG_SZ , " REG_SZ " } ,
{ REG_EXPAND_SZ , " REG_EXPAND_SZ " } ,
2010-03-11 16:27:45 +03:00
{ REG_BINARY , " REG_BINARY " } ,
{ REG_DWORD , " REG_DWORD " } ,
{ REG_DWORD_BIG_ENDIAN , " REG_DWORD_BIG_ENDIAN " } ,
{ REG_LINK , " REG_LINK " } ,
{ REG_MULTI_SZ , " REG_MULTI_SZ " } ,
{ REG_RESOURCE_LIST , " REG_RESOURCE_LIST " } ,
{ REG_FULL_RESOURCE_DESCRIPTOR , " REG_FULL_RESOURCE_DESCRIPTOR " } ,
{ REG_RESOURCE_REQUIREMENTS_LIST , " REG_RESOURCE_REQUIREMENTS_LIST " } ,
{ REG_QWORD , " REG_QWORD " } ,
2004-12-15 03:16:54 +03:00
{ 0 , NULL }
} ;
2006-03-06 13:09:53 +03:00
/** Return string description of registry value type */
2006-03-07 00:36:24 +03:00
_PUBLIC_ const char * str_regtype ( int type )
2004-04-04 20:24:08 +04:00
{
2009-11-07 23:07:20 +03:00
unsigned int i ;
2004-12-15 03:16:54 +03:00
for ( i = 0 ; reg_value_types [ i ] . name ; i + + ) {
2007-10-06 04:17:44 +04:00
if ( reg_value_types [ i ] . id = = type )
2004-12-15 03:16:54 +03:00
return reg_value_types [ i ] . name ;
2004-04-04 20:24:08 +04:00
}
2004-12-15 03:16:54 +03:00
2004-04-04 20:24:08 +04:00
return " Unknown " ;
}
2008-02-21 18:01:19 +03:00
_PUBLIC_ char * reg_val_data_string ( TALLOC_CTX * mem_ctx ,
struct smb_iconv_convenience * iconv_convenience ,
uint32_t type ,
2007-09-16 23:14:46 +04:00
const DATA_BLOB data )
2007-10-06 04:17:44 +04:00
{
char * ret = NULL ;
2004-04-04 20:24:08 +04:00
2007-10-06 04:17:44 +04:00
if ( data . length = = 0 )
return talloc_strdup ( mem_ctx , " " ) ;
2004-04-04 20:24:08 +04:00
2007-10-06 04:17:44 +04:00
switch ( type ) {
2010-03-15 13:12:52 +03:00
case REG_NONE :
/* "NULL" is the right return value */
break ;
2007-10-06 04:17:44 +04:00
case REG_EXPAND_SZ :
case REG_SZ :
2010-03-14 19:40:14 +03:00
if ( data . length % 2 = = 0 ) {
convert_string_talloc_convenience ( mem_ctx ,
iconv_convenience ,
CH_UTF16 , CH_UNIX ,
data . data ,
data . length ,
( void * * ) & ret ,
NULL , false ) ;
}
2009-11-27 23:14:44 +03:00
break ;
2007-10-06 04:17:44 +04:00
case REG_DWORD :
2010-03-15 20:55:33 +03:00
case REG_DWORD_BIG_ENDIAN :
2010-03-14 19:40:14 +03:00
if ( data . length = = sizeof ( uint32_t ) ) {
2010-03-19 21:55:32 +03:00
ret = talloc_asprintf ( mem_ctx , " 0x%8.8x " ,
IVAL ( data . data , 0 ) ) ;
2009-11-27 23:14:44 +03:00
}
break ;
2010-03-15 13:07:36 +03:00
case REG_QWORD :
if ( data . length = = sizeof ( uint64_t ) ) {
2010-03-15 13:51:42 +03:00
ret = talloc_asprintf ( mem_ctx , " 0x%16.16llx " ,
BVAL ( data . data , 0 ) ) ;
2010-03-15 13:07:36 +03:00
}
break ;
2010-03-15 13:15:19 +03:00
case REG_BINARY :
2007-10-06 04:17:44 +04:00
default :
2010-03-15 13:15:19 +03:00
ret = data_blob_hex_string_upper ( mem_ctx , & data ) ;
2007-10-06 04:17:44 +04:00
break ;
}
2004-04-04 20:24:08 +04:00
2007-10-06 04:17:44 +04:00
return ret ;
2004-04-04 20:24:08 +04:00
}
2006-03-06 13:09:53 +03:00
/** Generate a string that describes a registry value */
2008-02-21 18:01:19 +03:00
_PUBLIC_ char * reg_val_description ( TALLOC_CTX * mem_ctx ,
struct smb_iconv_convenience * iconv_convenience ,
const char * name ,
2007-10-06 04:17:44 +04:00
uint32_t data_type ,
const DATA_BLOB data )
2004-04-04 20:24:08 +04:00
{
2007-10-06 04:17:44 +04:00
return talloc_asprintf ( mem_ctx , " %s = %s : %s " , name ? name : " <No Name> " ,
str_regtype ( data_type ) ,
2008-02-21 18:01:19 +03:00
reg_val_data_string ( mem_ctx , iconv_convenience , data_type , data ) ) ;
2004-04-04 20:24:08 +04:00
}
2008-02-21 18:01:19 +03:00
_PUBLIC_ bool reg_string_to_val ( TALLOC_CTX * mem_ctx ,
struct smb_iconv_convenience * iconv_convenience ,
const char * type_str ,
2007-10-06 04:17:44 +04:00
const char * data_str , uint32_t * type ,
DATA_BLOB * data )
2004-04-04 20:24:08 +04:00
{
2009-11-07 23:07:20 +03:00
unsigned int i ;
2005-09-29 15:51:06 +04:00
* type = - 1 ;
2004-12-15 03:16:54 +03:00
/* Find the correct type */
for ( i = 0 ; reg_value_types [ i ] . name ; i + + ) {
if ( ! strcmp ( reg_value_types [ i ] . name , type_str ) ) {
2005-09-29 15:51:06 +04:00
* type = reg_value_types [ i ] . id ;
2004-12-15 03:16:54 +03:00
break ;
}
}
2007-10-06 04:17:44 +04:00
if ( * type = = - 1 )
2007-08-27 22:10:19 +04:00
return false ;
2004-12-15 03:16:54 +03:00
/* Convert data appropriately */
2009-11-27 23:14:44 +03:00
switch ( * type ) {
2010-03-15 13:12:52 +03:00
case REG_NONE :
ZERO_STRUCTP ( data ) ;
break ;
2004-12-15 03:16:54 +03:00
case REG_SZ :
case REG_EXPAND_SZ :
2010-03-22 14:22:13 +03:00
return convert_string_talloc_convenience ( mem_ctx ,
iconv_convenience ,
CH_UNIX , CH_UTF16 ,
data_str ,
strlen ( data_str ) + 1 ,
( void * * ) & data - > data ,
& data - > length , false ) ;
2004-12-15 03:16:54 +03:00
break ;
2010-03-15 20:55:33 +03:00
case REG_DWORD :
case REG_DWORD_BIG_ENDIAN : {
2005-09-03 21:17:30 +04:00
uint32_t tmp = strtol ( data_str , NULL , 0 ) ;
2010-03-15 13:07:36 +03:00
* data = data_blob_talloc ( mem_ctx , NULL , sizeof ( uint32_t ) ) ;
2010-03-22 14:22:13 +03:00
if ( data - > data = = NULL ) return false ;
2010-02-07 10:11:42 +03:00
SIVAL ( data - > data , 0 , tmp ) ;
2005-09-03 21:17:30 +04:00
}
2004-12-15 03:16:54 +03:00
break ;
2010-03-15 13:07:36 +03:00
case REG_QWORD : {
uint64_t tmp = strtoll ( data_str , NULL , 0 ) ;
* data = data_blob_talloc ( mem_ctx , NULL , sizeof ( uint64_t ) ) ;
2010-03-22 14:22:13 +03:00
if ( data - > data = = NULL ) return false ;
2010-03-15 13:07:36 +03:00
SBVAL ( data - > data , 0 , tmp ) ;
}
break ;
2010-03-15 13:15:19 +03:00
case REG_BINARY :
2004-12-15 03:16:54 +03:00
default :
2010-03-15 13:15:19 +03:00
* data = strhex_to_data_blob ( mem_ctx , data_str ) ;
break ;
2004-12-15 03:16:54 +03:00
}
2007-08-27 22:10:19 +04:00
return true ;
2004-04-04 20:24:08 +04:00
}
2006-03-06 13:09:53 +03:00
/** Open a key by name (including the predefined key name!) */
2007-10-06 04:17:44 +04:00
WERROR reg_open_key_abs ( TALLOC_CTX * mem_ctx , struct registry_context * handle ,
const char * name , struct registry_key * * result )
2004-12-14 23:49:18 +03:00
{
struct registry_key * predef ;
WERROR error ;
2009-11-07 23:07:20 +03:00
size_t predeflength ;
2004-12-14 23:49:18 +03:00
char * predefname ;
2007-10-06 04:17:44 +04:00
if ( strchr ( name , ' \\ ' ) ! = NULL )
2007-08-26 19:16:40 +04:00
predeflength = strchr ( name , ' \\ ' ) - name ;
2007-10-06 04:17:44 +04:00
else
2007-08-26 19:16:40 +04:00
predeflength = strlen ( name ) ;
2004-12-14 23:49:18 +03:00
2006-09-28 10:44:47 +04:00
predefname = talloc_strndup ( mem_ctx , name , predeflength ) ;
2010-03-22 21:44:19 +03:00
W_ERROR_HAVE_NO_MEMORY ( predefname ) ;
2004-12-14 23:49:18 +03:00
error = reg_get_predefined_key_by_name ( handle , predefname , & predef ) ;
2006-09-28 10:44:47 +04:00
talloc_free ( predefname ) ;
2004-12-14 23:49:18 +03:00
2007-08-26 19:16:40 +04:00
if ( ! W_ERROR_IS_OK ( error ) ) {
2004-12-14 23:49:18 +03:00
return error ;
}
if ( strchr ( name , ' \\ ' ) ) {
2007-10-06 04:17:44 +04:00
return reg_open_key ( mem_ctx , predef , strchr ( name , ' \\ ' ) + 1 ,
result ) ;
2004-12-14 23:49:18 +03:00
} else {
* result = predef ;
return WERR_OK ;
}
}
2007-10-06 04:17:44 +04:00
static WERROR get_abs_parent ( TALLOC_CTX * mem_ctx , struct registry_context * ctx ,
const char * path , struct registry_key * * parent ,
2010-03-22 21:53:23 +03:00
char * * name )
2004-12-14 23:49:18 +03:00
{
char * parent_name ;
WERROR error ;
2007-10-06 04:17:44 +04:00
2004-12-14 23:49:18 +03:00
if ( strchr ( path , ' \\ ' ) = = NULL ) {
return WERR_FOOBAR ;
}
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
parent_name = talloc_strndup ( mem_ctx , path , strrchr ( path , ' \\ ' ) - path ) ;
2010-03-22 21:44:19 +03:00
W_ERROR_HAVE_NO_MEMORY ( parent_name ) ;
2004-12-14 23:49:18 +03:00
error = reg_open_key_abs ( mem_ctx , ctx , parent_name , parent ) ;
2010-03-22 21:44:19 +03:00
talloc_free ( parent_name ) ;
2004-12-14 23:49:18 +03:00
if ( ! W_ERROR_IS_OK ( error ) ) {
return error ;
}
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
* name = talloc_strdup ( mem_ctx , strrchr ( path , ' \\ ' ) + 1 ) ;
2010-03-22 21:44:19 +03:00
W_ERROR_HAVE_NO_MEMORY ( * name ) ;
2004-12-14 23:49:18 +03:00
return WERR_OK ;
}
2010-03-22 21:47:49 +03:00
WERROR reg_key_del_abs ( TALLOC_CTX * mem_ctx , struct registry_context * ctx ,
const char * path )
2004-12-14 23:49:18 +03:00
{
struct registry_key * parent ;
2010-03-22 21:53:23 +03:00
char * n ;
2004-12-14 23:49:18 +03:00
WERROR error ;
2007-10-06 04:17:44 +04:00
2004-12-14 23:49:18 +03:00
if ( ! strchr ( path , ' \\ ' ) ) {
return WERR_FOOBAR ;
}
2007-10-06 04:17:44 +04:00
2004-12-14 23:49:18 +03:00
error = get_abs_parent ( mem_ctx , ctx , path , & parent , & n ) ;
if ( W_ERROR_IS_OK ( error ) ) {
2010-03-22 21:18:56 +03:00
error = reg_key_del ( mem_ctx , parent , n ) ;
2004-12-14 23:49:18 +03:00
}
2010-03-22 21:44:19 +03:00
talloc_free ( parent ) ;
talloc_free ( n ) ;
2004-12-14 23:49:18 +03:00
return error ;
}
2007-10-06 04:17:44 +04:00
WERROR reg_key_add_abs ( TALLOC_CTX * mem_ctx , struct registry_context * ctx ,
const char * path , uint32_t access_mask ,
struct security_descriptor * sec_desc ,
struct registry_key * * result )
2004-12-14 23:49:18 +03:00
{
struct registry_key * parent ;
2010-03-22 21:53:23 +03:00
char * n ;
2004-12-14 23:49:18 +03:00
WERROR error ;
2007-10-06 04:17:44 +04:00
2010-03-22 23:34:54 +03:00
* result = NULL ;
2004-12-14 23:49:18 +03:00
if ( ! strchr ( path , ' \\ ' ) ) {
2007-08-26 19:16:40 +04:00
return WERR_ALREADY_EXISTS ;
2004-12-14 23:49:18 +03:00
}
2007-10-06 04:17:44 +04:00
2004-12-14 23:49:18 +03:00
error = get_abs_parent ( mem_ctx , ctx , path , & parent , & n ) ;
2010-03-22 21:45:21 +03:00
if ( W_ERROR_IS_OK ( error ) ) {
error = reg_key_add_name ( mem_ctx , parent , n , NULL , sec_desc ,
result ) ;
2004-12-14 23:49:18 +03:00
}
2010-03-22 21:44:19 +03:00
talloc_free ( parent ) ;
talloc_free ( n ) ;
2004-12-14 23:49:18 +03:00
return error ;
}