2007-10-06 04:17:44 +04:00
/*
2007-08-26 19:16:40 +04:00
Unix SMB / CIFS implementation .
Reading . REG files
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
Copyright ( C ) Jelmer Vernooij 2004 - 2007
2010-07-27 00:10:43 +04:00
Copyright ( C ) Wilco Baan Hofman 2006 - 2010
2007-08-26 19:16:40 +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
2008-03-28 09:08:49 +03:00
the Free Software Foundation ; either version 3 of the License , or
2007-08-26 19:16:40 +04:00
( at your option ) any later version .
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
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 .
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2010-07-27 00:10:43 +04:00
/* FIXME:
* - Newer . REG files , created by Windows XP and above use unicode UCS - 2
* - @ = " " constructions should write value with empty name .
*/
2007-08-26 19:16:40 +04:00
# include "includes.h"
2024-04-10 14:02:39 +03:00
# include "lib/util/util_file.h"
2007-08-26 19:16:40 +04:00
# include "lib/registry/registry.h"
# include "system/filesys.h"
/**
* @ file
* @ brief Registry patch files
*/
# define HEADER_STRING "REGEDIT4"
struct dotreg_data {
int fd ;
} ;
2010-10-03 08:11:31 +04:00
/*
* This is basically a copy of data_blob_hex_string_upper , but with comma ' s
* between the bytes in hex .
*/
2010-10-04 03:35:36 +04:00
static char * dotreg_data_blob_hex_string ( TALLOC_CTX * mem_ctx , const DATA_BLOB * blob )
2010-10-03 08:11:31 +04:00
{
2010-10-03 18:14:34 +04:00
size_t i ;
2010-10-03 08:11:31 +04:00
char * hex_string ;
hex_string = talloc_array ( mem_ctx , char , ( blob - > length * 3 ) + 1 ) ;
if ( ! hex_string ) {
return NULL ;
}
for ( i = 0 ; i < blob - > length ; i + + )
slprintf ( & hex_string [ i * 3 ] , 4 , " %02X, " , blob - > data [ i ] ) ;
2010-10-03 08:36:49 +04:00
/* Remove last comma and NULL-terminate the string */
hex_string [ ( blob - > length * 3 ) - 1 ] = ' \0 ' ;
2010-10-03 08:11:31 +04:00
return hex_string ;
}
/*
* This is basically a copy of reg_val_data_string , except that this function
* has no 0 x for dwords , everything else is regarded as binary , and binary
* strings are represented with bytes comma - separated .
*/
2010-10-04 03:35:36 +04:00
static char * reg_val_dotreg_string ( TALLOC_CTX * mem_ctx , uint32_t type ,
2010-10-03 08:11:31 +04:00
const DATA_BLOB data )
{
2011-03-29 22:16:26 +04:00
size_t converted_size = 0 ;
2010-10-03 08:11:31 +04:00
char * ret = NULL ;
if ( data . length = = 0 )
return talloc_strdup ( mem_ctx , " " ) ;
switch ( type ) {
case REG_EXPAND_SZ :
case REG_SZ :
convert_string_talloc ( mem_ctx ,
2011-03-24 02:59:41 +03:00
CH_UTF16 , CH_UNIX , data . data , data . length ,
2011-03-29 22:16:26 +04:00
( void * * ) & ret , & converted_size ) ;
2010-10-03 08:11:31 +04:00
break ;
case REG_DWORD :
case REG_DWORD_BIG_ENDIAN :
SMB_ASSERT ( data . length = = sizeof ( uint32_t ) ) ;
ret = talloc_asprintf ( mem_ctx , " %08x " ,
IVAL ( data . data , 0 ) ) ;
break ;
default : /* default means treat as binary */
case REG_BINARY :
ret = dotreg_data_blob_hex_string ( mem_ctx , & data ) ;
break ;
}
return ret ;
}
2007-08-26 19:16:40 +04:00
static WERROR reg_dotreg_diff_add_key ( void * _data , const char * key_name )
{
2007-09-07 17:31:15 +04:00
struct dotreg_data * data = ( struct dotreg_data * ) _data ;
2007-08-26 19:16:40 +04:00
fdprintf ( data - > fd , " \n [%s] \n " , key_name ) ;
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
return WERR_OK ;
}
static WERROR reg_dotreg_diff_del_key ( void * _data , const char * key_name )
{
2007-09-07 17:31:15 +04:00
struct dotreg_data * data = ( struct dotreg_data * ) _data ;
2007-08-26 19:16:40 +04:00
fdprintf ( data - > fd , " \n [-%s] \n " , key_name ) ;
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
return WERR_OK ;
}
2007-10-06 04:17:44 +04:00
static WERROR reg_dotreg_diff_set_value ( void * _data , const char * path ,
const char * value_name ,
uint32_t value_type , DATA_BLOB value )
2007-08-26 19:16:40 +04:00
{
2007-09-07 17:31:15 +04:00
struct dotreg_data * data = ( struct dotreg_data * ) _data ;
2010-10-03 08:11:31 +04:00
char * data_string = reg_val_dotreg_string ( NULL ,
2010-03-22 14:00:57 +03:00
value_type , value ) ;
2010-10-03 08:36:49 +04:00
char * data_incl_type ;
2010-10-03 08:11:31 +04:00
2010-03-22 14:00:57 +03:00
W_ERROR_HAVE_NO_MEMORY ( data_string ) ;
2010-10-03 08:36:49 +04:00
switch ( value_type ) {
case REG_SZ :
data_incl_type = talloc_asprintf ( data_string , " \" %s \" " ,
data_string ) ;
break ;
case REG_DWORD :
data_incl_type = talloc_asprintf ( data_string ,
" dword:%s " , data_string ) ;
break ;
case REG_BINARY :
data_incl_type = talloc_asprintf ( data_string , " hex:%s " ,
data_string ) ;
break ;
default :
data_incl_type = talloc_asprintf ( data_string , " hex(%x):%s " ,
value_type , data_string ) ;
break ;
2010-10-03 08:11:31 +04:00
}
2010-10-03 08:36:49 +04:00
2010-10-03 08:11:31 +04:00
if ( value_name [ 0 ] = = ' \0 ' ) {
2010-10-03 08:36:49 +04:00
fdprintf ( data - > fd , " @=%s \n " , data_incl_type ) ;
2010-10-03 08:11:31 +04:00
} else {
2010-10-03 08:36:49 +04:00
fdprintf ( data - > fd , " \" %s \" =%s \n " ,
value_name , data_incl_type ) ;
2010-10-03 08:11:31 +04:00
}
2010-03-22 14:00:57 +03:00
talloc_free ( data_string ) ;
2007-10-06 04:17:44 +04:00
2007-08-26 19:16:40 +04:00
return WERR_OK ;
}
2007-10-06 04:17:44 +04:00
static WERROR reg_dotreg_diff_del_value ( void * _data , const char * path ,
const char * value_name )
2007-08-26 19:16:40 +04:00
{
2007-09-07 17:31:15 +04:00
struct dotreg_data * data = ( struct dotreg_data * ) _data ;
2007-08-26 19:16:40 +04:00
fdprintf ( data - > fd , " \" %s \" =- \n " , value_name ) ;
return WERR_OK ;
}
static WERROR reg_dotreg_diff_done ( void * _data )
{
2007-09-07 19:35:18 +04:00
struct dotreg_data * data = ( struct dotreg_data * ) _data ;
2007-08-26 19:16:40 +04:00
close ( data - > fd ) ;
talloc_free ( data ) ;
return WERR_OK ;
}
2007-10-06 04:17:44 +04:00
static WERROR reg_dotreg_diff_del_all_values ( void * callback_data ,
const char * key_name )
2007-08-26 19:16:40 +04:00
{
return WERR_NOT_SUPPORTED ;
}
/**
* Save registry diff
*/
2007-10-06 04:17:44 +04:00
_PUBLIC_ WERROR reg_dotreg_diff_save ( TALLOC_CTX * ctx , const char * filename ,
struct reg_diff_callbacks * * callbacks ,
void * * callback_data )
2007-08-26 19:16:40 +04:00
{
struct dotreg_data * data ;
data = talloc_zero ( ctx , struct dotreg_data ) ;
* callback_data = data ;
if ( filename ) {
2008-04-15 13:52:33 +04:00
data - > fd = open ( filename , O_CREAT | O_WRONLY , 0755 ) ;
if ( data - > fd < 0 ) {
2007-08-26 19:16:40 +04:00
DEBUG ( 0 , ( " Unable to open %s \n " , filename ) ) ;
2015-12-03 17:24:12 +03:00
return WERR_FILE_NOT_FOUND ;
2007-08-26 19:16:40 +04:00
}
} else {
data - > fd = STDOUT_FILENO ;
}
2008-04-15 13:52:33 +04:00
fdprintf ( data - > fd , " %s \n \n " , HEADER_STRING ) ;
2007-08-26 19:16:40 +04:00
* callbacks = talloc ( ctx , struct reg_diff_callbacks ) ;
( * callbacks ) - > add_key = reg_dotreg_diff_add_key ;
( * callbacks ) - > del_key = reg_dotreg_diff_del_key ;
( * callbacks ) - > set_value = reg_dotreg_diff_set_value ;
( * callbacks ) - > del_value = reg_dotreg_diff_del_value ;
( * callbacks ) - > del_all_values = reg_dotreg_diff_del_all_values ;
( * callbacks ) - > done = reg_dotreg_diff_done ;
return WERR_OK ;
2007-10-06 04:17:44 +04:00
}
2007-08-26 19:16:40 +04:00
/**
* Load diff file
*/
2007-10-06 04:17:44 +04:00
_PUBLIC_ WERROR reg_dotreg_diff_load ( int fd ,
const struct reg_diff_callbacks * callbacks ,
void * callback_data )
2007-08-26 19:16:40 +04:00
{
char * line , * p , * q ;
char * curkey = NULL ;
TALLOC_CTX * mem_ctx = talloc_init ( " reg_dotreg_diff_load " ) ;
WERROR error ;
uint32_t value_type ;
2010-07-27 00:10:43 +04:00
DATA_BLOB data ;
bool result ;
char * type_str = NULL ;
2015-02-25 15:19:44 +03:00
char * data_str = NULL ;
char * value = NULL ;
2010-07-27 00:10:43 +04:00
bool continue_next_line = 0 ;
2007-08-26 19:16:40 +04:00
line = afdgets ( fd , mem_ctx , 0 ) ;
if ( ! line ) {
DEBUG ( 0 , ( " Can't read from file. \n " ) ) ;
talloc_free ( mem_ctx ) ;
close ( fd ) ;
2015-12-03 17:24:21 +03:00
return WERR_GEN_FAILURE ;
2007-08-26 19:16:40 +04:00
}
while ( ( line = afdgets ( fd , mem_ctx , 0 ) ) ) {
2010-07-27 00:10:43 +04:00
/* Remove '\r' if it's a Windows text file */
2016-04-15 14:51:32 +03:00
if ( strlen ( line ) & & line [ strlen ( line ) - 1 ] = = ' \r ' ) {
2010-07-27 00:10:43 +04:00
line [ strlen ( line ) - 1 ] = ' \0 ' ;
}
2007-08-26 19:16:40 +04:00
/* Ignore comments and empty lines */
if ( strlen ( line ) = = 0 | | line [ 0 ] = = ' ; ' ) {
talloc_free ( line ) ;
2007-10-06 04:17:44 +04:00
if ( curkey ) {
2007-08-26 19:16:40 +04:00
talloc_free ( curkey ) ;
}
curkey = NULL ;
continue ;
}
/* Start of key */
if ( line [ 0 ] = = ' [ ' ) {
2010-07-27 00:10:43 +04:00
if ( line [ strlen ( line ) - 1 ] ! = ' ] ' ) {
DEBUG ( 0 , ( " Missing ']' on line: %s \n " , line ) ) ;
talloc_free ( line ) ;
continue ;
2007-08-26 19:16:40 +04:00
}
2010-07-27 00:10:43 +04:00
2007-08-26 19:16:40 +04:00
/* Deleting key */
if ( line [ 1 ] = = ' - ' ) {
curkey = talloc_strndup ( line , line + 2 , strlen ( line ) - 3 ) ;
2010-03-22 22:10:26 +03:00
W_ERROR_HAVE_NO_MEMORY ( curkey ) ;
2007-08-26 19:16:40 +04:00
2007-10-06 04:17:44 +04:00
error = callbacks - > del_key ( callback_data ,
curkey ) ;
2010-03-22 22:10:26 +03:00
2007-08-26 19:16:40 +04:00
if ( ! W_ERROR_IS_OK ( error ) ) {
2007-10-06 04:17:44 +04:00
DEBUG ( 0 , ( " Error deleting key %s \n " ,
curkey ) ) ;
2007-08-26 19:16:40 +04:00
talloc_free ( mem_ctx ) ;
return error ;
}
talloc_free ( line ) ;
curkey = NULL ;
continue ;
}
curkey = talloc_strndup ( mem_ctx , line + 1 , strlen ( line ) - 2 ) ;
2010-03-22 22:10:26 +03:00
W_ERROR_HAVE_NO_MEMORY ( curkey ) ;
2007-08-26 19:16:40 +04:00
error = callbacks - > add_key ( callback_data , curkey ) ;
if ( ! W_ERROR_IS_OK ( error ) ) {
DEBUG ( 0 , ( " Error adding key %s \n " , curkey ) ) ;
talloc_free ( mem_ctx ) ;
return error ;
}
talloc_free ( line ) ;
continue ;
}
/* Deleting/Changing value */
2010-07-27 00:10:43 +04:00
if ( continue_next_line ) {
continue_next_line = 0 ;
2007-08-26 19:16:40 +04:00
2010-07-27 00:10:43 +04:00
/* Continued data start with two whitespaces */
if ( line [ 0 ] ! = ' ' | | line [ 1 ] ! = ' ' ) {
DEBUG ( 0 , ( " Malformed line: %s \n " , line ) ) ;
talloc_free ( line ) ;
continue ;
}
p = line + 2 ;
2007-08-26 19:16:40 +04:00
2010-07-27 00:10:43 +04:00
/* Continue again if line ends with a backslash */
if ( line [ strlen ( line ) - 1 ] = = ' \\ ' ) {
line [ strlen ( line ) - 1 ] = ' \0 ' ;
continue_next_line = 1 ;
data_str = talloc_strdup_append ( data_str , p ) ;
talloc_free ( line ) ;
continue ;
}
data_str = talloc_strdup_append ( data_str , p ) ;
} else {
p = strchr_m ( line , ' = ' ) ;
if ( p = = NULL ) {
DEBUG ( 0 , ( " Malformed line: %s \n " , line ) ) ;
talloc_free ( line ) ;
continue ;
}
* p = ' \0 ' ; p + + ;
if ( curkey = = NULL ) {
DEBUG ( 0 , ( " Value change without key \n " ) ) ;
talloc_free ( line ) ;
continue ;
}
2007-08-26 19:16:40 +04:00
2010-07-27 00:10:43 +04:00
/* Values should be double-quoted */
if ( line [ 0 ] ! = ' " ' ) {
DEBUG ( 0 , ( " Malformed line \n " ) ) ;
talloc_free ( line ) ;
continue ;
}
/* Chop of the quotes and store as value */
value = talloc_strndup ( mem_ctx , line + 1 , strlen ( line ) - 2 ) ;
/* Delete value */
if ( p [ 0 ] = = ' - ' ) {
error = callbacks - > del_value ( callback_data ,
2010-07-27 19:21:48 +04:00
curkey , value ) ;
2010-07-27 00:10:43 +04:00
2015-12-03 17:24:12 +03:00
/* Ignore if key does not exist (WERR_FILE_NOT_FOUND)
2010-07-27 00:10:43 +04:00
* Consistent with Windows behaviour */
if ( ! W_ERROR_IS_OK ( error ) & &
2015-12-03 17:24:12 +03:00
! W_ERROR_EQUAL ( error , WERR_FILE_NOT_FOUND ) ) {
2010-07-27 00:10:43 +04:00
DEBUG ( 0 , ( " Error deleting value %s in key %s \n " ,
2010-07-27 19:21:48 +04:00
value , curkey ) ) ;
2010-07-27 00:10:43 +04:00
talloc_free ( mem_ctx ) ;
return error ;
}
talloc_free ( line ) ;
talloc_free ( value ) ;
continue ;
2007-08-26 19:16:40 +04:00
}
2010-07-27 00:10:43 +04:00
/* Do not look for colons in strings */
if ( p [ 0 ] = = ' " ' ) {
q = NULL ;
2010-08-30 14:21:29 +04:00
data_str = talloc_strndup ( mem_ctx , p + 1 , strlen ( p ) - 2 ) ;
2010-07-27 00:10:43 +04:00
} else {
/* Split the value type from the data */
q = strchr_m ( p , ' : ' ) ;
if ( q ) {
* q = ' \0 ' ;
q + + ;
type_str = talloc_strdup ( mem_ctx , p ) ;
data_str = talloc_strdup ( mem_ctx , q ) ;
} else {
data_str = talloc_strdup ( mem_ctx , p ) ;
}
}
2007-10-06 04:17:44 +04:00
2010-07-27 00:10:43 +04:00
/* Backslash before the CRLF means continue on next line */
if ( data_str [ strlen ( data_str ) - 1 ] = = ' \\ ' ) {
data_str [ strlen ( data_str ) - 1 ] = ' \0 ' ;
talloc_free ( line ) ;
continue_next_line = 1 ;
continue ;
}
}
DEBUG ( 9 , ( " About to write %s with type %s, length %ld: %s \n " , value , type_str , ( long ) strlen ( data_str ) , data_str ) ) ;
result = reg_string_to_val ( value ,
type_str ? type_str : " REG_SZ " , data_str ,
& value_type , & data ) ;
if ( ! result ) {
DEBUG ( 0 , ( " Error converting string to value for line: \n %s \n " ,
line ) ) ;
2015-12-03 17:24:21 +03:00
return WERR_GEN_FAILURE ;
2007-08-26 19:16:40 +04:00
}
2007-10-06 04:17:44 +04:00
2010-07-27 19:21:48 +04:00
error = callbacks - > set_value ( callback_data , curkey , value ,
2010-07-27 00:10:43 +04:00
value_type , data ) ;
2007-08-26 19:16:40 +04:00
if ( ! W_ERROR_IS_OK ( error ) ) {
2007-10-06 04:17:44 +04:00
DEBUG ( 0 , ( " Error setting value for %s in %s \n " ,
2010-07-27 19:21:48 +04:00
value , curkey ) ) ;
2007-08-26 19:16:40 +04:00
talloc_free ( mem_ctx ) ;
return error ;
}
2010-07-27 00:10:43 +04:00
/* Clean up buffers */
if ( type_str ! = NULL ) {
talloc_free ( type_str ) ;
type_str = NULL ;
}
talloc_free ( data_str ) ;
talloc_free ( value ) ;
2007-08-26 19:16:40 +04:00
talloc_free ( line ) ;
}
close ( fd ) ;
2010-07-27 00:10:43 +04:00
talloc_free ( mem_ctx ) ;
2007-08-26 19:16:40 +04:00
return WERR_OK ;
}