2012-01-12 03:38:24 +00:00
/*
Serval Distributed Numbering Architecture ( DNA )
Copyright ( C ) 2010 Paul Gardner - Stephen
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 2
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 , write to the Free Software
Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*/
2012-02-23 02:15:42 +00:00
# include "serval.h"
2012-01-12 03:38:24 +00:00
# include "rhizome.h"
# include <stdlib.h>
2012-05-25 23:54:47 +00:00
int rhizome_manifest_verify ( rhizome_manifest * m )
{
int end_of_text = 0 ;
/* find end of manifest body and start of signatures */
while ( m - > manifestdata [ end_of_text ] & & end_of_text < m - > manifest_all_bytes )
end_of_text + + ;
end_of_text + + ; /* include null byte in body for verification purposes */
/* Calculate hash of the text part of the file, as we need to couple this with
each signature block to */
crypto_hash_sha512 ( m - > manifesthash , m - > manifestdata , end_of_text ) ;
/* Read signature blocks from file. */
2012-05-26 00:04:12 +00:00
int ofs = end_of_text ;
2012-05-25 23:54:47 +00:00
while ( ofs < m - > manifest_all_bytes ) {
if ( debug & DEBUG_RHIZOME ) DEBUGF ( " ofs=0x%x, m->manifest_bytes=0x%x " , ofs , m - > manifest_all_bytes ) ;
if ( rhizome_manifest_extract_signature ( m , & ofs ) ) break ;
}
if ( m - > sig_count = = 0 ) {
m - > errors + + ;
}
/* Make sure that id variable is correct */
{
char * id = rhizome_manifest_get ( m , " id " , NULL , 0 ) ;
if ( ! id ) {
WARN ( " Manifest lacks 'id' field " ) ;
m - > errors + + ;
}
else {
unsigned char manifest_bytes [ crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES ] ;
rhizome_hex_to_bytes ( id , manifest_bytes ,
crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2 ) ;
if ( ( m - > sig_count = = 0 ) | |
memcmp ( & m - > signatories [ 0 ] [ 0 ] , manifest_bytes ,
crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES ) )
{
if ( debug & DEBUG_RHIZOME ) {
if ( m - > sig_count > 0 ) {
DEBUGF ( " Manifest id variable does not match first signature block (signature key is %s) " ,
/* XXX bit of a hack that relies on SIDs and signing public keys being the same length */
overlay_render_sid ( & m - > signatories [ 0 ] [ 0 ] )
) ;
} else {
DEBUG ( " Manifest has no signature blocks, but should have self-signature block " ) ;
}
}
m - > errors + + ;
m - > selfSigned = 0 ;
} else m - > selfSigned = 1 ;
}
}
/* Mark as finalised, as it is all read and intact,
unless of course it has errors , or is lacking a self - signature . */
if ( ! m - > errors ) m - > finalised = 1 ;
else WHY ( " Verified a manifest that has errors, so marking as not finalised " ) ;
if ( m - > errors ) return WHY ( " Manifest verification failed " ) ;
else return 0 ;
}
int rhizome_read_manifest_file ( rhizome_manifest * m , const char * filename , int bufferP )
2012-01-12 03:38:24 +00:00
{
2012-05-25 06:08:13 +00:00
if ( bufferP > MAX_MANIFEST_BYTES ) return WHY ( " Buffer too big " ) ;
if ( ! m ) return WHY ( " Null manifest " ) ;
2012-01-12 03:38:24 +00:00
if ( bufferP ) {
m - > manifest_bytes = bufferP ;
2012-04-02 08:12:40 +00:00
memcpy ( m - > manifestdata , filename , m - > manifest_bytes ) ;
2012-05-20 14:39:14 +00:00
} else {
2012-05-25 06:08:13 +00:00
FILE * f = fopen ( filename , " r " ) ;
if ( f = = NULL )
return WHYF ( " Could not open manifest file %s for reading. " , filename ) ;
m - > manifest_bytes = fread ( m - > manifestdata , 1 , MAX_MANIFEST_BYTES , f ) ;
int ret = 0 ;
if ( m - > manifest_bytes = = - 1 )
ret = WHY_perror ( " fread " ) ;
if ( fclose ( f ) = = EOF )
ret = WHY_perror ( " fclose " ) ;
if ( ret = = - 1 )
return - 1 ;
2012-01-12 03:38:24 +00:00
}
2012-01-13 10:43:17 +00:00
m - > manifest_all_bytes = m - > manifest_bytes ;
2012-01-12 03:38:24 +00:00
/* Parse out variables, signature etc */
int ofs = 0 ;
while ( ( ofs < m - > manifest_bytes ) & & ( m - > manifestdata [ ofs ] ) )
{
int i ;
char line [ 1024 ] , var [ 1024 ] , value [ 1024 ] ;
while ( ( ofs < m - > manifest_bytes ) & &
( m - > manifestdata [ ofs ] = = 0x0a | |
m - > manifestdata [ ofs ] = = 0x09 | |
m - > manifestdata [ ofs ] = = 0x20 | |
m - > manifestdata [ ofs ] = = 0x0d ) ) ofs + + ;
for ( i = 0 ; ( i < ( m - > manifest_bytes - ofs ) )
& & ( i < 1023 )
& & ( m - > manifestdata [ ofs + i ] ! = 0x00 )
& & ( m - > manifestdata [ ofs + i ] ! = 0x0d )
& & ( m - > manifestdata [ ofs + i ] ! = 0x0a ) ; i + + )
line [ i ] = m - > manifestdata [ ofs + i ] ;
ofs + = i ;
line [ i ] = 0 ;
/* Ignore blank lines */
if ( line [ 0 ] = = 0 ) continue ;
2012-03-29 03:37:07 +00:00
/* Ignore comment lines */
if ( line [ 0 ] = = ' # ' | | line [ 0 ] = = ' ! ' ) continue ;
/* Parse property lines */
/* This could be improved to parse Java's Properties.store() output, by handling backlash
escapes and continuation lines */
2012-05-20 14:39:14 +00:00
if ( sscanf ( line , " %[^=]=%[^ \n \r ] " , var , value ) = = 2 ) {
if ( rhizome_manifest_get ( m , var , NULL , 0 ) ) {
WARNF ( " Ill formed manifest file, duplicate variable \" %s \" -- keeping first value) " , var ) ;
m - > errors + + ;
} else if ( m - > var_count < MAX_MANIFEST_VARS ) {
/*`
if ( debug & DEBUG_RHIZOME ) {
char buf [ 80 ] ;
DEBUGF ( " read manifest line: %s=%s " , var , catv ( value , buf , sizeof buf ) ) ;
2012-01-12 03:38:24 +00:00
}
2012-05-20 14:39:14 +00:00
*/
m - > vars [ m - > var_count ] = strdup ( var ) ;
m - > values [ m - > var_count ] = strdup ( value ) ;
2012-05-26 02:25:56 +00:00
if ( ! strcasecmp ( var , " ID " ) )
{
/* Parse hex string of ID into public key */
rhizome_hex_to_bytes ( value , m - > cryptoSignPublic ,
2012-05-27 15:56:11 +00:00
crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES * 2 ) ;
}
if ( ( ! strcasecmp ( var , " ID " ) ) | | ( ! strcasecmp ( var , " FILEHASH " ) ) ) {
/* Also force to upper case to avoid case sensitive comparison problems later. */
int i ;
for ( i = 0 ; i < strlen ( m - > vars [ m - > var_count ] ) ; i + + )
m - > values [ m - > var_count ] [ i ] = toupper ( m - > values [ m - > var_count ] [ i ] ) ;
2012-05-26 02:25:56 +00:00
}
2012-05-20 14:39:14 +00:00
m - > var_count + + ;
2012-01-12 03:38:24 +00:00
}
2012-05-20 14:39:14 +00:00
} else {
char buf [ 80 ] ;
2012-05-22 04:50:01 +00:00
if ( 0 ) WARNF ( " Skipping malformed line in manifest file %s: %s " , bufferP ? " <buffer> " : filename , catv ( line , buf , sizeof buf ) ) ;
2012-05-20 14:39:14 +00:00
}
2012-01-12 03:38:24 +00:00
}
/* The null byte gets included in the check sum */
if ( ofs < m - > manifest_bytes ) ofs + + ;
/* Remember where the text ends */
int end_of_text = ofs ;
2012-05-26 02:48:49 +00:00
# warning DEBUG("Group membership determination not implemented (see which signatories are groups? what about manifests signed by groups we don't yet know about?)");
2012-01-12 03:38:24 +00:00
m - > manifest_bytes = end_of_text ;
2012-05-25 06:08:13 +00:00
return 0 ;
2012-01-12 03:38:24 +00:00
}
2012-05-02 08:27:35 +00:00
int rhizome_strn_is_file_hash ( const char * text )
{
int i ;
2012-05-23 06:34:00 +00:00
for ( i = 0 ; i ! = RHIZOME_FILEHASH_STRLEN ; + + i )
2012-05-02 08:27:35 +00:00
if ( ! isxdigit ( text [ i ] ) )
return 0 ;
return 1 ;
}
int rhizome_str_is_file_hash ( const char * text )
{
size_t len = strlen ( text ) ;
2012-05-23 06:34:00 +00:00
return len = = RHIZOME_FILEHASH_STRLEN & & rhizome_strn_is_file_hash ( text ) ;
2012-05-02 08:27:35 +00:00
}
2012-05-25 15:20:48 +00:00
int rhizome_hash_file ( rhizome_manifest * m , const char * filename , char * hash_out )
2012-01-12 03:38:24 +00:00
{
/* Gnarf! NaCl's crypto_hash() function needs the whole file passed in in one
go . Trouble is , we need to run Serval DNA on filesystems that lack mmap ( ) ,
and may be very resource constrained . Thus we need a streamable SHA - 512
implementation .
*/
2012-06-05 06:15:53 +00:00
// TODO encrypted payloads
if ( m & & m - > payloadEncryption )
2012-05-25 15:20:48 +00:00
return WHY ( " Encryption of payloads not implemented " ) ;
2012-01-12 03:38:24 +00:00
SHA512_CTX context ;
SHA512_Init ( & context ) ;
2012-06-05 06:15:53 +00:00
if ( filename [ 0 ] ) {
FILE * f = fopen ( filename , " r " ) ;
if ( ! f ) {
WHY_perror ( " fopen " ) ;
return WHYF ( " Could not open %s to calculate SHA512 hash. " , filename ) ;
2012-05-21 03:46:44 +00:00
}
2012-06-05 06:15:53 +00:00
while ( ! feof ( f ) ) {
unsigned char buffer [ 8192 ] ;
int r = fread ( buffer , 1 , 8192 , f ) ;
if ( r = = - 1 ) {
WHY_perror ( " fread " ) ;
fclose ( f ) ;
return WHYF ( " Error reading %s to calculate SHA512 hash " , filename ) ;
}
if ( r > 0 )
SHA512_Update ( & context , buffer , r ) ;
}
fclose ( f ) ;
2012-01-12 03:38:24 +00:00
}
2012-04-12 09:00:52 +00:00
SHA512_End ( & context , ( char * ) hash_out ) ;
2012-05-23 06:34:00 +00:00
str_toupper_inplace ( hash_out ) ;
2012-01-12 03:38:24 +00:00
return 0 ;
}
2012-04-12 09:00:52 +00:00
char * rhizome_manifest_get ( const rhizome_manifest * m , const char * var , char * out , int maxlen )
2012-01-12 03:38:24 +00:00
{
int i , j ;
if ( ! m ) return NULL ;
for ( i = 0 ; i < m - > var_count ; i + + )
if ( ! strcmp ( m - > vars [ i ] , var ) ) {
if ( out ) {
for ( j = 0 ; ( j < maxlen ) ; j + + ) {
out [ j ] = m - > values [ i ] [ j ] ;
if ( ! out [ j ] ) break ;
}
}
return m - > values [ i ] ;
}
return NULL ;
}
2012-04-12 09:00:52 +00:00
long long rhizome_manifest_get_ll ( rhizome_manifest * m , const char * var )
2012-01-12 03:38:24 +00:00
{
2012-04-12 09:00:52 +00:00
if ( ! m )
return - 1 ;
2012-01-12 03:38:24 +00:00
int i ;
2012-04-12 09:00:52 +00:00
for ( i = 0 ; i ! = m - > var_count ; + + i )
if ( ! strcmp ( m - > vars [ i ] , var ) ) {
char * vp = m - > values [ i ] ;
char * ep = vp ;
long long val = strtoll ( vp , & ep , 10 ) ;
return ( ep ! = vp & & * ep = = ' \0 ' ) ? val : - 1 ;
}
2012-01-12 03:38:24 +00:00
return - 1 ;
}
double rhizome_manifest_get_double ( rhizome_manifest * m , char * var , double default_value )
{
int i ;
if ( ! m ) return default_value ;
for ( i = 0 ; i < m - > var_count ; i + + )
if ( ! strcmp ( m - > vars [ i ] , var ) )
return strtod ( m - > values [ i ] , NULL ) ;
return default_value ;
}
2012-04-02 08:12:40 +00:00
int rhizome_manifest_set ( rhizome_manifest * m , const char * var , const char * value )
2012-01-12 03:38:24 +00:00
{
int i ;
if ( ! m ) return - 1 ;
for ( i = 0 ; i < m - > var_count ; i + + )
if ( ! strcmp ( m - > vars [ i ] , var ) ) {
free ( m - > values [ i ] ) ;
m - > values [ i ] = strdup ( value ) ;
m - > finalised = 0 ;
return 0 ;
}
if ( m - > var_count > = MAX_MANIFEST_VARS ) return - 1 ;
m - > vars [ m - > var_count ] = strdup ( var ) ;
m - > values [ m - > var_count ] = strdup ( value ) ;
m - > var_count + + ;
m - > finalised = 0 ;
return 0 ;
}
int rhizome_manifest_set_ll ( rhizome_manifest * m , char * var , long long value )
{
char svalue [ 100 ] ;
snprintf ( svalue , 100 , " %lld " , value ) ;
return rhizome_manifest_set ( m , var , svalue ) ;
}
2012-01-28 01:15:45 +00:00
rhizome_manifest manifests [ MAX_RHIZOME_MANIFESTS ] ;
char manifest_free [ MAX_RHIZOME_MANIFESTS ] ;
int manifest_first_free = - 1 ;
const char * manifest_alloc_sourcefiles [ MAX_RHIZOME_MANIFESTS ] ;
const char * manifest_alloc_functions [ MAX_RHIZOME_MANIFESTS ] ;
int manifest_alloc_lines [ MAX_RHIZOME_MANIFESTS ] ;
const char * manifest_free_sourcefiles [ MAX_RHIZOME_MANIFESTS ] ;
const char * manifest_free_functions [ MAX_RHIZOME_MANIFESTS ] ;
int manifest_free_lines [ MAX_RHIZOME_MANIFESTS ] ;
2012-05-25 07:31:56 +00:00
static void _log_manifest_trace ( const char * filename , const char * funcname , int line , const char * operation )
{
int count_free = 0 ;
int i ;
for ( i = 0 ; i ! = MAX_RHIZOME_MANIFESTS ; + + i )
if ( manifest_free [ i ] )
+ + count_free ;
logMessage ( LOG_LEVEL_DEBUG , filename , line , funcname , " %s(): count_free = %d " , operation , count_free ) ;
}
2012-05-24 07:41:55 +00:00
rhizome_manifest * _rhizome_new_manifest ( const char * filename , const char * funcname , int line )
2012-01-12 03:38:24 +00:00
{
2012-01-28 01:15:45 +00:00
if ( manifest_first_free < 0 ) {
/* Setup structures */
int i ;
for ( i = 0 ; i < MAX_RHIZOME_MANIFESTS ; i + + ) {
manifest_alloc_sourcefiles [ i ] = " <never allocated> " ;
manifest_alloc_functions [ i ] = " <never allocated> " ;
manifest_alloc_lines [ i ] = - 1 ;
manifest_free_sourcefiles [ i ] = " <never freed> " ;
manifest_free_functions [ i ] = " <never freed> " ;
manifest_free_lines [ i ] = - 1 ;
manifest_free [ i ] = 1 ;
}
manifest_first_free = 0 ;
}
2012-01-12 03:38:24 +00:00
2012-01-28 01:15:45 +00:00
/* No free manifests */
if ( manifest_first_free > = MAX_RHIZOME_MANIFESTS )
{
int i ;
2012-05-24 07:41:55 +00:00
logMessage ( LOG_LEVEL_ERROR , filename , line , funcname , " %s(): no free manifest records, this probably indicates a memory leak " , __FUNCTION__ ) ;
2012-05-25 06:08:13 +00:00
WHYF ( " Slot# | Last allocated by " ) ;
2012-01-28 01:15:45 +00:00
for ( i = 0 ; i < MAX_RHIZOME_MANIFESTS ; i + + ) {
2012-05-25 06:08:13 +00:00
WHYF ( " %-5d | %s:%d in %s() " ,
2012-01-28 01:15:45 +00:00
i ,
manifest_alloc_sourcefiles [ i ] ,
manifest_alloc_lines [ i ] ,
2012-05-24 07:41:55 +00:00
manifest_alloc_functions [ i ]
) ;
2012-01-28 01:15:45 +00:00
}
return NULL ;
}
rhizome_manifest * m = & manifests [ manifest_first_free ] ;
bzero ( m , sizeof ( rhizome_manifest ) ) ;
m - > manifest_record_number = manifest_first_free ;
/* Indicate where manifest was allocated, and that it is no longer
free . */
manifest_alloc_sourcefiles [ manifest_first_free ] = filename ;
manifest_alloc_lines [ manifest_first_free ] = line ;
manifest_alloc_functions [ manifest_first_free ] = funcname ;
manifest_free [ manifest_first_free ] = 0 ;
manifest_free_sourcefiles [ manifest_first_free ] = " <not freed> " ;
manifest_free_functions [ manifest_first_free ] = " <not freed> " ;
manifest_free_lines [ manifest_first_free ] = - 1 ;
/* Work out where next free manifest record lives */
2012-05-25 07:31:56 +00:00
for ( ; manifest_first_free < MAX_RHIZOME_MANIFESTS & & ! manifest_free [ manifest_first_free ] ; + + manifest_first_free )
;
if ( debug & DEBUG_MANIFESTS ) _log_manifest_trace ( filename , funcname , line , __FUNCTION__ ) ;
2012-01-28 01:15:45 +00:00
return m ;
}
void _rhizome_manifest_free ( const char * sourcefile , const char * funcname , int line ,
rhizome_manifest * m )
{
if ( ! m ) return ;
2012-01-12 03:38:24 +00:00
int i ;
2012-01-28 01:15:45 +00:00
int mid = m - > manifest_record_number ;
if ( m ! = & manifests [ mid ] ) {
2012-05-24 07:41:55 +00:00
logMessage ( LOG_LEVEL_ERROR , sourcefile , line , funcname ,
" %s(): asked to free manifest %p, which claims to be manifest slot #%d (%p), but isn't " ,
__FUNCTION__ , m , mid , & manifests [ mid ]
) ;
2012-01-28 01:15:45 +00:00
exit ( - 1 ) ;
}
2012-02-09 06:40:52 +00:00
if ( manifest_free [ mid ] ) {
2012-05-24 07:41:55 +00:00
logMessage ( LOG_LEVEL_ERROR , sourcefile , line , funcname ,
" %s(): asked to free manifest slot #%d (%p), which was already freed at %s:%d:%s() " ,
__FUNCTION__ , mid , m ,
manifest_free_sourcefiles [ mid ] ,
manifest_free_lines [ mid ] ,
manifest_free_functions [ mid ]
) ;
2012-02-09 06:40:52 +00:00
exit ( - 1 ) ;
}
2012-01-28 01:15:45 +00:00
/* Free variable and signature blocks.
XXX These should be moved to malloc - free storage eventually */
2012-01-12 03:38:24 +00:00
for ( i = 0 ; i < m - > var_count ; i + + )
{ free ( m - > vars [ i ] ) ; free ( m - > values [ i ] ) ;
m - > vars [ i ] = NULL ; m - > values [ i ] = NULL ; }
for ( i = 0 ; i < m - > sig_count ; i + + )
{ free ( m - > signatories [ i ] ) ;
m - > signatories [ i ] = NULL ;
}
if ( m - > dataFileName ) free ( m - > dataFileName ) ;
m - > dataFileName = NULL ;
2012-01-28 01:15:45 +00:00
manifest_free [ mid ] = 1 ;
manifest_free_sourcefiles [ mid ] = sourcefile ;
manifest_free_functions [ mid ] = funcname ;
manifest_free_lines [ mid ] = line ;
if ( mid < manifest_first_free ) manifest_first_free = mid ;
2012-01-12 03:38:24 +00:00
2012-05-25 07:31:56 +00:00
if ( debug & DEBUG_MANIFESTS ) _log_manifest_trace ( sourcefile , funcname , line , __FUNCTION__ ) ;
2012-01-12 03:38:24 +00:00
return ;
}
/* Convert variable list to string, complaining if it ends up
too long .
Signatures etc will be added later . */
int rhizome_manifest_pack_variables ( rhizome_manifest * m )
{
int i , ofs = 0 ;
for ( i = 0 ; i < m - > var_count ; i + + )
{
if ( ( ofs + strlen ( m - > vars [ i ] ) + 1 + strlen ( m - > values [ i ] ) + 1 + 1 ) > MAX_MANIFEST_BYTES )
return WHY ( " Manifest variables too long in total to fit in MAX_MANIFEST_BYTES " ) ;
snprintf ( ( char * ) & m - > manifestdata [ ofs ] , MAX_MANIFEST_BYTES - ofs , " %s=%s \n " ,
m - > vars [ i ] , m - > values [ i ] ) ;
ofs + = strlen ( ( char * ) & m - > manifestdata [ ofs ] ) ;
}
m - > manifestdata [ ofs + + ] = 0x00 ;
m - > manifest_bytes = ofs ;
2012-05-20 14:39:14 +00:00
if ( debug & DEBUG_RHIZOME ) DEBUG ( " Repacked variables in manifest. " ) ;
2012-01-13 10:43:17 +00:00
m - > manifest_all_bytes = ofs ;
2012-01-12 03:38:24 +00:00
/* Recalculate hash */
crypto_hash_sha512 ( m - > manifesthash , m - > manifestdata , m - > manifest_bytes ) ;
return 0 ;
}
2012-05-25 15:20:48 +00:00
/* Sign this manifest using our it's own BID secret key.
*/
# warning need to also allow signing by other parties (including SASes) instead of just self-signing.
int rhizome_manifest_selfsign ( rhizome_manifest * m )
2012-01-12 03:38:24 +00:00
{
2012-05-25 15:20:48 +00:00
if ( ! m - > haveSecret ) return WHY ( " Need private key to sign manifest " ) ;
/* XXX we have to pass it in as hex, but then we just turn it into bytes
anyway . */
char secret [ crypto_sign_edwards25519sha512batch_SECRETKEYBYTES * 2 + 1 ] ;
rhizome_bytes_to_hex_upper ( m - > cryptoSignSecret , secret ,
crypto_sign_edwards25519sha512batch_SECRETKEYBYTES ) ;
rhizome_signature * sig = rhizome_sign_hash ( m , secret ) ;
2012-01-12 03:38:24 +00:00
if ( ! sig ) return WHY ( " rhizome_sign_hash() failed. " ) ;
/* Append signature to end of manifest data */
if ( sig - > signatureLength + m - > manifest_bytes > MAX_MANIFEST_BYTES ) {
free ( sig ) ;
return WHY ( " Manifest plus signatures is too long. " ) ;
}
bcopy ( & sig - > signature [ 0 ] , & m - > manifestdata [ m - > manifest_bytes ] , sig - > signatureLength ) ;
m - > manifest_bytes + = sig - > signatureLength ;
2012-01-13 10:43:17 +00:00
m - > manifest_all_bytes = m - > manifest_bytes ;
2012-01-12 03:38:24 +00:00
free ( sig ) ;
return 0 ;
}
2012-04-02 08:12:40 +00:00
int rhizome_write_manifest_file ( rhizome_manifest * m , const char * filename )
2012-01-12 03:38:24 +00:00
{
2012-05-24 01:58:32 +00:00
if ( debug & DEBUG_RHIZOME ) DEBUGF ( " write manifest (%d bytes) to %s " , m - > manifest_all_bytes , filename ) ;
2012-01-12 03:38:24 +00:00
if ( ! m ) return WHY ( " Manifest is null. " ) ;
if ( ! m - > finalised ) return WHY ( " Manifest must be finalised before it can be written. " ) ;
2012-05-24 01:58:32 +00:00
FILE * f = fopen ( filename , " w " ) ;
if ( f = = NULL ) {
WHY_perror ( " fopen " ) ;
return WHYF ( " Cannot write manifest to %s " , filename ) ;
}
int r1 = fwrite ( m - > manifestdata , m - > manifest_all_bytes , 1 , f ) ;
int r2 = fclose ( f ) ;
if ( r1 ! = 1 )
return WHYF ( " fwrite(%s) returned % d " , filename, r1) ;
if ( r2 = = EOF )
return WHYF ( " fclose(%s) returned % d " , filename, r2) ;
2012-01-12 03:38:24 +00:00
return 0 ;
}
/*
Adds a group that this bundle should be present in . If we have the means to sign
the bundle as a member of that group , then we create the appropriate signature block .
The group signature blocks , like all signature blocks , will be appended to the
manifest data during the finalisation process .
*/
int rhizome_manifest_add_group ( rhizome_manifest * m , char * groupid )
{
return WHY ( " Not implemented. " ) ;
}
2012-05-24 07:41:55 +00:00
int rhizome_manifest_dump ( rhizome_manifest * m , const char * msg )
2012-01-12 03:38:24 +00:00
{
int i ;
2012-05-24 07:41:55 +00:00
WHYF ( " Dumping manifest %s: " , msg ) ;
2012-01-12 03:38:24 +00:00
for ( i = 0 ; i < m - > var_count ; i + + )
2012-05-24 07:41:55 +00:00
WHYF ( " [%s]=[%s] \n " , m - > vars [ i ] , m - > values [ i ] ) ;
2012-01-12 03:38:24 +00:00
return 0 ;
}
2012-05-25 15:20:48 +00:00
int rhizome_manifest_finalise ( rhizome_manifest * m )
2012-01-12 03:38:24 +00:00
{
/* set fileHexHash */
if ( ! m - > fileHashedP ) {
2012-05-25 15:20:48 +00:00
if ( rhizome_hash_file ( m , m - > dataFileName , m - > fileHexHash ) )
2012-01-12 03:38:24 +00:00
return WHY ( " rhizome_hash_file() failed during finalisation of manifest . " ) ;
m - > fileHashedP = 1 ;
2012-01-27 05:51:48 +00:00
/* set fileLength */
2012-06-05 06:15:53 +00:00
if ( m - > dataFileName [ 0 ] ) {
struct stat stat ;
if ( lstat ( m - > dataFileName , & stat ) ) {
WHY_perror ( " lstat " ) ;
return WHY ( " Could not stat() associated file " ) ;
}
m - > fileLength = stat . st_size ;
} else
m - > fileLength = 0 ;
2012-01-12 03:38:24 +00:00
}
/* Set file hash and size information */
rhizome_manifest_set ( m , " filehash " , m - > fileHexHash ) ;
rhizome_manifest_set_ll ( m , " filesize " , m - > fileLength ) ;
/* set fileHighestPriority based on group associations.
XXX - Should probably be set as groups are added */
/* set version of manifest, either from version variable, or using current time */
if ( rhizome_manifest_get ( m , " version " , NULL , 0 ) = = NULL )
{
/* No version set */
2012-05-11 01:08:46 +00:00
m - > version = gettime_ms ( ) ;
2012-01-12 03:38:24 +00:00
rhizome_manifest_set_ll ( m , " version " , m - > version ) ;
}
else
m - > version = rhizome_manifest_get_ll ( m , " version " ) ;
/* Convert to final form for signing and writing to disk */
2012-05-25 15:20:48 +00:00
if ( rhizome_manifest_pack_variables ( m ) )
return WHY ( " Could not convert manifest to wire format " ) ;
2012-01-12 03:38:24 +00:00
/* Sign it */
2012-05-25 15:20:48 +00:00
if ( rhizome_manifest_selfsign ( m ) )
return WHY ( " Could not sign manifest " ) ;
2012-01-12 03:38:24 +00:00
/* mark manifest as finalised */
m - > finalised = 1 ;
return 0 ;
}