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.
2010-07-26 22:16:44 +04:00
Copyright ( C ) Wilco Baan Hofman 2010.
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"
2010-07-28 16:46:38 +04:00
# include "lib/util/data_blob.h"
2004-04-04 20:24:08 +04:00
2010-05-09 19:20:01 +04:00
_PUBLIC_ char * reg_val_data_string ( TALLOC_CTX * mem_ctx , uint32_t type ,
2007-09-16 23:14:46 +04:00
const DATA_BLOB data )
2007-10-06 04:17:44 +04:00
{
2011-03-29 22:16:26 +04:00
size_t converted_size = 0 ;
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 ) {
case REG_EXPAND_SZ :
case REG_SZ :
2010-05-09 19:20:01 +04:00
convert_string_talloc ( mem_ctx ,
2010-10-14 12:54:50 +04:00
CH_UTF16 , CH_UNIX ,
data . data , data . length ,
2011-03-29 22:16:26 +04:00
( void * * ) & ret , & converted_size ) ;
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-28 19:03:08 +04:00
SMB_ASSERT ( data . length = = sizeof ( uint32_t ) ) ;
2010-03-29 21:55:16 +04: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 :
2010-03-28 19:03:08 +04:00
SMB_ASSERT ( data . length = = sizeof ( uint64_t ) ) ;
ret = talloc_asprintf ( mem_ctx , " 0x%16.16llx " ,
2010-07-26 22:16:44 +04:00
( long long ) BVAL ( data . data , 0 ) ) ;
2010-03-15 13:07:36 +03:00
break ;
2010-03-28 19:07:09 +04:00
case REG_BINARY :
ret = data_blob_hex_string_upper ( mem_ctx , & data ) ;
break ;
2010-03-28 18:46:53 +04:00
case REG_NONE :
/* "NULL" is the right return value */
break ;
2010-03-28 18:46:30 +04:00
case REG_MULTI_SZ :
/* FIXME: We don't support this yet */
break ;
2007-10-06 04:17:44 +04:00
default :
2010-03-28 18:46:30 +04:00
/* FIXME */
/* Other datatypes aren't supported -> return "NULL" */
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 */
2010-10-14 12:54:50 +04:00
_PUBLIC_ char * reg_val_description ( TALLOC_CTX * mem_ctx ,
2008-02-21 18:01:19 +03:00
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 ) ,
2010-05-09 19:20:01 +04:00
reg_val_data_string ( mem_ctx , data_type , data ) ) ;
2004-04-04 20:24:08 +04:00
}
2010-10-03 08:19:12 +04:00
/*
* This implements reading hex bytes that include comma ' s .
2010-10-14 12:54:50 +04:00
* It was previously handled by strhex_to_data_blob , but that did not cover
2010-10-03 08:19:12 +04:00
* the format used by windows .
*/
2010-07-28 16:46:38 +04:00
static DATA_BLOB reg_strhex_to_data_blob ( TALLOC_CTX * mem_ctx , const char * str )
{
DATA_BLOB ret ;
const char * HEXCHARS = " 0123456789ABCDEF " ;
size_t i , j ;
char * hi , * lo ;
ret = data_blob_talloc_zero ( mem_ctx , ( strlen ( str ) + ( strlen ( str ) % 3 ) ) / 3 ) ;
j = 0 ;
for ( i = 0 ; i < strlen ( str ) ; i + + ) {
hi = strchr ( HEXCHARS , toupper ( str [ i ] ) ) ;
if ( hi = = NULL )
continue ;
i + + ;
lo = strchr ( HEXCHARS , toupper ( str [ i ] ) ) ;
if ( lo = = NULL )
break ;
2010-10-14 12:54:50 +04:00
2010-07-28 16:46:38 +04:00
ret . data [ j ] = PTR_DIFF ( hi , HEXCHARS ) < < 4 ;
ret . data [ j ] + = PTR_DIFF ( lo , HEXCHARS ) ;
j + + ;
if ( j > ret . length ) {
DEBUG ( 0 , ( " Trouble converting hex string to bin \n " ) ) ;
break ;
}
}
return ret ;
2010-10-14 12:54:50 +04:00
}
2010-07-28 16:46:38 +04:00
2010-05-09 19:20:01 +04:00
_PUBLIC_ bool reg_string_to_val ( TALLOC_CTX * mem_ctx , const char * type_str ,
const char * data_str , uint32_t * type , DATA_BLOB * data )
2004-04-04 20:24:08 +04:00
{
2010-07-26 22:16:44 +04:00
char * tmp_type_str , * p , * q ;
int result ;
2010-04-27 18:37:56 +04:00
* type = regtype_by_string ( type_str ) ;
2004-12-15 03:16:54 +03:00
2010-07-26 22:16:44 +04:00
if ( * type = = - 1 ) {
/* Normal windows format is hex, hex(type int as string),
dword or just a string . */
if ( strncmp ( type_str , " hex( " , 4 ) = = 0 ) {
/* there is a hex string with the value type between
the braces */
tmp_type_str = talloc_strdup ( mem_ctx , type_str ) ;
q = p = tmp_type_str + strlen ( " hex( " ) ;
/* Go to the closing brace or end of the string */
while ( * q ! = ' ) ' & & * q ! = ' \0 ' ) q + + ;
* q = ' \0 ' ;
/* Convert hex string to int, store it in type */
result = sscanf ( p , " %x " , type ) ;
if ( ! result ) {
DEBUG ( 0 , ( " Could not convert hex to int \n " ) ) ;
return false ;
}
talloc_free ( tmp_type_str ) ;
} else if ( strcmp ( type_str , " hex " ) = = 0 ) {
* type = REG_BINARY ;
} else if ( strcmp ( type_str , " dword " ) = = 0 ) {
* type = REG_DWORD ;
}
}
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 ) {
2004-12-15 03:16:54 +03:00
case REG_SZ :
2010-05-09 19:20:01 +04:00
return convert_string_talloc ( mem_ctx ,
2010-10-14 12:54:50 +04:00
CH_UNIX , CH_UTF16 ,
data_str , strlen ( data_str ) + 1 ,
( void * * ) & data - > data ,
2011-03-24 02:59:41 +03:00
& data - > length ) ;
2004-12-15 03:16:54 +03:00
break ;
2010-07-28 16:46:38 +04:00
case REG_MULTI_SZ :
case REG_EXPAND_SZ :
2010-03-28 18:46:30 +04:00
case REG_BINARY :
2010-07-28 16:46:38 +04:00
* data = reg_strhex_to_data_blob ( mem_ctx , data_str ) ;
2010-03-28 18:46:30 +04:00
break ;
2010-03-29 20:43:38 +04:00
case REG_DWORD :
2010-03-15 20:55:33 +03:00
case REG_DWORD_BIG_ENDIAN : {
2010-07-28 16:46:38 +04:00
uint32_t tmp = strtol ( data_str , NULL , 16 ) ;
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 : {
2010-10-14 12:50:19 +04:00
uint64_t tmp = strtoll ( data_str , NULL , 16 ) ;
2010-03-15 13:07:36 +03:00
* 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-28 18:46:53 +04:00
case REG_NONE :
ZERO_STRUCTP ( data ) ;
break ;
2004-12-15 03:16:54 +03:00
default :
2010-03-28 18:46:30 +04:00
/* FIXME */
/* Other datatypes aren't supported -> return no success */
return false ;
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-28 17:59:53 +04:00
const 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-28 18:30:43 +04:00
WERROR reg_key_del_abs ( struct registry_context * ctx , const char * path )
2004-12-14 23:49:18 +03:00
{
struct registry_key * parent ;
2010-03-28 18:30:43 +04:00
const char * n ;
TALLOC_CTX * mem_ctx = talloc_init ( " reg_key_del_abs " ) ;
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 ) ;
2010-03-23 00:38:45 +03:00
}
2010-03-28 18:30:43 +04:00
2010-03-29 20:43:38 +04:00
talloc_free ( mem_ctx ) ;
2010-03-22 21:44:19 +03:00
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-29 20:43:38 +04:00
const 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-28 18:18:46 +04:00
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 2 , ( " Opening parent of %s failed with %s \n " , path ,
win_errstr ( error ) ) ) ;
return error ;
2010-03-23 00:38:45 +03:00
}
2010-03-22 21:44:19 +03:00
2010-03-28 18:18:46 +04:00
error = reg_key_add_name ( mem_ctx , parent , n , NULL , sec_desc , result ) ;
2004-12-14 23:49:18 +03:00
return error ;
}