2016-09-15 14:36:35 +03:00
/*
Unix SMB / CIFS implementation .
routines for marshalling / unmarshalling cab structures
Copyright ( C ) Guenther Deschner 2016
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
the Free Software Foundation ; either version 3 of the License , or
( 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
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "librpc/gen_ndr/ndr_cab.h"
_PUBLIC_ void ndr_print_cf_time ( struct ndr_print * ndr , const char * name , const struct cf_time * r )
{
uint8_t hour = 0 , minute = 0 , seconds = 0 ;
char * s ;
if ( r = = NULL ) { ndr_print_null ( ndr ) ; return ; }
hour = r - > time > > 11 ;
minute = ( r - > time > > 5 ) & 0x3f ;
seconds = ( r - > time < < 1 ) & 0x3e ;
s = talloc_asprintf ( ndr , " %02d:%02d:%02d " , hour , minute , seconds ) ;
if ( s = = NULL ) { return ; }
ndr_print_string ( ndr , " time " , s ) ;
talloc_free ( s ) ;
}
_PUBLIC_ void ndr_print_cf_date ( struct ndr_print * ndr , const char * name , const struct cf_date * r )
{
uint16_t year = 0 ;
uint8_t month = 0 , day = 0 ;
char * s ;
if ( r = = NULL ) { ndr_print_null ( ndr ) ; return ; }
year = ( r - > date > > 9 ) ;
year + = 1980 ;
month = ( r - > date > > 5 & 0xf ) ;
day = ( r - > date & 0x1f ) ;
s = talloc_asprintf ( ndr , " %02d/%02d/%04d " , day , month , year ) ;
if ( s = = NULL ) { return ; }
ndr_print_string ( ndr , " date " , s ) ;
talloc_free ( s ) ;
}
uint32_t ndr_count_cfdata ( const struct cab_file * r )
{
uint32_t count = 0 , i ;
for ( i = 0 ; i < r - > cfheader . cFolders ; i + + ) {
2016-11-30 20:19:43 +03:00
if ( count + r - > cffolders [ i ] . cCFData < count ) {
/* Integer wrap. */
return 0 ;
}
2016-09-15 14:36:35 +03:00
count + = r - > cffolders [ i ] . cCFData ;
}
return count ;
}
2016-09-16 01:15:30 +03:00
static uint32_t ndr_cab_compute_checksum ( uint8_t * data , uint32_t length , uint32_t seed )
{
int num_ulong ;
uint32_t checksum ;
uint8_t * pb ;
uint32_t ul ;
num_ulong = length / 4 ;
checksum = seed ;
pb = data ;
while ( num_ulong - - > 0 ) {
ul = * pb + + ;
ul | = ( ( ( uint32_t ) ( * pb + + ) ) < < 8 ) ;
ul | = ( ( ( uint32_t ) ( * pb + + ) ) < < 16 ) ;
ul | = ( ( ( uint32_t ) ( * pb + + ) ) < < 24 ) ;
checksum ^ = ul ;
}
ul = 0 ;
switch ( length % 4 ) {
case 3 :
ul | = ( ( ( uint32_t ) ( * pb + + ) ) < < 16 ) ;
case 2 :
ul | = ( ( ( uint32_t ) ( * pb + + ) ) < < 8 ) ;
case 1 :
ul | = * pb + + ;
default :
break ;
}
checksum ^ = ul ;
return checksum ;
}
uint32_t ndr_cab_generate_checksum ( const struct CFDATA * r )
{
uint32_t csumPartial ;
csumPartial = ndr_cab_compute_checksum ( & r - > ab [ 0 ] , r - > cbData , 0 ) ;
return ndr_cab_compute_checksum ( ( uint8_t * ) discard_const ( & r - > cbData ) ,
sizeof ( r - > cbData ) + sizeof ( r - > cbUncomp ) ,
csumPartial ) ;
}
2016-11-30 20:23:52 +03:00
static bool ndr_size_cab_file ( const struct cab_file * r , uint32_t * psize )
2016-09-21 02:46:54 +03:00
{
uint32_t size = 0 ;
int i ;
/* header */
size + = 36 ;
/* folder */
for ( i = 0 ; i < r - > cfheader . cFolders ; i + + ) {
2016-11-30 20:23:52 +03:00
if ( size + 8 < size ) {
/* Integer wrap. */
return false ;
}
2016-09-21 02:46:54 +03:00
size + = 8 ;
}
/* files */
for ( i = 0 ; i < r - > cfheader . cFiles ; i + + ) {
2016-11-30 20:23:52 +03:00
uint32_t cfsize = ndr_size_CFFILE ( & r - > cffiles [ i ] , 0 ) ;
if ( size + cfsize < size ) {
/* Integer wrap. */
return false ;
}
size + = cfsize ;
2016-09-21 02:46:54 +03:00
}
/* data */
for ( i = 0 ; i < ndr_count_cfdata ( r ) ; i + + ) {
2016-11-30 20:23:52 +03:00
if ( size + 8 < size ) {
/* Integer wrap. */
return false ;
}
size + = 8 ;
if ( size + r - > cfdata [ i ] . cbData < size ) {
/* Integer wrap. */
return false ;
}
size + = r - > cfdata [ i ] . cbData ;
2016-09-21 02:46:54 +03:00
}
2016-11-30 20:23:52 +03:00
* psize = size ;
return true ;
2016-09-21 02:46:54 +03:00
}
2016-09-20 01:20:18 +03:00
enum cf_compress_type ndr_cab_get_compression ( const struct cab_file * r )
{
if ( r - > cfheader . cFolders = = 0 ) {
return CF_COMPRESS_NONE ;
}
return r - > cffolders [ 0 ] . typeCompress ;
}
2016-09-15 14:36:35 +03:00
_PUBLIC_ enum ndr_err_code ndr_push_cab_file ( struct ndr_push * ndr , int ndr_flags , const struct cab_file * r )
{
uint32_t cntr_cffolders_0 ;
uint32_t cntr_cffiles_0 ;
uint32_t cntr_cfdata_0 ;
2016-11-30 20:23:52 +03:00
uint32_t cab_size = 0 ;
2016-09-15 14:36:35 +03:00
{
uint32_t _flags_save_STRUCT = ndr - > flags ;
ndr_set_flags ( & ndr - > flags , LIBNDR_PRINT_ARRAY_HEX | LIBNDR_FLAG_LITTLE_ENDIAN | LIBNDR_FLAG_NOALIGN ) ;
NDR_PUSH_CHECK_FLAGS ( ndr , ndr_flags ) ;
if ( ndr_flags & NDR_SCALARS ) {
2016-09-24 03:51:20 +03:00
uint32_t next_offset = 0 ;
2016-09-15 14:36:35 +03:00
NDR_CHECK ( ndr_push_align ( ndr , 4 ) ) ;
NDR_CHECK ( ndr_push_CFHEADER ( ndr , NDR_SCALARS , & r - > cfheader ) ) ;
for ( cntr_cffolders_0 = 0 ; cntr_cffolders_0 < ( r - > cfheader . cFolders ) ; cntr_cffolders_0 + + ) {
NDR_CHECK ( ndr_push_CFFOLDER ( ndr , NDR_SCALARS , & r - > cffolders [ cntr_cffolders_0 ] ) ) ;
}
for ( cntr_cffiles_0 = 0 ; cntr_cffiles_0 < ( r - > cfheader . cFiles ) ; cntr_cffiles_0 + + ) {
2016-09-24 03:51:20 +03:00
uint32_t offset = ndr - > offset + 4 ;
2016-09-15 14:36:35 +03:00
NDR_CHECK ( ndr_push_CFFILE ( ndr , NDR_SCALARS , & r - > cffiles [ cntr_cffiles_0 ] ) ) ;
2016-09-24 03:51:20 +03:00
if ( cntr_cffiles_0 > 0 ) {
next_offset + = r - > cffiles [ cntr_cffiles_0 - 1 ] . cbFile ;
}
SIVAL ( ndr - > data , offset , next_offset ) ;
2016-09-15 14:36:35 +03:00
}
#if 0
NDR_CHECK ( ndr_push_uint32 ( ndr , NDR_SCALARS , ndr_count_cfdata ( r ) ) ) ;
# endif
for ( cntr_cfdata_0 = 0 ; cntr_cfdata_0 < ( ndr_count_cfdata ( r ) ) ; cntr_cfdata_0 + + ) {
NDR_CHECK ( ndr_push_CFDATA ( ndr , NDR_SCALARS , & r - > cfdata [ cntr_cfdata_0 ] ) ) ;
}
NDR_CHECK ( ndr_push_trailer_align ( ndr , 4 ) ) ;
}
if ( ndr_flags & NDR_BUFFERS ) {
}
ndr - > flags = _flags_save_STRUCT ;
}
2016-09-21 02:46:54 +03:00
2016-11-30 20:23:52 +03:00
if ( ndr_size_cab_file ( r , & cab_size ) = = false ) {
return NDR_ERR_VALIDATE ;
}
SIVAL ( ndr - > data , 8 , cab_size ) ;
2016-09-21 02:46:54 +03:00
2016-09-15 14:36:35 +03:00
return NDR_ERR_SUCCESS ;
}
_PUBLIC_ enum ndr_err_code ndr_pull_cab_file ( struct ndr_pull * ndr , int ndr_flags , struct cab_file * r )
{
uint32_t size_cffolders_0 = 0 ;
uint32_t cntr_cffolders_0 ;
TALLOC_CTX * _mem_save_cffolders_0 = NULL ;
uint32_t size_cffiles_0 = 0 ;
uint32_t cntr_cffiles_0 ;
TALLOC_CTX * _mem_save_cffiles_0 = NULL ;
uint32_t size_cfdata_0 = 0 ;
uint32_t cntr_cfdata_0 ;
TALLOC_CTX * _mem_save_cfdata_0 = NULL ;
{
uint32_t _flags_save_STRUCT = ndr - > flags ;
ndr_set_flags ( & ndr - > flags , LIBNDR_PRINT_ARRAY_HEX | LIBNDR_FLAG_LITTLE_ENDIAN | LIBNDR_FLAG_NOALIGN ) ;
NDR_PULL_CHECK_FLAGS ( ndr , ndr_flags ) ;
if ( ndr_flags & NDR_SCALARS ) {
NDR_CHECK ( ndr_pull_align ( ndr , 4 ) ) ;
NDR_CHECK ( ndr_pull_CFHEADER ( ndr , NDR_SCALARS , & r - > cfheader ) ) ;
size_cffolders_0 = r - > cfheader . cFolders ;
NDR_PULL_ALLOC_N ( ndr , r - > cffolders , size_cffolders_0 ) ;
_mem_save_cffolders_0 = NDR_PULL_GET_MEM_CTX ( ndr ) ;
NDR_PULL_SET_MEM_CTX ( ndr , r - > cffolders , 0 ) ;
for ( cntr_cffolders_0 = 0 ; cntr_cffolders_0 < ( size_cffolders_0 ) ; cntr_cffolders_0 + + ) {
NDR_CHECK ( ndr_pull_CFFOLDER ( ndr , NDR_SCALARS , & r - > cffolders [ cntr_cffolders_0 ] ) ) ;
}
NDR_PULL_SET_MEM_CTX ( ndr , _mem_save_cffolders_0 , 0 ) ;
size_cffiles_0 = r - > cfheader . cFiles ;
NDR_PULL_ALLOC_N ( ndr , r - > cffiles , size_cffiles_0 ) ;
_mem_save_cffiles_0 = NDR_PULL_GET_MEM_CTX ( ndr ) ;
NDR_PULL_SET_MEM_CTX ( ndr , r - > cffiles , 0 ) ;
for ( cntr_cffiles_0 = 0 ; cntr_cffiles_0 < ( size_cffiles_0 ) ; cntr_cffiles_0 + + ) {
NDR_CHECK ( ndr_pull_CFFILE ( ndr , NDR_SCALARS , & r - > cffiles [ cntr_cffiles_0 ] ) ) ;
}
NDR_PULL_SET_MEM_CTX ( ndr , _mem_save_cffiles_0 , 0 ) ;
#if 0
NDR_CHECK ( ndr_pull_uint32 ( ndr , NDR_SCALARS , & r - > cfdata_count ) ) ;
# else
r - > cfdata_count = ndr_count_cfdata ( r ) ;
# endif
size_cfdata_0 = r - > cfdata_count ;
NDR_PULL_ALLOC_N ( ndr , r - > cfdata , size_cfdata_0 ) ;
_mem_save_cfdata_0 = NDR_PULL_GET_MEM_CTX ( ndr ) ;
NDR_PULL_SET_MEM_CTX ( ndr , r - > cfdata , 0 ) ;
for ( cntr_cfdata_0 = 0 ; cntr_cfdata_0 < ( size_cfdata_0 ) ; cntr_cfdata_0 + + ) {
NDR_CHECK ( ndr_pull_CFDATA ( ndr , NDR_SCALARS , & r - > cfdata [ cntr_cfdata_0 ] ) ) ;
}
NDR_PULL_SET_MEM_CTX ( ndr , _mem_save_cfdata_0 , 0 ) ;
NDR_CHECK ( ndr_pull_trailer_align ( ndr , 4 ) ) ;
}
if ( ndr_flags & NDR_BUFFERS ) {
}
ndr - > flags = _flags_save_STRUCT ;
}
return NDR_ERR_SUCCESS ;
}