ripole-0.2-dev/0000755000175000001440000000000010347157757012137 5ustar pldusersripole-0.2-dev/bt-int.c0000644000175000001440000000254011102627641013461 0ustar pldusers#include #include #include "bt-int.h" int BTI_init( struct bti_node **n ) { *n = NULL; return 0; } int BTI_add( struct bti_node **n, int value ) { int collision = 0; int dir = 0; struct bti_node *p = NULL, *node = *n; // fprintf(stdout,"Adding %d to %p\n", value, *n); while (node != NULL) { if (value > node->data) { p = node; dir=1; node = node->r; } else if (value < node->data) { p = node; dir=-1; node = node->l; } else if (value == node->data) { collision = 1; break; } } if (collision == 0) { struct bti_node *leaf; leaf = malloc(sizeof(struct bti_node)); if (leaf == NULL) { return -1; } leaf->data = value; leaf->l = leaf->r = NULL; if (p != NULL) { switch (dir) { case 1: p->r = leaf; break; case -1: p->l = leaf; break; } } else { *n = leaf; } } return collision; } int BTI_dump( struct bti_node **n ) { struct bti_node *node; node = *n; if (node->l) BTI_dump(&(node->l)); if (*n) { fprintf(stdout,"%d, ", node->data); } if (node->r) BTI_dump(&(node->r)); return 0; } int BTI_done( struct bti_node **n ) { struct bti_node *node; if (n == NULL) return 0; if (*n == NULL) return 0; node = *n; if (node->l) BTI_done(&(node->l)); if (node->r) BTI_done(&(node->r)); if (*n) { free(*n); *n = NULL; } return 0; } ripole-0.2-dev/bt-int.h0000644000175000001440000000040611102627641013465 0ustar pldusers#ifndef __BT_INT__ #define __BT_INT__ struct bti_node { int data; struct bti_node *l,*r; }; int BTI_init( struct bti_node **n ); int BTI_add( struct bti_node **n, int value ); int BTI_dump( struct bti_node **n ); int BTI_done( struct bti_node **n ); #endif ripole-0.2-dev/ripole.c0000644000175000001440000002045011102627641013556 0ustar pldusers // Microsoft OLE2 stream parser. #include #include #include #include #include "logger.h" #include "pldstr.h" #include "ole.h" struct ripOLE_object { int debug; int verbose; int save_unknown_streams; char *inputfile; char *outputdir; }; #define ROLE_VERSION "0.2.1" static char defaultdir[]="."; static char version[]="0.2.1 - November 1, 2008 (C) PLDaniels http://www.pldaniels.com/ripole"; static char help[]="ripOLE -i [ -d ] [--save-unknown-streams] [--version|-V] [--verbose|-v] [--debug] [--help|-h]"; /*-----------------------------------------------------------------\ Function Name : set_defaults Returns Type : int ----Parameter List 1. struct ripOLE_object *role , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_set_defaults( struct ripOLE_object *role ) { role->outputdir = defaultdir; role->debug = 0; role->verbose = 0; role->save_unknown_streams = 0; role->inputfile = NULL; return 0; } /*-----------------------------------------------------------------\ Function Name : parse_parameters Returns Type : int ----Parameter List 1. struct ripOLE_object *role, 2. int argc, 3. char **argv , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_parse_parameters( struct ripOLE_object *role, int argc, char **argv ) { int i; int result = 0; role->outputdir = defaultdir; for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'i': i++; role->inputfile = strdup(argv[i]); break; case 'd': i++; role->outputdir = strdup(argv[i]); break; case 'v': role->verbose = 1; break; case 'V': fprintf (stdout, "%s\n", version); exit (1); break; case 'h': fprintf (stdout, "%s\n", help); exit (1); break; // if we get ANOTHER - symbol, then we have an extended flag case '-': if (strncmp (&(argv[i][2]), "verbose", 7) == 0) { role->verbose=1; } else if (strncmp (&(argv[i][2]), "save-unknown-streams", 20) == 0) { role->save_unknown_streams = 1; } else if (strncmp (&(argv[i][2]), "debug", 5) == 0) { role->debug=1; } else if (strncmp (&(argv[i][2]), "version", 7) == 0) { fprintf (stdout, "%s\n", version); exit (1); } else if (strncmp(&(argv[i][2]),"help",4)==0) { fprintf(stdout,"%s\n",help); exit(1); } else { fprintf(stdout,"Cannot interpret option \"%s\"\n%s\n", argv[i], help); exit (1); break; } break; // else, just dump out the help message default: fprintf(stdout,"Cannot interpret option \"%s\"\n%s\n", argv[i], help); exit (1); break; } // Switch argv[i][1] } // if argv[i][0] == - } // for return result; } /*-----------------------------------------------------------------\ Function Name : set_parameters Returns Type : int ----Parameter List 1. struct ripOLE_object *role, 2. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_set_parameters( struct ripOLE_object *role, struct OLE_object *ole ) { if(role->debug == 1) { OLE_set_debug(ole, OLE_DEBUG_NORMAL); } if (role->verbose == 1) { OLE_set_verbose(ole, OLE_VERBOSE_NORMAL); } if (role->save_unknown_streams == 1) { OLE_set_save_unknown_streams(ole, 1); } return 0; } /*-----------------------------------------------------------------\ Function Name : ripOLE_report_filename_decoded Returns Type : int ----Parameter List 1. char *filename, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_report_filename_decoded(char *filename) { LOGGER_log("Decoding filename=%s", filename); return 0; } /*-----------------------------------------------------------------\ Function Name : ROLE_init Returns Type : int ----Parameter List 1. struct ripOLE_object *role, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_init(struct ripOLE_object *role) { role->debug = 0; role->verbose = 0; role->save_unknown_streams = 0; role->inputfile = NULL; role->outputdir = NULL; return 0; } /*-----------------------------------------------------------------\ Function Name : ROLE_done Returns Type : int ----Parameter List 1. struct ripOLE_object *role, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_done(struct ripOLE_object *role) { if (role->inputfile != NULL) free(role->inputfile); if (role->outputdir != NULL) free(role->outputdir); return 0; } /*-----------------------------------------------------------------\ Function Name : ROLE_validate Returns Type : int ----Parameter List 1. struct ripOLE_object *role , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int ROLE_validate(struct ripOLE_object *role ) { int result = 0; if (role->inputfile == NULL) { fprintf(stderr,"ripOLE requires an input file to decode\n"); return -1; } return result; } /*-----------------------------------------------------------------\ Function Name : main Returns Type : int ----Parameter List 1. int argc, 2. char **argv , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int main( int argc, char **argv ) { struct ripOLE_object role; struct OLE_object *ole = NULL; int result = 0; if (argc == 1) { fprintf (stdout, "%s\n", help); exit(1); } ole = malloc(sizeof(struct OLE_object)); if (ole == NULL) { LOGGER_log("ripOLE: Cannot allocate memory for OLE object"); return 1; } LOGGER_set_output_mode(_LOGGER_STDOUT); OLE_init(ole); ROLE_init(&role); ROLE_set_defaults( &role ); ROLE_parse_parameters(&role, argc, argv); result = ROLE_validate(&role); if (result != 0) return result; ROLE_set_parameters(&role, ole); OLE_set_filename_report_fn(ole, ROLE_report_filename_decoded ); result = OLE_decode_file( ole, role.inputfile, role.outputdir ); OLE_decode_file_done(ole); if ((result != 0)) { if (role.verbose) { switch (result) { case OLEER_NO_INPUT_FILE: case OLEER_BAD_INPUT_FILE: LOGGER_log("Cannot locate input file '%s'",role.inputfile); break; case OLEER_NOT_OLE_FILE: LOGGER_log("File '%s' is not OLE2 format",role.inputfile); break; case OLEER_INSANE_OLE_FILE: LOGGER_log("OLE input file '%s' is insane", role.inputfile); break; default: LOGGER_log("ripOLE: decoding of %s resulted in error %d\n", role.inputfile, result ); } } return result; } if (ole != NULL) free(ole); ROLE_done(&role); return result; } /** end of ripOLE **/ ripole-0.2-dev/logger.c0000644000175000001440000001724211102627641013550 0ustar pldusers // Abstract logging system used to facilitate multiple modes // of logging #include #include #include #ifndef WIN32 #include #endif #include #include #include #include "logger.h" #ifndef WIN32 static int _LOGGER_mode = _LOGGER_SYSLOG; static int _LOGGER_syslog_mode = LOG_MAIL|LOG_INFO; #else static int _LOGGER_mode = _LOGGER_STDERR; static int _LOGGER_syslog_mode = 0; #endif static FILE *_LOGGER_outf; struct LOGGER_globals { int wrap; int wraplength; }; // Create and Initialise the global structure for LOGGER, // we init it to have NO wrapping. static struct LOGGER_globals LOGGER_glb={ 0, 0 }; /*------------------------------------------------------------------------ Procedure: LOGGER_get_file ID:1 Purpose: Returns the pointer to the file being used to output logs to Input: Output: Errors: ------------------------------------------------------------------------*/ FILE *LOGGER_get_file( void ) { return _LOGGER_outf; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_output_mode ID:1 Purpose: Sets the message/log output method, ie, stderr, stdout or syslog Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_output_mode( int modechoice ) { _LOGGER_mode = modechoice; return 0; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_output_file ID:1 Purpose: Sets the output file for when _LOGGER_mode is set to _LOGGER_file Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_output_file( FILE *f ) { _LOGGER_outf = f; return 0; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_syslog_mode ID:1 Purpose: Sets the mode that messaging to the syslog daemon will be sent as (ie, LOG_MAIL|LOG_INFO) Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_syslog_mode( int syslogmode ) { _LOGGER_syslog_mode = syslogmode; return 0; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_logfile ID:1 Purpose: Opens and setups the internal Log file file pointer with the log file as given by lfname Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_logfile( char *lfname ) { int result = 0; _LOGGER_outf = fopen(lfname,"a"); if (!_LOGGER_outf) { #ifndef WIN32 syslog(1,"LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)",lfname,strerror(errno)); #else fprintf(stderr, "LOGGER_set_logfile: ERROR - Cannot open logfile '%s' (%s)\n", lfname, strerror(errno)); #endif result = -1; } return result; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_wraplength ID:1 Purpose: Sets the character count at which LOGGER will break a line Input: int length: Positive integer indicating number of chracters at which to wrap at Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_wraplength( int length ) { if ( length >= 0 ) { LOGGER_glb.wraplength = length; } return LOGGER_glb.wraplength; } /*------------------------------------------------------------------------ Procedure: LOGGER_set_wrap ID:1 Purpose: Set log output wrapping to on or off Input: int level: 0 = no wrap, > 0 = wrap. Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_set_wrap( int level ) { if ( level >= 0 ) { LOGGER_glb.wrap = level; } return LOGGER_glb.wrap; } /*------------------------------------------------------------------------ Procedure: LOGGER_close_logfile ID:1 Purpose: Closes the modules log file pointer. Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_close_logfile( void ) { int result = 0; if (_LOGGER_outf) fclose(_LOGGER_outf); return result; } /*------------------------------------------------------------------------ Procedure: LOGGER_clean_output ID:1 Purpose: Checks through the output string for any characters which could cause potential 'isssues' with the data writing calls, items such as stray non-escaped % characters can cause havoc. Input: char *string: Raw string int maxsize: Maximum available buffer size for this string to expand to Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_clean_output( char *string, char **buffer ) { char *newstr; char *p, *q; char *next_space; int pc; int slen = strlen( string ); int line_size; int maxsize = slen *2; // First up, allocate maxsize bytes for a temporary new string. newstr = malloc(slen *2 +1); if ( newstr == NULL ) { // FIXME - Report an error here ... to -somewhere- return -1; } p = newstr; q = string; pc = 0; line_size = 0; while (slen--) { // Do we need to apply any wrapping to the output? If so then we // shall embark on a journey of strange space and distance // evaluations to determine if we should wrap now or later if ( LOGGER_glb.wrap > 0 ) { if (isspace((int)*q)) { next_space = strpbrk( (q+1), "\t\r\n\v " ); if (next_space != NULL) { if ((line_size +(next_space -q)) >= LOGGER_glb.wraplength) { *p = '\n'; p++; pc++; line_size = 0; } } } if ( line_size >= LOGGER_glb.wraplength ) { *p = '\n'; p++; pc++; line_size = 0; } } // If the string has a % in it, then we need to encode it as // a DOUBLE % symbol. if (*q == '%') { // if (strchr("fdlsxXn",*(q+1))) // { *p = '%'; p++; pc++; // } } // Copy the character of the string in *p = *q; // Move everything along. q++; p++; pc++; line_size++; if ( pc > (maxsize -1) ) { break; } } *p = '\0'; // This will have to be deallocated later! if (newstr) *buffer = newstr; return 0; } /*------------------------------------------------------------------------ Procedure: LOGGER_log ID:1 Purpose: Logs the params as supplied to the required output as defined by LOGGER_set_output Input: Output: Errors: ------------------------------------------------------------------------*/ int LOGGER_log( char *format, ...) { va_list ptr; char tmpoutput[10240]; char linebreak[]="\n"; char nolinebreak[]=""; char *lineend; char *output; // get our variable arguments va_start(ptr,format); // produce output, and spit to the log file #ifdef NO_SNPRINTF vsprintf(tmpoutput, format, ptr); #else vsnprintf(tmpoutput,sizeof(tmpoutput),format,ptr); #endif LOGGER_clean_output( tmpoutput, &output ); if ( output[strlen(output)-1] == '\n' ) { lineend = nolinebreak; } else { lineend = linebreak; } if ( output[strlen(output)-1] == '\n' ) { lineend = nolinebreak; } else { lineend = linebreak; } // Send the output to the appropriate output destination switch (_LOGGER_mode) { case _LOGGER_STDERR: fprintf(stderr,"%s%s",output, lineend ); break; case _LOGGER_SYSLOG: syslog(_LOGGER_syslog_mode,"%s",output); break; case _LOGGER_STDOUT: fprintf(stdout,"%s%s",output, lineend); fflush(stdout); break; case _LOGGER_FILE: fprintf(_LOGGER_outf,"%s%s",output,lineend); fflush(_LOGGER_outf); break; case _LOGGER_NULL: // 20080303-2214:PLD: Added to allow us to direct all logging to NULL. break; default: fprintf(stdout,"LOGGER-Default: %s%s",output,lineend); } if (output) free(output); return 0; } ripole-0.2-dev/logger.h0000644000175000001440000000113411102627641013546 0ustar pldusers #ifndef __LOGGER__ #define __LOGGER__ // LOGGER.h // #define _LOGGER_STDERR 1 #define _LOGGER_STDOUT 2 #define _LOGGER_FILE 3 #ifndef WIN32 #define _LOGGER_SYSLOG 4 #endif #define _LOGGER_NULL 5 #ifndef FL #define FL __FILE__,__LINE__ #endif int LOGGER_log( char *format, ...); int LOGGER_set_output_mode( int modechoice ); int LOGGER_set_output_file( FILE *f ); int LOGGER_set_syslog_mode( int syslogmode ); int LOGGER_set_logfile( char *lfname ); int LOGGER_set_wraplength( int length ); int LOGGER_set_wrap( int level ); int LOGGER_close_logfile( void ); FILE *LOGGER_get_file( void ); #endif ripole-0.2-dev/pldstr.c0000644000175000001440000005164311102627641013604 0ustar pldusers #include #include #include #include #include #include #include #include "logger.h" #include "pldstr.h" /*-----------------------------------------------------------------\ Function Name : *PLD_strstr Returns Type : char ----Parameter List 1. char *haystack, 2. char *needle, 3. int insensitive, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ char *PLD_strstr(char *haystack, char *needle, int insensitive) { char *hs, *ne; char *result; // LOGGER_log("%s:%d:\nHS=%s\nNE=%s\nIS=%d\n",FL, haystack, needle, insensitive ); if (insensitive > 0) { hs = strdup(haystack); PLD_strlower(hs); ne = strdup(needle); PLD_strlower(ne); } else { hs = haystack; ne = needle; } result = strstr(hs, ne); // if (result) LOGGER_log("%s:%d:HIT: %s",FL, result); // else LOGGER_log("%s:%d:MISS (looking for %s|%s)",FL, needle,ne); if ((result != NULL)&&(insensitive > 0)) { result = result -hs +haystack; // free(hs); // free(ne); // LOGGER_log("%s:%d:HIT - %s",FL, result ); } if (insensitive) { free(hs); free(ne); } return result; } /*------------------------------------------------------------------------ Procedure: PLD_strncpy ID:1 Purpose: Copy characters from 'src' to 'dst', writing not more than 'len' characters to the destination, including the terminating \0. Thus, for any effective copying, len must be > 1. Input: char *dst: Destination string char *src: Source string size_t len: length of string Output: Returns a pointer to the destination string. Errors: ------------------------------------------------------------------------*/ char *PLD_strncpy (char *dst, const char *src, size_t len) { // Thanks go to 'defrost' of #c for providing the replacement // code which you now see here. It covers the errors better // than my own previous code. // If we have no buffer space, then it's futile attempting // to copy anything, just return NULL if (len==0) return NULL; // Providing our destination pointer isn't NULL, we can // commence copying data across if (dst) { char *dp = dst; // If our source string exists, start moving it to the // destination string character at a time. if (src) { char *sp = (char *)src; while ((--len)&&(*sp)) { *dp=*sp; dp++; sp++; } } *dp='\0'; } return dst; } /*------------------------------------------------------------------------ Procedure: PLD_strncat ID:1 Purpose: Buffer size limited string concat function for two strings. Input: char *dst: Destination string char *src: Source string size_t len: Destination string buffer size - total string size cannot exceed this Output: Errors: If the length of both strings in total is greater than the available buffer space in *dst, we copy the maximum possible amount of chars from *src such that buffer does not overflow. A suffixed '\0' will always be appended. ------------------------------------------------------------------------*/ char *PLD_strncat( char *dst, const char *src, size_t len ) { char *dp = dst; const char *sp = src; size_t cc; if (len == 0) return dst; len--; // Locate the end of the current string. cc = 0; while ((*dp)&&(cc < len)) { dp++; cc++; } // If we have no more buffer space, then return the destination if (cc >= len) return dst; // While we have more source, and there's more char space left in the buffer while ((*sp)&&(cc < len)) { cc++; *dp = *sp; dp++; sp++; } // Terminate dst, as a gaurantee of string ending. *dp = '\0'; return dst; } /*------------------------------------------------------------------------ Procedure: PLD_strncate ID:1 Purpose: Catencates a source string to the destination string starting from a given endpoint. This allows for faster catencation of strings by avoiding the computation required to locate the endpoint of the destination string. Input: char *dst: Destination string char *src: Source string size_t len: Destination buffer size char *endpoint: Endpoint of destination string, location from where new string will be appended Output: Errors: ------------------------------------------------------------------------*/ char *PLD_strncate( char *dst, const char *src, size_t len, char *endpoint ) { char *dp = dst; const char *sp = src; size_t cc = 0; if (len == 0) return dst; len--; // If endpoint does not relate correctly, then force manual detection // of the endpoint. if ((!endpoint)||(endpoint == dst)||((endpoint -dst +1)>(int)len)) { // Locate the end of the current string. cc = 0; while ((*dp != '\0')&&(cc < len)) { dp++; cc++; } } else { cc = endpoint -dst +1; dp = endpoint; } // If we have no more buffer space, then return the destination if (cc >= len) return dst; // While we have more source, and there's more char space left in the buffer while ((*sp)&&(cc < len)) { cc++; *dp = *sp; dp++; sp++; } // Terminate dst, as a gaurantee of string ending. *dp = '\0'; return dst; } /*------------------------------------------------------------------------ Procedure: XAM_strncasecmp ID:1 Purpose: Portable version of strncasecmp(), this may be removed in later versions as the strncase* type functions are more widely implemented Input: Output: Errors: ------------------------------------------------------------------------*/ int PLD_strncasecmp( char *s1, char *s2, int n ) { char *ds1 = s1, *ds2 = s2; char c1, c2; int result = 0; while(n > 0) { c1 = tolower(*ds1); c2 = tolower(*ds2); if (c1 == c2) { n--; ds1++; ds2++; } else { result = c2 - c1; n = 0; } } return result; } /*------------------------------------------------------------------------ Procedure: XAM_strtok ID:1 Purpose: A thread safe version of strtok() Input: Output: Errors: ------------------------------------------------------------------------*/ char *PLD_strtok( struct PLD_strtok *st, char *line, char *delimeters ) { char *stop; char *dc; char *result = NULL; if ( line ) { st->start = line; } //Strip off any leading delimeters dc = delimeters; while ((st->start)&&(*dc != '\0')) { if (*dc == *(st->start)) { st->start++; dc = delimeters; } else dc++; } // Where we are left, is the start of our token. result = st->start; if ((st->start)&&(st->start != '\0')) { stop = strpbrk( st->start, delimeters ); /* locate our next delimeter */ // If we found a delimeter, then that is good. We must now break the string here // and don't forget to store the character which we stopped on. Very useful bit // of information for programs which process expressions. if (stop) { // Store our delimeter. st->delimeter = *stop; // Terminate our token. *stop = '\0'; // Because we're emulating strtok() behaviour here, we have to // absorb all the concurrent delimeters, that is, unless we // reach the end of the string, we cannot return a string with // no chars. stop++; dc = delimeters; while (*dc != '\0') { if (*dc == *stop) { stop++; dc = delimeters; } else dc++; } // While if (*stop == '\0') st->start = NULL; else st->start = stop; } else { st->start = NULL; st->delimeter = '\0'; } } else { st->start = NULL; result = NULL; } return result; } /*------------------------------------------------------------------------ Procedure: PLD_strlower ID:1 Purpose: Converts a string to lowercase Input: char *convertme : string to convert Output: Errors: Comments: Really need to validate against high-ASCII chars. Tested against strings like; Logo de la République française Македонски ------------------------------------------------------------------------*/ int PLD_strlower( char *convertme ) { char *c = convertme; while ( *c != '\0') {*c = (unsigned char)tolower((int)*c); c++;} return 0; } /*-----------------------------------------------------------------\ Function Name : *PLD_strreplace Returns Type : char ----Parameter List 1. char *source, Original buffer, \0 terminated 2. char *searchfor, String sequence to search for 3. char *replacewith, String sequence to replace 'searchfor' with 4. int replacenumber , How many times to replace 'searchfor', 0 == unlimited ------------------ Exit Codes : Returns a pointer to the new buffer space. The original buffer will still remain intact - ensure that the calling program free()'s the original buffer if it's no longer needed Side Effects : -------------------------------------------------------------------- Comments: Start out with static text matching - upgrade to regex later. -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ char *PLD_strreplace_general( struct PLD_strreplace *replace_details ) { char *new_buffer=NULL; char *source_end; char *segment_start, *segment_end, *segment_p; char *new_p; char *preexist_location=NULL; char *postexist_location=NULL; int replace_count=0; int size_required; int size_difference; int source_length; int searchfor_length; int replacewith_length; int segment_ok; if (replace_details->source == NULL) return NULL; source_length = strlen( replace_details->source ); source_end = replace_details->source +source_length; searchfor_length = strlen(replace_details->searchfor); replacewith_length = strlen(replace_details->replacewith); size_difference = replacewith_length -searchfor_length; size_required = source_length; replace_count = replace_details->replacenumber; if ((replace_details->preexist != NULL)&&(strlen(replace_details->preexist) < 1)) replace_details->preexist = NULL; if ((replace_details->postexist != NULL)&&(strlen(replace_details->postexist) < 1)) replace_details->postexist = NULL; // If we have a 'pre-exist' request, then we need to check this out first // because if the pre-exist string cannot be found, then there's very // little point us continuing on in our search ( because without the // preexist string existing, we are thus not qualified to replace anything ) if (replace_details->preexist != NULL) { preexist_location = PLD_strstr(replace_details->source, replace_details->preexist, replace_details->insensitive); if (preexist_location == NULL) { return replace_details->source; } } // Determine if initial POSTexist tests will pass, if we don't pick up // anything here, then there's no point in continuing either if (replace_details->postexist != NULL) { char *p = replace_details->source; postexist_location = NULL; do { p = PLD_strstr(p, replace_details->postexist, replace_details->insensitive); if (p != NULL) { postexist_location = p; p = p +strlen(replace_details->postexist); } } while (p != NULL); if (postexist_location == NULL) { return replace_details->source; } } // Step 1 - determine the MAXIMUM number of times we might have to replace this string ( or the limit // set by replacenumber // // Note - we only need this number if the string we're going to be inserting into the // source is larger than the one we're replacing - this is so that we can ensure that // we have sufficient memory available in the buffer. if (size_difference > 0) { if (replace_count == 0) { char *p, *q; p = replace_details->source; q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive); while (q != NULL) { replace_count++; //size_required += size_difference; p = q +searchfor_length; q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive); } } size_required = source_length +(size_difference *replace_count) +1; } else size_required = source_length +1; // Allocate the memory required to hold the new string [at least], check to see that // all went well, if not, then return an error new_buffer = malloc( sizeof(char) *size_required); if (new_buffer == NULL) { LOGGER_log("%s:%d:PLD_strreplace:ERROR: Cannot allocate %d bytes of memory to perform replacement operation", FL, size_required); return replace_details->source; } // Our segment must always start at the beginning of the source, // on the other hand, the segment_end can be anything from the // next byte to NULL ( which is specially treated to mean to // the end of the source ) segment_start = replace_details->source; // Locate the first segment segment_ok = 0; segment_end = PLD_strstr(replace_details->source, replace_details->searchfor, replace_details->insensitive); // Determine if the first segment is valid in the presence of the // pre-exist and post-exist requirements while ((segment_end != NULL)&&(segment_ok == 0)\ &&((replace_details->preexist != NULL)||(replace_details->postexist != NULL))) { int pre_ok = 0; int post_ok = 0; // The PREexist test assumes a couple of factors - please ensure these are // relevant if you change any code prior to this point. // // 1. preexist_location has already been computed and is not NULL // // 2. By relative position, the first preexist_location will be a valid location // on which to validate for ALL replacements beyond that point, thus, we // never actually have to recompute preexist_location again. // // 3. Conversely, the last computed postexist_location is valid for all // matches before it // if (preexist_location == NULL) pre_ok = 1; else if (preexist_location < segment_end){ pre_ok = 1;} if (postexist_location == NULL) post_ok = 1; else if (postexist_location > segment_end){ post_ok = 1;} if ((pre_ok == 0)||(post_ok == 0)) { segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive); } else segment_ok = 1; } segment_p = segment_start; new_p = new_buffer; while (segment_start != NULL) { int replacewith_count; char *replacewith_p; if (segment_end == NULL) segment_end = source_end; replace_count--; // Perform the segment copy segment_p = segment_start; while ((segment_p < segment_end)&&(size_required > 0)) { *new_p = *segment_p; new_p++; segment_p++; size_required--; } // Perform the string replacement if (segment_end < source_end) { replacewith_count = replacewith_length; replacewith_p = replace_details->replacewith; while ((replacewith_count--)&&(size_required > 0)) { *new_p = *replacewith_p; new_p++; replacewith_p++; size_required--; } } if (size_required < 1 ) { LOGGER_log("%s:%d:PLD_strreplace_general: Allocated memory ran out while replacing '%s' with '%s'",FL, replace_details->searchfor, replace_details->replacewith); *new_p='\0'; break; } // Find the next segment segment_start = segment_end +searchfor_length; // If we've reached the end of the number of replacements we're supposed // to do, then we prepare the termination of the while loop by setting // our segment end to the end of the source. // // NOTE: Remember that the replace_count is pre-decremented at the start // of the while loop, so, if the caller requested '0' replacements // this will now be -1, thus, it won't get terminated from this == 0 // match. Just thought you'd like to be reminded of that incase you // were wondering "Huh? this would terminate an unlimited replacement" if (replace_count == 0) { segment_end = NULL; } else { // If our new segment to copy starts after the // end of the source, then we actually have // nothing else to copy, thus, we prepare the // segment_start varible to cause the while loop // to terminate. // // Otherwise, we try and locate the next segment // ending point, and set the starting point to // be on the 'other side' of the 'searchfor' string // which we found in the last search. // if (segment_start > source_end) { segment_start = NULL; } else { // Try find the next segment segment_ok = 0; segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive); // If we have a pre/post-exist requirement, then enter into this // series of tests. NOTE - at least one of the pre or post tests // must fire to give an meaningful result - else we'll end up with // a loop which simply goes to the end of the searchspace buffer while ((segment_end != NULL)&&(segment_ok == 0)\ &&((replace_details->preexist != NULL)||(replace_details->postexist != NULL))) { int pre_ok = 0; int post_ok = 0; // The PREexist test assumes a couple of factors - please ensure these are // relevant if you change any code prior to this point. // // 1. preexist_location has already been computed and is not NULL // // 2. By relative position, the first preexist_location will be a valid location // on which to validate for ALL replacements beyond that point, thus, we // never actually have to recompute preexist_location again. // // 3. Conversely, the last computed postexist_location is valid for all // matches before it // if (preexist_location == NULL) pre_ok = 1; else if (preexist_location < segment_end){ pre_ok = 1;} if (postexist_location == NULL) post_ok = 1; else if (postexist_location > segment_end){ post_ok = 1;} if ((pre_ok == 0)||(post_ok == 0)) { segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive); } else segment_ok = 1; } } // If-else segment_start > source_end } } *new_p = '\0'; // if (replace_details->source != NULL) free (replace_details->source); // replace_details->source = new_buffer; return new_buffer; } /*-----------------------------------------------------------------\ Function Name : *PLD_strreplace Returns Type : char ----Parameter List 1. char **source, 2. char *searchfor, 3. char *replacewith, 4. int replacenumber , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ char *PLD_strreplace( char **source, char *searchfor, char *replacewith, int replacenumber ) { struct PLD_strreplace replace_details; char *tmp_source; replace_details.source = *source; replace_details.searchfor = searchfor; replace_details.replacewith = replacewith; replace_details.replacenumber = replacenumber; replace_details.preexist = NULL; replace_details.postexist = NULL; replace_details.insensitive = 0; tmp_source = PLD_strreplace_general( &replace_details ); if (tmp_source != *source) *source = tmp_source; return *source; } /*-----------------------------------------------------------------\ Function Name : *PLD_dprintf Returns Type : char ----Parameter List 1. const char *format, 2. ..., ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: This is a dynamic string allocation function, not as fast as some other methods, but it works across the board with both glibc 2.0 and 2.1 series. -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ char *PLD_dprintf(const char *format, ...) { int n, size = 1024; // Assume we don't need more than 1K to start with char *p; va_list ap; // Attempt to allocate and then check p = malloc(size *sizeof(char)); if (p == NULL) return NULL; while (1) { // Attempt to print out string out into the allocated space va_start(ap, format); n = vsnprintf (p, size, format, ap); va_end(ap); // If things went well, then return the new string if ((n > -1) && (n < size)) return p; // If things didn't go well, then we have to allocate more space // based on which glibc we're using ( fortunately, the return codes // tell us which glibc is being used! *phew* // // If n > -1, then we're being told precisely how much space we need // else (older glibc) we have to just guess again ... if (n > -1) size = n+1; // Allocate precisely what is needed else size *= 2; // Double the amount allocated, note, we could just increase by 1K, but if we have a long string, we'd end up using a lot of realloc's // We could just realloc 'blind', but that'd be wrong and potentially cause a DoS, so // instead, we'll be good and first attempt to realloc to a temp variable then, if all // is well, we go ahead and update if (1) { char *tmp_p; tmp_p = realloc(p, size); if (tmp_p == NULL){ if (p != NULL) free(p); return NULL; } else p = tmp_p; } } } //-----------------END. ripole-0.2-dev/pldstr.h0000644000175000001440000000165411102627641013606 0ustar pldusers#ifndef __PLDSTR__ #define __PLDSTR__ #ifndef FL #define FL __FILE__,__LINE__ #endif struct PLD_strtok { char *start; char delimeter; }; struct PLD_strreplace { char *source; char *searchfor; char *replacewith; char *preexist; char *postexist; int replacenumber; int insensitive; }; char *PLD_strstr(char *haystack, char *needle, int insensitive); char *PLD_strncpy( char *dst, const char *src, size_t len ); char *PLD_strncat( char *dst, const char *src, size_t len ); char *PLD_strncate( char *dst, const char *src, size_t len, char *endpoint ); char *PLD_strtok( struct PLD_strtok *st, char *line, char *delimeters ); int PLD_strncasecmp( char *s1, char *s2, int n ); int PLD_strlower( char *convertme ); char *PLD_strreplace_general( struct PLD_strreplace *replace_details ); char *PLD_strreplace( char **source, char *searchfor, char *replacewith, int replacenumber ); char *PLD_dprintf(const char *fmt, ...); #endif ripole-0.2-dev/ole.c0000644000175000001440000016005611102627641013052 0ustar pldusers#include #include #include #include #include #include #include #include "logger.h" #include "pldstr.h" #include "bt-int.h" #include "bytedecoders.h" #include "olestream-unwrap.h" #include "ole.h" /** Sector ID values (predefined) **/ #define OLE_SECTORID_FREE -1 /** Unallocated sector **/ #define OLE_SECTORID_ENDOFCHAIN -2 /** Sector marks the end of the a sector-ID chain **/ #define OLE_SECTORID_SAT -3 /** Sector used by sector allocation Table **/ #define OLE_SECTORID_MSAT -4 /** Sector used by master sector allocation Table **/ // Main header accessors #define header_id(x) ((x) +0) #define header_clid(x) ((x) +0x08) #define header_minor_version(x) ((x) +0x18) #define header_dll_version(x) ((x) +0x1a) #define header_byte_order(x) ((x) +0x1c) #define header_sector_shift(x) ((x) +0x1e) #define header_mini_sector_shift(x) ((x) +0x20) #define header_fat_sector_count(x) ((x) +0x2c) #define header_directory_stream_start_sector(x) ((x) +0x30) #define header_mini_cutoff_size(x) ((x) +0x38) #define header_mini_fat_start(x) ((x) +0x3c) #define header_mini_fat_sector_count(x) ((x) +0x40) #define header_dif_start_sector(x) ((x) +0x44) #define header_dif_sector_count(x) ((x) +0x48) #define header_fat_sectors(x) ((x) +0x4c) //Property Storage accessor macros #define pps_rawname(x) ((x) +0) #define pps_sizeofname(x) ((x) +0x40) #define pps_type(x) ((x) +0x42) #define pps_previouspps(x) ((x) +0x44) #define pps_nextpps(x) ((x) +0x48) #define pps_directorypps(x) ((x) +0x4c) #define pps_time1seconds(x) ((x) +0x64) #define pps_time1days(x) ((x) +0x68) #define pps_time2seconds(x) ((x) +0x6c) #define pps_time2days(x) ((x) +0x70) #define pps_propertystart(x) ((x) +0x74) #define pps_sizeofproperty(x) ((x) +0x78) // Type lenghts #define LEN_BYTE 1 #define LEN_USHORT 2 #define LEN_ULONG 4 // Directory types #define STGTY_INVALID 0 #define STGTY_STORAGE 1 #define STGTY_STREAM 2 #define STGTY_LOCKBYTES 3 #define STGTY_PROPERTY 4 #define STGTY_ROOT 5 // Directory tag colours #define DE_RED 0 #define DE_BLACK 1 #define DOLE if (OLE_DNORMAL(ole->debug)) #define VOLE if (ole->verbose) unsigned char OLE_id_v2[]={ 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 }; unsigned char OLE_id_v1[]={ 0x0e, 0x11, 0xfc, 0x0d, 0xd0, 0xcf, 0x11, 0xe0 }; /*-----------------------------------------------------------------\ Function Name : OLE_version Returns Type : int ----Parameter List 1. void , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_version( void ) { fprintf(stderr,"ripOLE: %s\n", LIBOLE_VERSION); return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_init Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: 20041127-2029:PLD: Added file_size initialization \------------------------------------------------------------------*/ int OLE_init( struct OLE_object *ole ) { ole->debug = 0; ole->verbose = 0; ole->quiet = 0; ole->filename_report_fn = NULL; ole->f = NULL; ole->file_size = 0; ole->FAT = NULL; ole->FAT_limit = NULL; ole->miniFAT = NULL; ole->miniFAT_limit = NULL; ole->header_block[0] = '\0'; ole->ministream = NULL; ole->properties = NULL; ole->header.sector_shift = 0; ole->header.mini_sector_shift = 0; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_dir_init Returns Type : int ----Parameter List 1. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_dir_init(struct OLE_directory_entry *dir ) { memset(dir->element_name,'\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE); dir->element_name_byte_count = 0; dir->element_type = 0; dir->element_colour = 0; dir->left_child = 0; dir->right_child = 0; dir->root = 0; dir->class[0] = '\0'; dir->userflags = 0; dir->timestamps[0] = '\0'; dir->start_sector = 0; dir->stream_size = 0; return 0; }; /*-----------------------------------------------------------------\ Function Name : OLE_set_verbose Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_verbose( struct OLE_object *ole, int level ) { ole->verbose = level; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_quiet Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_quiet( struct OLE_object *ole, int level ) { ole->quiet = level; ole->verbose = 0; ole->debug = 0; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_debug Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_debug( struct OLE_object *ole, int level ) { ole->debug = level; if (ole->debug > 0) LOGGER_log("%s:%d:OLE_set_debug: Debug level set to %d",FL, ole->debug); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_set_save_unknown_streams Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_save_unknown_streams( struct OLE_object *ole, int level ) { ole->save_unknown_streams = level; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_sectorpos Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int SID , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: Given a sector ID, this function will return the file position offset. Assumes that the offset for the file starts at 512 bytes (which is the size of the OLE header) -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_sectorpos( struct OLE_object *ole, int SID ) { int pos = 0; pos = 512 +(SID *ole->header.sector_size); return pos; } /*-----------------------------------------------------------------\ Function Name : OLE_get_block Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int block_index, Block indexes / Sector ID's are signed ints. 3. unsigned char *block_buffer , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_block( struct OLE_object *ole, int block_index, unsigned char *block_buffer ) { if (block_buffer == NULL) { LOGGER_log("%s:%d:OLE_get_block:ERROR: Block buffer is NULL",FL); return -1; } if (ole->f != NULL) { int read_count = 0; int fseek_result = 0; size_t offset = 0; unsigned char *bb = NULL; bb = malloc(sizeof(unsigned char) *ole->header.sector_size); if (bb == NULL) { LOGGER_log("%s:%d:OLE_get_block:ERROR: Cannot allocate %d bytes for OLE block",FL, ole->header.sector_size); return -1; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: BlockIndex=%d, Buffer=0x%x",FL, block_index, block_buffer); //20051211-2343:PLD: offset = (block_index +1) << ole->header.sector_shift; offset = OLE_sectorpos(ole, block_index); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Read offset in file = 0x%x size to read= 0x%x",FL,offset,ole->header.sector_size); fseek_result = fseek(ole->f, offset, SEEK_SET); if (fseek_result != 0) { if (bb != NULL) { free(bb); bb = NULL; } LOGGER_log("%s:%d:OLE_get_block:ERROR: Seek failure (block=%d:%d)",FL, block_index,offset, strerror(errno)); return OLEER_GET_BLOCK_SEEK; } //read_count = fread(block_buffer, sizeof(unsigned char), ole->header.sector_size, ole->f); read_count = fread(bb, sizeof(unsigned char), ole->header.sector_size, ole->f); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Read %d byte of data",FL,read_count); if (read_count != (int)ole->header.sector_size) { if (bb != NULL){ free(bb); bb = NULL; } VOLE LOGGER_log("%s:%d:Mismatch in bytes read. Requested %d, got %d\n", FL, ole->header.sector_size, read_count); return OLEER_GET_BLOCK_READ; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Copying over memory read from file",FL); memcpy(block_buffer, bb, ole->header.sector_size); DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: memory block copied to block_buffer",FL); /* We're now done with BB, dispose of it */ if (bb) { free(bb); bb = NULL; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Disposed of temporary bb block",FL); } else { LOGGER_log("%s:%d:OLE_get_block:ERROR: OLE file is closed\n",FL); return -1; } DOLE LOGGER_log("%s:%d:OLE_get_block:DEBUG: Done",FL); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_get_miniblock Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. unsigned int block_index, 3. unsigned char *block_buffer , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_miniblock( struct OLE_object *ole, int block_index, unsigned char *block_buffer ) { if (ole->ministream) { int offset = block_index << ole->header.mini_sector_shift; memcpy( block_buffer, ole->ministream +offset, ole->header.mini_sector_size); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_dbstosbs Returns Type : int ----Parameter List 1. char *raw_string, 2. size_t char_count, 3. char *clean_string , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_dbstosbs( char *raw_string, size_t byte_count, char *clean_string, int clean_string_len ) { char *limit = raw_string +byte_count -1; clean_string_len--; while ((raw_string < limit)&&(byte_count >0)&&(byte_count--)&&(clean_string_len--)) { int v = (char)*raw_string; if (isprint(v)) { *clean_string = v; clean_string++; } raw_string += 2; } *clean_string = '\0'; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_string Returns Type : int ----Parameter List 1. char *string, 2. size_t length , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_string( char *string, size_t char_count) { while (char_count--) { printf("%c",*string); string += 2; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_sector Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. unsigned char *sector , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_sector( struct OLE_object *ole, char *sector, unsigned int bytes) { int current_byte; int ubytes = bytes; printf("\n"); for (current_byte = 0; current_byte < ubytes; current_byte++ ) { printf("%02X ", *(sector +current_byte)); if (((current_byte+1) %32)==0) { int j; for (j = current_byte -31; j <=current_byte; j++) { if (isalnum(*(sector +j))) printf("%c",*(sector+j)); else printf("."); } printf("\n"); } } printf("\n"); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_is_OLE_file Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_is_file_OLE( struct OLE_object *ole ) { if (memcmp(OLE_id_v1, ole->header_block, sizeof(OLE_id_v1))==0) return 1; if (memcmp(OLE_id_v2, ole->header_block, sizeof(OLE_id_v2))==0) return 1; return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_get_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_get_header( struct OLE_object *ole ) { int result = 0; ole->header.sector_size = OLE_HEADER_BLOCK_SIZE; result = OLE_get_block( ole, -1, ole->header_block ); if (OLE_is_file_OLE( ole ) == 0) { return OLEER_NOT_OLE_FILE; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_convert_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_convert_header( struct OLE_object *ole ) { struct OLE_header *h; unsigned char *hb; /** pointer to the header block **/ unsigned char *fat_start; unsigned int i; h = &(ole->header); hb = ole->header_block; /** Note that the header_*(hb) calls are actually macros which are ** defined in the ole.h file. These macros basically take the ** hb value and add the required offset, they don't affect the ** value of hb (or they certainly SHOULD NOT! ) **/ h->minor_version = get_uint16((char *)header_minor_version(hb)); h->dll_version = get_uint16((char *)header_dll_version(hb)); h->byte_order = get_uint16((char *)header_byte_order(hb)); /** 0xFEFF = Little endian, 0xFFFE = big endian **/ h->sector_shift = get_uint16((char *)header_sector_shift(hb)); h->sector_size = 1 << h->sector_shift; h->mini_sector_shift = get_uint16((char *)header_mini_sector_shift(hb)); h->mini_sector_size = 1 << h->mini_sector_shift; h->fat_sector_count = get_uint32((char *)header_fat_sector_count(hb)); /** Total number of sectors use for the SAT **/ h->directory_stream_start_sector = get_uint32((char *)header_directory_stream_start_sector(hb)); /** Start sector-ID for the DIRECTORY STREAM **/ h->mini_cutoff_size = get_uint32((char *)header_mini_cutoff_size(hb)); h->mini_fat_start = get_uint32((char *)header_mini_fat_start(hb)); h->mini_fat_sector_count = get_uint32((char *)header_mini_fat_sector_count(hb)); h->dif_start_sector = get_uint32((char *)header_dif_start_sector(hb)); h->dif_sector_count = get_uint32((char *)header_dif_sector_count(hb)); /** Compute the maximum possible sector number by taking our OLE filesize ** and dividing it by the size of our sector size. While this isn't ** absolutely accurate it is at least useful in providing us with an ** upper-bound of what is an acceptable sector ID **/ ole->last_sector = ole->file_size >> h->sector_shift; /** Decode our first 109 sector-ID's into the master sector allocation table (MSAT/FAT) **/ fat_start = header_fat_sectors(hb); for (i = 0; i < h->fat_sector_count; i++) { if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) break; h->FAT[i] = get_uint32( (char *)( fat_start +(LEN_ULONG *i))); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_header_sanity_check Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: Determines the degree of insanity in the header, returning it as an integer, 1 per degree of insanity. -------------------------------------------------------------------- Changes: 20041127-2027:PLD: Initial version \------------------------------------------------------------------*/ int OLE_header_sanity_check( struct OLE_object *ole ) { int insanity=0; int max_sectors; struct OLE_header *h; h = &(ole->header); max_sectors = ole->file_size / h->sector_size; if (h->sector_shift > 20) insanity++; if (h->mini_sector_shift > 10) insanity++; if (h->fat_sector_count < 0) insanity++; if (h->fat_sector_count > max_sectors) insanity++; if (h->directory_stream_start_sector > max_sectors) insanity++; return insanity; } /*-----------------------------------------------------------------\ Function Name : OLE_print_header Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_header( struct OLE_object *ole ) { unsigned int i; struct OLE_header *h; h = &(ole->header); printf( "Minor version = %d\n" "DLL version = %d\n" "Byte order = %d\n\n" "Sector shift = %d\n" "Sector size = %d\n" "Mini Sector shift = %d\n" "Mini sector size = %d\n\n" "FAT sector count = %d\n" "First FAT sector = %d\n\n" "Maximum ministream size = %d\n\n" "First MiniFAT sector = %d\n" "MiniFAT sector count = %d\n\n" "First DIF sector = %d\n" "DIF sector count = %d\n" "--------------------------------\n" ,h->minor_version ,h->dll_version ,h->byte_order ,h->sector_shift ,h->sector_size ,h->mini_sector_shift ,h->mini_sector_size ,h->fat_sector_count ,h->directory_stream_start_sector ,h->mini_cutoff_size ,h->mini_fat_start ,h->mini_fat_sector_count ,h->dif_start_sector ,h->dif_sector_count ); // Print out the FAT chain for (i = 0; i < h->fat_sector_count; i++) { if (i >= OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) break; // We can't read beyond the 109th sector location printf("FAT[%d] = %d\n", i, h->FAT[i]); } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_convert_directory Returns Type : int ----Parameter List 1. unsigned char *buf, 2. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_convert_directory( struct OLE_object *ole, unsigned char *buf, struct OLE_directory_entry *dir ) { /** Converts a raw block of 128 bytes from the file to a ** struct OLE_directory_entry data structure **/ /** Flush the element name **/ memset( dir->element_name, '\0', OLE_DIRECTORY_ELEMENT_NAME_SIZE); /** The first 64 bytes of the structure are the element's name ** in 16-bite UNICODE, meaning a maximum of 31 characters when ** we account for the trailing zero byte **/ /** Copy the first 64 bytes of our *buf parameter into the element name **/ memcpy( dir->element_name, buf, OLE_DIRECTORY_ELEMENT_NAME_SIZE ); /** how many bytes of the above 64 bytes are used for the name (NOT CHARACTERS!), ** ** example, for a 8 character string with a trailing zero we use ** ** (8+1)*2 = 18 bytes **/ dir->element_name_byte_count = get_int16( (char *) buf + 0x40 ); /** Element type is of the following: ** 0x00 - empty ** 0x01 - user storage ** 0x02 - user stream ** 0x03 - lock bytes (we don't know what this is for) ** 0x04 - property (again, we don't know) ** 0x05 - root storage **/ dir->element_type = get_int8((char *) buf +0x42 ); /** Element colour for the red-black tree: ** 0x00 - Red ** 0x01 - Black **/ dir->element_colour = get_int8((char*) buf +0x43 ); /** Directory ID (DID) of the left child, -1 if no sibling **/ dir->left_child = get_uint32((char*) buf +0x44 ); /** Directory ID (DID) of the right child, -1 if no sibling **/ dir->right_child = get_uint32((char *) buf +0x48 ); /** Directory ID (DID) of the root node entry of the RB tree of all ** storage members (if this entry is a storage), else -1. **/ dir->root = get_uint32((char*) buf +0x4c ); memcpy( dir->class, buf +0x50, 16 ); dir->userflags = get_uint32((char*) buf +0x60 ); memcpy( dir->timestamps, buf +0x64, 16 ); /** Actually consists of 2 8 byte stamps **/ /** Sector ID of the first sector or short-sector **/ dir->start_sector = get_uint32((char*) buf +0x74 ); /** Size of this stream **/ DOLE LOGGER_log("%s:%d:OLE_directory_entry:DEBUG: stream size = 0x%x %x %x %x" ,FL ,*(buf +0x78) ,*(buf +0x79) ,*(buf +0x7A) ,*(buf +0x7B) ); dir->stream_size = get_uint32((char *) buf +0x78 ); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_print_directory Returns Type : int ----Parameter List 1. struct OLE *ole, 2. struct OLE_directory_entry *dir , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_print_directory( struct OLE_object *ole, struct OLE_directory_entry *dir ) { char element[64]; OLE_dbstosbs( dir->element_name, dir->element_name_byte_count, element, sizeof(element) ); printf( "Element Name = %s\n" "Element type = %d\n" "Element colour = %d\n" "Left Child = %d\n" "Right Child = %d\n" "Root = %d\n" "User flags = %d\n" "Start sector = %ld\n" "Stream Size = %d\n" ,element ,dir->element_type ,dir->element_colour ,dir->left_child ,dir->right_child ,dir->root ,dir->userflags ,dir->start_sector ,dir->stream_size ); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_load_FAT Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_load_FAT( struct OLE_object *ole ) { unsigned int FAT_size; FAT_size = ole->header.fat_sector_count << ole->header.sector_shift; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG:Allocating for %d sectors (%d bytes) \n" ,FL,ole->header.fat_sector_count, FAT_size); ole->FAT = malloc( FAT_size *sizeof(unsigned char)); ole->FAT_limit = ole->FAT +FAT_size; if (ole->FAT != NULL) { unsigned int i; unsigned char *fat_position = ole->FAT; unsigned int sector_count = ole->header.fat_sector_count; if (sector_count > OLE_HEADER_FAT_SECTOR_COUNT_LIMIT) { sector_count = OLE_HEADER_FAT_SECTOR_COUNT_LIMIT; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: sector count greater than limit; set to %d",FL, sector_count); } // Load in all our primary-FAT sectors from the OLE file for (i = 0; i < sector_count; i++) { int getblock_result = 0; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading sector %d",FL, i); getblock_result = OLE_get_block(ole, ole->header.FAT[i], fat_position); if (getblock_result != 0) { // if the get block fails, return the error - but keep the FAT // pointer alive - so that we can facilitate debugging // otherwise the caller is always going to get a NULL pointer // and have no idea to what extent the data was read. // // This behavior may be changed later - but for now (beta development) // it'll be okay to leave it here - just make sure we know to // free the FAT block later. return getblock_result; } fat_position += ole->header.sector_size; if (fat_position > ole->FAT_limit) { LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT boundary limit exceeded %p > %p", FL, fat_position, ole->FAT_limit); return -1; } } // If our DIF count is > 0, this means we have a pretty big // file on hand (> 7Mb) and thus we now have to do some // fancy double-dereferenced sector request - enough to // twist your brain if you're not alert, you have been // warned. if (ole->header.dif_sector_count > 0) { unsigned char *fat_block; unsigned char *fat_block_end; unsigned int current_sector = ole->header.dif_start_sector; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Allocating %d bytes to fat_block\n",FL, ole->header.sector_size); fat_block = malloc( ole->header.sector_size ); if (fat_block == NULL) { LOGGER_log("%s:%d:OLE_load_FAT:ERROR: Unable to allocate %d bytes\n", FL, ole->header.sector_size); return -1; // exit(1); } // We need to know where the end of this block is - because it's // used to show us where the NEXT FAT block is going to come from // NOTE - this only occurs if we do have another block, else // we'll simply have to just realise that we don't need any more // blocks and stop with this one. fat_block_end = fat_block +ole->header.sector_size -LEN_ULONG; // We know we've got 'dif_sector_count' blocks to read, each of // these blocks hold no more than 127 sector addresses which // contain the actual FAT data we're after (this is the double // dereference bit that twists your brain ) DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Loading DIF sectors (count = %d)",FL,ole->header.dif_sector_count); for (i = 0; i < ole->header.dif_sector_count; i++) { int import_sector; unsigned char *DIF = fat_block; int tick = 0; int getblock_result; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT index-data[%d] from sector 0x%x",FL,i,current_sector); getblock_result = OLE_get_block(ole, current_sector, fat_block); if (getblock_result != OLE_OK) { if (fat_block) free(fat_block); return getblock_result; } if (OLE_DPEDANTIC(ole->debug)) OLE_print_sector(ole, (char *)fat_block, ole->header.sector_size); // Now, traverse this block until we hit a < 0 // If we get what is a non-valid sector value // we know we've reached the end of the valid // sectors from which to read more extended FAT // data. do { import_sector = get_int32( (char *) DIF ); DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: import sector = 0x%x",FL,import_sector); if (import_sector >= 0) { if (fat_position +ole->header.sector_size <= ole->FAT_limit) { DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Reading DIF/XBAT-data[%d] from sector 0x%x",FL,tick,import_sector); getblock_result = OLE_get_block(ole, import_sector, fat_position); if (getblock_result != OLE_OK) { LOGGER_log("%s:%d:OLE_load_FAT:ERROR: Not able to load block, import sector = 0x%x, fat position = 0x%x",FL, import_sector, fat_position); if (fat_block) free(fat_block); return getblock_result; } fat_position += ole->header.sector_size; DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: FAT position = 0x%x (start = 0x%x, end = 0x%x)" ,FL ,fat_position ,fat_block ,ole->FAT_limit ); //if (fat_position +ole->header.sector_size > ole->FAT_limit) if (fat_position > ole->FAT_limit) { DOLE LOGGER_log("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p",FL,fat_position,ole->FAT_limit); if (fat_block) free(fat_block); return OLEER_MEMORY_OVERFLOW; } tick++; DIF += LEN_ULONG; } else { LOGGER_log("%s:%d:OLE_load_FAT:ERROR: FAT memory boundary limit exceeded %p >= %p",FL,fat_position,ole->FAT_limit); if (fat_block) free(fat_block); return OLEER_MEMORY_OVERFLOW; } } else { VOLE LOGGER_log("%s:%d:OLE_load_FAT:ERROR: sector request was negative (%d)",FL, import_sector); } DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: DIF = 0x%x",FL,DIF); } while ((import_sector >= 0)&&(DIF < fat_block_end)); // Get the next sector of DIF/XBAT data ... // // If we still have more sectors full of extended FAT // sectors that we have to read, then we neet to // obtain the address of the next FAT-sector filled // sector if ( i < ole->header.dif_sector_count -1 ) { current_sector = get_uint32((char *) fat_block_end ); DOLE LOGGER_log("%s:%d:OLE_load_FAT:DEBUG: Next DIF/XBAT index sector located at 0x%x",FL,current_sector); if (current_sector < 0) break; } } // For every DIF/XBAT sector we're supposed to read if (fat_block) free(fat_block); } // If we have DIF/XBAT sectors to read into the FAT } // If we managed to allocate memory for our FAT table return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_follow_chain Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_follow_chain( struct OLE_object *ole, int FAT_sector_start ) { int current_sector = FAT_sector_start; int chain_length=0; int last_sector_of_file = ole->last_sector; int break_out = 0; struct bti_node *n; BTI_init(&n); if (FAT_sector_start < 0) return 0; DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Starting chain follow at sector %d",FL, FAT_sector_start ); do { unsigned int next_sector; unsigned char *next_sector_location; next_sector_location = ole->FAT +(LEN_ULONG *current_sector); if (next_sector_location > (ole->FAT_limit -4)) { DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: ERROR: Next sector was outside of the limits of this file (%ld > %ld)",FL, next_sector_location, ole->FAT_limit); break; } //next_sector = get_4byte_value( ole->FAT +(LEN_ULONG *current_sector)); next_sector = get_uint32((char*) next_sector_location ); if (BTI_add(&n, next_sector) != 0) { DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: Sector collision, terminating chain traversal",FL); chain_length=-1; break; } DOLE LOGGER_log("%s:%d:OLE_follow_chain:DEBUG: 0x%0X:%d)->(0x%0X:%d)\n",FL, current_sector, current_sector, next_sector, next_sector); // 20040729-10H37 Added this to prevent endless loop which sometimes occurs at sector 0 if (next_sector == current_sector) break; // fflush(stdout); current_sector = next_sector; chain_length++; /** Test to see if we should terminate this chain traversal **/ switch (current_sector) { case OLE_SECTORID_MSAT: case OLE_SECTORID_SAT: case OLE_SECTORID_ENDOFCHAIN: case OLE_SECTORID_FREE: break_out=1; break; default: break_out=0; }; if (current_sector < 0) break_out = 1; } while ((break_out==0)&&(current_sector < last_sector_of_file)); BTI_done(&n); return chain_length; } /*-----------------------------------------------------------------\ Function Name : OLE_follow_minichain Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_follow_minichain( struct OLE_object *ole, int miniFAT_sector_start ) { //unsigned int current_sector = miniFAT_sector_start; int current_sector = miniFAT_sector_start; int chain_length=0; int break_out = 0; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Starting at sector %d",FL, miniFAT_sector_start); if (miniFAT_sector_start < 0) return 0; do { unsigned int next_sector; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requesting 4-byte value at '%d'",FL, ole->miniFAT +(LEN_ULONG *current_sector)); if (ole->miniFAT +(LEN_ULONG *current_sector) > ole->miniFAT_limit) { DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Requested location is out of bounds\n",FL); return 0; } next_sector = get_uint32((char*) ole->miniFAT +(LEN_ULONG *current_sector)); DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Current Msector(0x%0X:%d)->next(0x%0X:%d)\n", FL, current_sector, current_sector, next_sector, next_sector); /** Check for conditions that indicate we should stop traversing this chain **/ /** 1. We cannot point to ourselves **/ if (current_sector == next_sector) break; chain_length++; current_sector = next_sector; /** Test for non-positive type sector ID's **/ switch (current_sector) { case OLE_SECTORID_MSAT: case OLE_SECTORID_SAT: case OLE_SECTORID_ENDOFCHAIN: case OLE_SECTORID_FREE: break_out=1; break; default: break_out=0; }; DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: current sector = %d",FL,current_sector); } while ((break_out==0)&&(current_sector <= ole->last_sector )); DOLE LOGGER_log("%s:%d:OLE_follow_minichain:DEBUG: Done. Chainlength=%d",FL, chain_length); return chain_length; } /*-----------------------------------------------------------------\ Function Name : char Returns Type : unsigned ----Parameter List 1. *OLE_load_minichain( struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: PLD:2003-Aug-28: Added sanity checking on the miniFAT_sector_start value so that we didn't try to load up a miniFAT starting on a negative value \------------------------------------------------------------------*/ unsigned char *OLE_load_minichain( struct OLE_object *ole, int miniFAT_sector_start ) { int chain_length = 0; int current_sector = miniFAT_sector_start; unsigned char *buffer; unsigned char *bp; DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading minichain starting at %d",FL, miniFAT_sector_start); // Added this sanity checking 2003 Aug 28 if (miniFAT_sector_start < 0) return NULL; chain_length = OLE_follow_minichain( ole, miniFAT_sector_start ); DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Found %d mini-sectors to load (%d bytes)\n",FL, chain_length, chain_length *ole->header.mini_sector_size); // 20040911-21H59 // If our chain is 0 length, then there's nothing to return if (chain_length == 0) return NULL; bp = buffer = malloc( chain_length *ole->header.mini_sector_size *sizeof(unsigned char)); if (buffer != NULL) { do { unsigned int next_sector; DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Loading sector %d",FL, current_sector); OLE_get_miniblock( ole, current_sector, bp ); bp += ole->header.mini_sector_size; next_sector = get_uint32((char *)( ole->miniFAT +(LEN_ULONG *current_sector))); current_sector = next_sector; } while ((current_sector != OLE_SECTORID_ENDOFCHAIN)&&(current_sector >= 0)&&(current_sector <= ole->last_sector)); } else { LOGGER_log("%s:%d:OLE_get_miniblock:ERROR: Failed to allocate enough memory for miniChain",FL); } DOLE LOGGER_log("%s:%d:OLE_load_minichain:DEBUG: Done. buffer=%p",FL, buffer); return buffer; } /*-----------------------------------------------------------------\ Function Name : char Returns Type : unsigned ----Parameter List 1. *OLE_load_chain( struct OLE_object *ole, 2. int FAT_sector_start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: Make the loading aware of negative-value sectors so that it can make more intelligent exit strategies. \------------------------------------------------------------------*/ unsigned char *OLE_load_chain( struct OLE_object *ole, int FAT_sector_start ) { int chain_length = 0; int current_sector = FAT_sector_start; unsigned char *buffer = NULL; unsigned char *bp = NULL; ole->last_chain_size = 0; if (FAT_sector_start < 0) return NULL; DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading chain, starting at sector %d",FL,FAT_sector_start); chain_length = OLE_follow_chain( ole, FAT_sector_start ); DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: %d sectors need to be loaded",FL,chain_length); if (chain_length > 0) { size_t offset; offset = ole->last_chain_size = chain_length << ole->header.sector_shift; bp = buffer = malloc( offset *sizeof(unsigned char)); if (buffer == NULL) { LOGGER_log("%s:%d:OLE_load_chain:ERROR: Cannot allocate %d bytes for OLE chain",FL,offset); return NULL; } if (buffer != NULL) { int tick = 0; unsigned char *bp_limit; bp_limit = bp +offset; do { int next_sector; DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Loading sector[%d] %d",FL, tick, current_sector ); ole->error = OLE_get_block( ole, current_sector, bp ); if (ole->error != OLE_OK) { //FREE5 if (bp != NULL) free(bp); return NULL; } bp += ole->header.sector_size; if (bp > bp_limit) { if (buffer != NULL) { free(buffer); bp = buffer = NULL; } VOLE LOGGER_log("%s:%d:OLE_load_chain:ERROR: Load-chain went over memory boundary",FL); return NULL; }; next_sector = get_uint32((char *)( ole->FAT +(LEN_ULONG *current_sector))); current_sector = next_sector; tick++; } while ((current_sector >= 0)&&(current_sector <= ole->last_sector)); } } DOLE LOGGER_log("%s:%d:OLE_load_chain:DEBUG: Done loading chain",FL); return buffer; } /*-----------------------------------------------------------------\ Function Name : OLE_open_file Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *fullpath , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: 20041127-2033:PLD: Added ole->file_size setting so that we can use this in the sanity checking to see if the requested sectors are outside of the possible valid filesize range. \------------------------------------------------------------------*/ int OLE_open_file( struct OLE_object *ole, char *fullpath ) { struct stat st; int stat_result; FILE *f; stat_result = stat(fullpath, &st); if (stat_result != 0) { DOLE LOGGER_log("%s:%d:OLE_open_file:ERROR: Cannot locate file '%s' for opening (%s)",FL, fullpath, strerror(errno)); return OLEER_BAD_INPUT_FILE; } DOLE LOGGER_log("%s:%d:OLE_open_file:DEBUG: File size of %s = %ld",FL, fullpath, st.st_size); if ((stat_result == 0) && (st.st_size < 512)) return OLEER_NOT_OLE_FILE; ole->file_size = st.st_size; f = fopen(fullpath,"r"); if (f == NULL) { ole->f = NULL; if (ole->quiet == 0) { LOGGER_log("%s:%d:OLE_open_file:ERROR:Cannot open %s for reading (%s)\n",FL,fullpath, strerror(errno)); } return -1; } else { ole->f = f; ole->file_size = st.st_size; ole->last_sector = -1; } return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_open_directory Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *directory , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_open_directory( struct OLE_object *ole, char *directory ) { int result=0; result = mkdir( directory, S_IRWXU ); if ((result != 0)&&(errno != EEXIST)) { LOGGER_log("%s:%d:OLE_open_directory:ERROR: %s",FL,strerror(errno)); } else result = OLE_OK; return result; } /*-----------------------------------------------------------------\ Function Name : OLE_set_filename_report_fn Returns Type : int ----Parameter List 1. int (*ptr_to_fn)(char *) , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: This is merely a passthrough function to the OLEUW one, we do this in order to avoid having to force the calling parent from having to #include the OLEUW headers as well -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_set_filename_report_fn( struct OLE_object *ole, int (*ptr_to_fn)(char *) ) { ole->filename_report_fn = ptr_to_fn; return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_store_stream Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. char *stream_name, 3. char *directory, 4. unsigned char *stream , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_store_stream( struct OLE_object *ole, char *stream_name, char *directory, char *stream, size_t stream_size ) { char *full_path = NULL; full_path = PLD_dprintf("%s/%s", directory, stream_name); if (full_path == NULL) { LOGGER_log("%s:%d:OLE_store_stream:ERROR: Cannot compose full filename string from '%s' and '%s'", FL, directory, stream_name); return -1; } else { FILE *f; f = fopen(full_path,"w"); if (f == NULL) { LOGGER_log("%s:%d:OLE_store_stream:ERROR: Cannot open %s for writing (%s)",FL, full_path, strerror(errno)); if (full_path) free(full_path); return -1; } else { size_t written_bytes; written_bytes = fwrite( stream, 1, stream_size, f ); if (written_bytes != stream_size) { LOGGER_log("%s:%d:OLE_store_stream:WARNING: Only wrote %d of %d bytes to file %s",FL,written_bytes,stream_size,full_path); } fclose(f); if ((OLE_VNORMAL(ole->verbose))&&(ole->filename_report_fn != NULL)) { ole->filename_report_fn( stream_name ); } } // if file is valid } // if full_path is valid if (full_path) free(full_path); return OLE_OK; } /*-----------------------------------------------------------------\ Function Name : OLE_decode_file_done Returns Type : int ----Parameter List 1. struct OLE_object *ole , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_decode_file_done( struct OLE_object *ole ) { if (ole->f) fclose(ole->f); /** Why weren't these active? (they were commented out ) **/ if (ole->FAT) free(ole->FAT); if (ole->miniFAT) free(ole->miniFAT); if (ole->ministream) free(ole->ministream); if (ole->properties) free(ole->properties); return 0; } /*-----------------------------------------------------------------\ Function Name : OLE_terminate_and_return Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. int result , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_terminate_and_return( struct OLE_object *ole, int result ) { OLE_decode_file_done(ole); return result; } #ifdef RIPOLE_WALK_TREE int OLE_walk_tree( struct OLE_object *ole, char *fname, char *decode_path, int depth ) { /** Sanity check **/ if (depth > 100) return 0; if (ole->total_file_count > 10000) return 0; if (element_type < 0) return 0; switch (element_type) { case STGTY_ROOT: /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ DOLE LOGGER_log("%s:%d:OLE_walk_tree:DEBUG: Loading ministream/SmallBlockArray",FL); ole->ministream = OLE_load_chain( ole, adir->start_sector ); if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done",FL); } } else if (adir->element_type == STGTY_STORAGE) { /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n",FL,i); ole->ministream = OLE_load_chain( ole, adir->start_sector ); if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done",FL); } #endif /*-----------------------------------------------------------------\ Date Code: : 20081101-020137 Function Name : OLE_decode_stream Returns Type : int ----Parameter List 1. struct OLE_object *ole, 2. struct OLE_directory_entry *adir, 3. char *decode_path , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_decode_stream( struct OLE_object *ole, struct OLE_directory_entry *adir, char *decode_path ) { unsigned char *stream_data; struct OLEUNWRAP_object oleuw; int decode_result = OLEUW_STREAM_NOT_DECODED; char element_name[64]; int result = 0; memset(element_name, '\0', 64); OLE_dbstosbs( adir->element_name, adir->element_name_byte_count, element_name, 64 ); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Decoding stream '%s'",FL, element_name); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Initializing stream unwrapper",FL); OLEUNWRAP_init(&oleuw); OLEUNWRAP_set_debug(&oleuw,ole->debug); OLEUNWRAP_set_verbose(&oleuw,ole->verbose); OLEUNWRAP_set_filename_report_fn(&oleuw, ole->filename_report_fn); OLEUNWRAP_set_save_unknown_streams(&oleuw, ole->save_unknown_streams); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Unwrap engine set.",FL); if (adir->stream_size >= ole->header.mini_cutoff_size) { /** Standard size sector stored stream **/ /** Standard size sector stored stream **/ /** Standard size sector stored stream **/ DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Loading normal sized chain starting at sector %d",FL, adir->start_sector); stream_data = OLE_load_chain( ole, (int)adir->start_sector ); if (stream_data == NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Terminating from stream data being NULL ",FL); //OLE_decode_file_done(ole); return OLEER_MINISTREAM_STREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode START. element name ='%s' stream size = '%ld'",FL, element_name, adir->stream_size); decode_result = OLEUNWRAP_decodestream( &oleuw, element_name, (char *)stream_data, adir->stream_size, decode_path ); DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Normal decode done.",FL); } else { /** Minichain/Minisector stored stream **/ /** Minichain/Minisector stored stream **/ /** Minichain/Minisector stored stream **/ DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Minichain loader, starting at sector %d" ,FL ,adir->start_sector ); stream_data = OLE_load_minichain( ole, adir->start_sector ); if (stream_data == NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Ministream was non-existant, terminating",FL); //OLE_decode_file_done(ole); return OLEER_NORMALSTREAM_STREAM_READ_FAIL; } DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode START.",FL); decode_result = OLEUNWRAP_decodestream( &oleuw, element_name, (char *)stream_data, adir->stream_size, decode_path ); DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Mini decode done.",FL); } if ((stream_data != NULL)&&(decode_result == OLEUW_STREAM_NOT_DECODED)&&(ole->save_unknown_streams)) { char *lfname; lfname = PLD_dprintf("ole-stream.%d",adir->start_sector); if (lfname != NULL) { DOLE LOGGER_log("%s:%d:OLE_decode_stream:DEBUG: Saving stream to %s",FL,lfname); OLE_store_stream( ole, lfname, decode_path, (char *) stream_data, adir->stream_size ); free(lfname); } } // If we needed to save an unknown stream // Clean up an stream_data which we may have // read in from the chain-loader. if (stream_data) free(stream_data); return result; } /*-----------------------------------------------------------------\ Function Name : OLE_decode_file Returns Type : int ----Parameter List 1. char *fname, 2. char *decode_path , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLE_decode_file( struct OLE_object *ole, char *fname, char *decode_path ) { unsigned char *current_property, *property_limit; int result = 0; int i; // Reject any bad paramters. if (ole == NULL) return OLEER_DECODE_NULL_OBJECT; if (fname == NULL) return OLEER_DECODE_NULL_FILENAME; if (decode_path == NULL) return OLEER_DECODE_NULL_PATH; // We need to gain access to the OLE2 data file, without // this pretty much everything is pointless. DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening %s", FL, fname ); result = OLE_open_file( ole, fname ); if (result != 0) return result; // Try create the output directory which we're using // to write the decoded files out to. DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: opening output directory %s", FL, decode_path); result = OLE_open_directory( ole, decode_path ); if (result != 0) return result; // In order to successfully decode an OLE2 stream, we have to read // and understand the first 512 bytes of the file, this is the // OLE2 header. DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Getting main header", FL); result = OLE_get_header( ole ); if (result != 0) return result; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Converting main header", FL); result = OLE_convert_header( ole ); if (result != 0) return result; result = OLE_header_sanity_check( ole ); if (result > 0) return OLEER_INSANE_OLE_FILE; DOLE OLE_print_header( ole ); DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading FAT", FL); result = OLE_load_FAT( ole ); if (result != 0) return result; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading miniFAT chain", FL); ole->miniFAT = OLE_load_chain( ole, ole->header.mini_fat_start ); if (ole->miniFAT == NULL) return OLEER_MINIFAT_READ_FAIL; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading Directory stream chain", FL); ole->properties = OLE_load_chain( ole, ole->header.directory_stream_start_sector ); if (ole->properties == NULL) return OLEER_PROPERTIES_READ_FAIL; i=0; current_property = ole->properties; property_limit = current_property +ole->last_chain_size ; // while(1) while (current_property < property_limit) { struct OLE_directory_entry a_dir_object, *adir; int property_value=0; adir = &a_dir_object; OLE_dir_init(adir); property_value = get_uint8((char *)current_property); if (property_value < 1) break; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG:--------- DIRECTORY INDEX: %d",FL,i); OLE_convert_directory( ole, current_property, adir ); DOLE { LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Printing directory details...",FL); OLE_print_directory( ole, adir); LOGGER_log("%s:%d:OLE_decode_file:DEBUG: End of directory details",FL); } if (adir->element_colour > 1) break; if ((adir->element_type == STGTY_INVALID)||(adir->element_type > STGTY_ROOT)) { DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: breaking out due to element type %d",FL, adir->element_type); break; } else if (adir->element_type == STGTY_ROOT){ /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ /** ROOT DIRECTORY ENTRY **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Loading ministream/SmallBlockArray",FL); ole->ministream = OLE_load_chain( ole, adir->start_sector ); if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: ministream done",FL); } else if (adir->element_type == STGTY_STORAGE) { /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ /** STORAGE ELEMENT **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Item is directory, start child is at index %d\n",FL,i); ole->ministream = OLE_load_chain( ole, adir->start_sector ); if (ole->ministream == NULL) return OLEER_MINISTREAM_READ_FAIL; DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: DIRECTORY ministream done",FL); } else if (adir->element_type == STGTY_STREAM) { /** STREAM ELEMENT **/ /** STREAM ELEMENT **/ /** STREAM ELEMENT **/ OLE_decode_stream( ole, adir, decode_path ); } else { /** If the element isn't of the above types then it's possibly ** an empty element or just one used for the MSAT/SAT ** either way we just step over it and carry on **/ DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Element type %d does not need to be handled",FL,adir->element_type); } // Jump to the next property record, which // is always 128 bytes ahead. current_property += 128; i++; } // While there are still more directory entries to read in. DOLE LOGGER_log("%s:%d:OLE_decode_file:DEBUG: Finished",FL); /* //if (ole->f) fclose(ole->f); fclose(ole->f); if (ole->FAT) free(ole->FAT); if (ole->miniFAT) free(ole->miniFAT); if (ole->ministream) free(ole->ministream); if (ole->properties) free(ole->properties); */ return OLE_OK; } ripole-0.2-dev/ole.h0000644000175000001440000001117511102627641013054 0ustar pldusers #ifndef LIBOLE #define LIBOLE #define LIBOLE_VERSION "200811010143" #define OLE_OK 0 #define OLEER_NO_INPUT_FILE 100 #define OLEER_BAD_INPUT_FILE 101 #define OLEER_NOT_OLE_FILE 102 #define OLEER_INSANE_OLE_FILE 103 #define OLEER_DECODE_NULL_OBJECT 10 #define OLEER_DECODE_NULL_FILENAME 11 #define OLEER_DECODE_NULL_PATH 12 #define OLEER_MINIFAT_READ_FAIL 30 #define OLEER_PROPERTIES_READ_FAIL 31 #define OLEER_MINISTREAM_READ_FAIL 32 #define OLEER_MINISTREAM_STREAM_READ_FAIL 33 #define OLEER_NORMALSTREAM_STREAM_READ_FAIL 34 #define OLEER_GET_BLOCK_SEEK 41 #define OLEER_GET_BLOCK_READ 42 #define OLEER_MEMORY_OVERFLOW 50 #define OLE_VERBOSE_NORMAL 1 #define OLE_VERBOSE_FATREAD 2 #define OLE_VERBOSE_DIRREAD 4 #define OLE_VERBOSE_STREAMREAD 8 #define OLE_VERBOSE_STREAMDECODE 16 #define OLE_VNORMAL(x) ((x) && OLE_VERBOSE_NORMAL == OLE_VERBOSE_NORMAL ) #define OLE_DEBUG_NORMAL 1 #define OLE_DEBUG_PEDANTIC 2 #define OLE_DNORMAL(x) ((x) && OLE_DEBUG_NORMAL == OLE_DEBUG_NORMAL) #define OLE_DPEDANTIC(x) ((x) && OLE_DEBUG_PEDANTIC == OLE_DEBUG_PEDANTIC) #define OLE_HEADER_FAT_SECTOR_COUNT_LIMIT 109 struct OLE_header { unsigned int minor_version; unsigned int dll_version; unsigned int byte_order; unsigned int sector_shift; unsigned int sector_size; unsigned int mini_sector_shift; unsigned int mini_sector_size; unsigned int fat_sector_count; unsigned int directory_stream_start_sector; unsigned int mini_cutoff_size; unsigned int mini_fat_start; unsigned int mini_fat_sector_count; unsigned int dif_start_sector; unsigned int dif_sector_count; unsigned int FAT[OLE_HEADER_FAT_SECTOR_COUNT_LIMIT]; }; #define OLE_DIRECTORY_ELEMENT_NAME_SIZE 64 #define OLE_DIRECTORY_CLASS_SIZE 16 #define OLE_DIRECTORY_TIMESTAMPS_SIZE 16 struct OLE_directory_entry { char element_name[OLE_DIRECTORY_ELEMENT_NAME_SIZE]; int element_name_byte_count; char element_type; char element_colour; unsigned int left_child; unsigned int right_child; unsigned int root; unsigned char class[OLE_DIRECTORY_CLASS_SIZE]; unsigned int userflags; unsigned char timestamps[OLE_DIRECTORY_TIMESTAMPS_SIZE]; long int start_sector; unsigned int stream_size; }; #define OLE_HEADER_BLOCK_SIZE 512 struct OLE_object { int error; size_t file_size; int last_sector; size_t last_chain_size; FILE *f; unsigned char *FAT; unsigned char *FAT_limit; /** Added to prevent segment violations **/ unsigned char *miniFAT; unsigned char *miniFAT_limit; /** Added to prevent segment violations **/ unsigned char header_block[OLE_HEADER_BLOCK_SIZE]; unsigned char *ministream; unsigned char *properties; struct OLE_header header; // End user configurable parameters: int debug; int verbose; int quiet; int save_unknown_streams; int save_streams; int save_mini_streams; int save_normal_streams; int decode_streams; int decode_mini_streams; int decode_normal_streams; int (*filename_report_fn)(char *); }; // Prototypes int OLE_version( void ); int OLE_init( struct OLE_object *ole ); int OLE_set_verbose( struct OLE_object *ole, int level ); int OLE_set_debug( struct OLE_object *ole, int level ); int OLE_set_quiet( struct OLE_object *ole, int level ); int OLE_set_save_unknown_streams( struct OLE_object *ole, int level ); int OLE_get_block( struct OLE_object *ole, int block_index, unsigned char *block_buffer ); int OLE_get_miniblock( struct OLE_object *ole, int block_index, unsigned char *block_buffer ); int OLE_dbstosbs( char *raw_string, size_t char_count, char *clean_string, int clean_string_len ); int OLE_print_string( char *string, size_t char_count); int OLE_print_sector( struct OLE_object *ole, char *sector, unsigned int bytes); int OLE_get_header( struct OLE_object *ole ); int OLE_convert_header( struct OLE_object *ole ); int OLE_print_header( struct OLE_object *ole ); int OLE_convert_directory(struct OLE_object *ole, unsigned char *buf, struct OLE_directory_entry *dir ); int OLE_print_directory( struct OLE_object *ole, struct OLE_directory_entry *dir ); int OLE_load_FAT( struct OLE_object *ole ); int OLE_follow_chain( struct OLE_object *ole, int FAT_sector_start ); int OLE_follow_minichain( struct OLE_object *ole, int miniFAT_sector_start ); unsigned char *OLE_load_minichain( struct OLE_object *ole, int miniFAT_sector_start ); unsigned char *OLE_load_chain( struct OLE_object *ole, int FAT_sector_start ); int OLE_open_file( struct OLE_object *ole, char *fullpath ); int OLE_decode_file( struct OLE_object *ole, char *fname, char *decode_path ); int OLE_decode_file_done( struct OLE_object *ole ); // Our callbacks. int OLE_set_filename_report_fn( struct OLE_object *ole, int (*ptr_to_fn)(char *) ); #endif ripole-0.2-dev/olestream-unwrap.c0000644000175000001440000003500111102627641015567 0ustar pldusers#include #include #include #include #include #include "logger.h" #include "pldstr.h" #include "bytedecoders.h" #include "olestream-unwrap.h" #define DUW if (oleuw->debug) struct OLE10_header{ unsigned char data[6]; char *attach_name; unsigned char data2[8]; char *fname_1; char *fname_2; size_t attach_size; size_t attach_size_1; size_t attach_start_offset; }; struct ESCHER_header_fixed { int spid_max; size_t cidcl; size_t cspsaved; size_t cdgsaved; }; struct typesig { char *sequence; int length; int offset; }; /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_init Returns Type : int ----Parameter List 1. struct OLEUNWRAP_object *oleuw , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_init( struct OLEUNWRAP_object *oleuw ) { oleuw->debug = 0; oleuw->verbose = 0; oleuw->filename_report_fn = NULL; return OLEUW_OK; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_set_debug Returns Type : int ----Parameter List 1. struct OLEUNWRAP_object *oleuw, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_set_debug( struct OLEUNWRAP_object *oleuw, int level ) { oleuw->debug = level; return OLEUW_OK; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_set_verbose Returns Type : int ----Parameter List 1. struct OLEUNWRAP_object *oleuw, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_set_verbose( struct OLEUNWRAP_object *oleuw, int level ) { oleuw->verbose = level; return OLEUW_OK; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_set_save_unknown_streams Returns Type : int ----Parameter List 1. struct OLEUNWRAP_object *oleuw, 2. int level , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_set_save_unknown_streams( struct OLEUNWRAP_object *oleuw, int level ) { oleuw->save_unknown_streams = level; return OLEUW_OK; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_save_stream Returns Type : int ----Parameter List 1. char *fname, 2. char *stream, 3. size_t bytes , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_save_stream( struct OLEUNWRAP_object *oleuw, char *fname, char *decode_path, char *stream, size_t bytes ) { char *full_name; FILE *f; int result = 0; DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: fname=%s, decodepath=%s, size=%ld" ,FL ,fname ,decode_path ,bytes ); full_name = PLD_dprintf("%s/%s", decode_path, fname ); if (full_name == NULL) { LOGGER_log("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to create filename string from '%s' and '%s'",FL,fname,decode_path); return -1; } f = fopen(full_name,"w"); if (f != NULL) { size_t write_count; write_count = fwrite( stream, 1, bytes, f ); if (write_count != bytes) { LOGGER_log("%s:%d:OLEUNWRAP_save_stream:WARNING: Only wrote %d of %d bytes to file %s\n",FL, write_count, bytes, full_name ); } fclose(f); } else { LOGGER_log("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to open %s for writing (%s)\n",FL,full_name, strerror(errno)); result = -1; } if (full_name) free(full_name); DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: Done saving '%s'",FL, fname); return result; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_sanitize_filename Returns Type : int ----Parameter List 1. char *fname , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_sanitize_filename( char *fname ) { if (fname == NULL) return 0; while (*fname) { if( !isalnum((int)*fname) && (*fname != '.') ) *fname='_'; if( (*fname < ' ')||(*fname > '~') ) *fname='_'; fname++; } return 0; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_seach_for_file_sig Returns Type : int ----Parameter List 1. char *block , ------------------ Exit Codes : Returns the offset from the block to the start of the signature. Returns -1 if not found. Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_seach_for_file_sig( struct OLEUNWRAP_object *oleuw, char *block, size_t block_len ) { int result = -1; int hit = 0; char *p; /** signature pointer **/ char *bp; /** pointer in the block **/ struct typesig sigs[]= { { "\x89\x50\x4e\x47", 4, 0 }, /** PNG **/ { "\xff\xd8\xff", 3, 0 }, /** JPEG **/ { NULL, -1, -1 } /** End of array **/ }; bp = block; block_len -= 4; /** While there's more data in the block and we're not found a match **/ while ((block_len > 0)&&(hit==0)) { struct typesig *tsp; /** Type signature pointer **/ block_len--; tsp = sigs; /** tsp points to the first signature in the array **/ /** While there's more valid signatures in the array **/ while (tsp->length > 0) { int cmpresult = 0; p = tsp->sequence; /** set p to point to the start of the image signature sequence **/ cmpresult = memcmp(bp, p, 3); if (cmpresult == 0) { DUW LOGGER_log("%s:%d:OLEUNWRAP_seach_for_file_sig:DEBUG: Hit at offset %d for signature %d",FL,(bp-block),(tsp -sigs)); hit = 1; break; } /** If we had a match in the signatures **/ tsp++; /** go to the next signature **/ } /** While more signatures **/ if (hit == 0) bp++; /** If we didn't get a hit, move to the next byte in the file **/ } /** while more data in the block **/ if (hit == 1) { result = bp -block; } else { result = -1; } return result; } /** Look for PNG signature **/ /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_decode_attachment Returns Type : int ----Parameter List 1. char *stream , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_decode_attachment( struct OLEUNWRAP_object *oleuw, char *stream, size_t stream_size, char *decode_path ) { struct OLE10_header oh; char *sp = stream; char *data_start_point = stream; int result = OLEUW_OK; // Get the data size oh.attach_size_1 = (size_t)get_int32( sp ); sp += 4; DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: attachsize = %d [ 0x%x ], stream length = %d [ 0x%x] \n", FL, oh.attach_size_1, oh.attach_size_1, stream_size, stream_size ); oh.attach_start_offset = (stream_size -oh.attach_size_1); data_start_point = stream +oh.attach_start_offset; //if (oh.attach_start_offset == 4) if (oh.attach_start_offset < 4) { int cbheader; // number of bytes in PIC int mfpmm; int mfpxext; int mfpyext; int mfphmf; // check next 4 bytes. cbheader = get_uint16( sp ); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: cbHeader = %d [ 0x%x ]", FL, cbheader, cbheader); mfpmm = get_uint16( sp +2 ); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.mm = %d [ 0x%x ]", FL, mfpmm, mfpmm); mfpxext = get_uint16( sp +4 ); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.xext = %d [ 0x%x ]", FL, mfpxext, mfpxext); mfpyext = get_uint16( sp +8 ); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.yext = %d [ 0x%x ]", FL, mfpyext, mfpyext); mfphmf = get_uint16( sp +10 ); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: mfp.hmf = %d [ 0x%x ]", FL, mfphmf, mfphmf); // If we only had the stream byte-lenght in our header // then we know we don't have a complex header. DUW { switch (mfpmm) { case 100: LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is Escher format",FL); break; case 99: LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is Bitmapped",FL); break; case 98: LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image is TIFF",FL); break; default: LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Unknown image type for code '%d'",FL, mfpmm); } } data_start_point = sp +cbheader -4; if (mfpmm == 100) { int imageoffset = 0; int search_size = 500; DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: searcing for image signatures",FL); if (stream_size < (search_size +68)) search_size = (stream_size -69); /** just make sure we don't over-search the stream **/ imageoffset = OLEUNWRAP_seach_for_file_sig(oleuw, data_start_point, search_size); if (imageoffset >= 0) { DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Image data found at offset %d",FL,imageoffset); data_start_point += imageoffset; } else { DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Could not detect image signature, dumping whole stream",FL); } } oh.attach_name = PLD_dprintf("image-%ld",oh.attach_size_1); oh.attach_size = oh.attach_size_1; oh.fname_1 = oh.fname_2 = NULL; DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Setting attachment name to '%s', size = %d",FL,oh.attach_name, oh.attach_size); } else { DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Decoding file information header",FL); // Unknown memory segment memcpy( oh.data, sp, 2 ); sp += 2; // Full attachment string oh.attach_name = strdup( sp ); sp = sp + strlen(oh.attach_name) +1; // Attachment full path oh.fname_1 = strdup( sp ); sp += strlen(oh.fname_1) +1; // Unknown memory segment memcpy( oh.data2, sp, 8 ); sp = sp +8; // Attachment full path oh.fname_2 = strdup( sp ); sp += strlen(oh.fname_2) +1; oh.attach_size = (size_t)get_uint32( sp ); sp += 4; if (oh.attach_size > stream_size) oh.attach_size = stream_size; data_start_point = sp; } DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Attachment %s:%s:%s size = %d\n",FL, oh.attach_name, oh.fname_1, oh.fname_2, oh.attach_size ); /** 20050119:2053:PLD - Added to sanitize 8-bit filenames **/ /** Sanitize the output filename **/ OLEUNWRAP_sanitize_filename(oh.attach_name); OLEUNWRAP_sanitize_filename(oh.fname_1); OLEUNWRAP_sanitize_filename(oh.fname_2); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Sanitized attachment filenames",FL); result = OLEUNWRAP_save_stream( oleuw, oh.attach_name, decode_path, data_start_point, oh.attach_size ); if (result == OLEUW_OK) { DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Calling reporter for the filename",FL); if ((oleuw->verbose > 0)&&(oleuw->filename_report_fn != NULL)) { oleuw->filename_report_fn(oh.attach_name); } // Do call back to reporting function } DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Cleaning up",FL); // Clean up our previously allocated data if (oh.fname_1 != NULL) free(oh.fname_1); if (oh.attach_name != NULL) free(oh.attach_name); if (oh.fname_2 != NULL) free(oh.fname_2); DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: done.",FL); return OLEUW_OK; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_decodestream Returns Type : int ----Parameter List 1. char *element_string, 2. char *stream , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_decodestream( struct OLEUNWRAP_object *oleuw, char *element_string, char *stream, size_t stream_size, char *decode_path ) { int result = OLEUW_OK; if (strstr(element_string, OLEUW_ELEMENT_10NATIVE_STRING) != NULL) { DUW LOGGER_log("%s:%d:OLEUNWRAP_decodestream:DEBUG: Debugging element '%s'",FL, element_string); OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path ); } else if (strstr(element_string, OLEUW_ELEMENT_DATA) != NULL) { DUW LOGGER_log("%s:%d:OLEUNWRAP_decodestream:DEBUG: Debugging element '%s'",FL, element_string); OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path ); } else { DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Unable to decode stream with element string '%s'\n", FL, element_string); result = OLEUW_STREAM_NOT_DECODED; } return result; } /*-----------------------------------------------------------------\ Function Name : OLEUNWRAP_set_filename_report_fn Returns Type : int ----Parameter List 1. struct OLEUNWRAP_object *oleuw, 2. int (*ptr_to_fn)(char *) , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int OLEUNWRAP_set_filename_report_fn( struct OLEUNWRAP_object *oleuw, int (*ptr_to_fn)(char *) ) { oleuw->filename_report_fn = ptr_to_fn; return 0; } ripole-0.2-dev/olestream-unwrap.h0000644000175000001440000000204311102627641015574 0ustar pldusers #define OLEUW_ELEMENT_10NATIVE 10 #define OLEUW_ELEMENT_10NATIVE_STRING "Ole10Native" #define OLEUW_ELEMENT_DATA "Data" #define OLEUW_OK 0 #define OLEUW_STREAM_NOT_DECODED 100 struct OLEUNWRAP_object { int (*filename_report_fn)(char *); int debug; int verbose; int save_unknown_streams; }; int OLEUNWRAP_init( struct OLEUNWRAP_object *oleuw ); int OLEUNWRAP_set_debug( struct OLEUNWRAP_object *oleuw, int level ); int OLEUNWRAP_set_verbose( struct OLEUNWRAP_object *oleuw, int level ); int OLEUNWRAP_set_save_unknown_streams( struct OLEUNWRAP_object *oleuw, int level ); int OLEUNWRAP_save_stream( struct OLEUNWRAP_object *oleuw, char *fname, char *decode_path, char *stream, size_t bytes ); int OLEUNWRAP_decode_attachment( struct OLEUNWRAP_object *oleuw, char *stream, size_t stream_size, char *decode_path ); int OLEUNWRAP_decodestream( struct OLEUNWRAP_object *oleuw, char *element_string, char *stream, size_t stream_size, char *decode_path ); int OLEUNWRAP_set_filename_report_fn( struct OLEUNWRAP_object *oleuw, int (*ptr_to_fn)(char *) ); ripole-0.2-dev/bytedecoders.c0000644000175000001440000000745111102627641014746 0ustar pldusers#include /*-----------------------------------------------------------------\ Function Name : int Returns Type : unsigned ----Parameter List 1. get_byte_value( unsigned char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int get_int8( char *start ) { return (int) *start; } /*-----------------------------------------------------------------\ Date Code: : 20081101-014815 Function Name : char Returns Type : unsigned ----Parameter List 1. get_uint8( char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ unsigned int get_uint8( char *start ) { return (unsigned char) *start; } /*-----------------------------------------------------------------\ Function Name : int Returns Type : unsigned ----Parameter List 1. get_ushort_value( unsigned char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int get_int16( char *start ) { int value = 0; value = (unsigned char)*start | (((unsigned char)*(start +1)) << 8); return value; } /*-----------------------------------------------------------------\ Date Code: : 20081101-014643 Function Name : int Returns Type : unsigned ----Parameter List 1. get_uint16( char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ unsigned int get_uint16( char *start ) { unsigned int value = 0; value = (unsigned char)*start | (((unsigned char)*(start +1)) << 8); return value; } /*-----------------------------------------------------------------\ Function Name : int Returns Type : unsigned ----Parameter List 1. get_ulong_value( unsigned char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int get_int32( char *start ) { int value = 0; value = (int)((unsigned char)*start) |(((unsigned char)*(start +1)) << 8) |(((unsigned char)*(start +2)) << 16) |(((unsigned char)*(start +3)) << 24); // printf("String=0x%x %x %x %x:%u = %d\n", *start, *(start +1), *(start +2), *(start +3), *(start +3), value); return value; } /*-----------------------------------------------------------------\ Date Code: : 20081101-014748 Function Name : int Returns Type : unsigned ----Parameter List 1. get_uint32( char *start , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ unsigned int get_uint32( char *start ) { unsigned int value = 0; value = (unsigned int)((unsigned char)*start) |(((unsigned char)*(start +1)) << 8) |(((unsigned char)*(start +2)) << 16) |(((unsigned char)*(start +3)) << 24); return value; } ripole-0.2-dev/bytedecoders.h0000644000175000001440000000041511102627641014744 0ustar pldusers#ifndef __BYTEDECODERS__ #define __BYTEDECODERS__ int get_int8( char *start ); int get_int16( char *start ); int get_int32( char *start ); unsigned int get_uint8( char *start ); unsigned int get_uint16( char *start ); unsigned int get_uint32( char *start ); #endif ripole-0.2-dev/CHANGELOG0000644000175000001440000001364111102627641013336 0ustar pldusers -----------------------------------ripOLE--------------------- 20081101-0215:PLD:DEV Cleaned up source code to make sure it builds without errors with the new stricter build defaults on many systems (such as Ubuntu 8.10). Changed the old bytedecoders file to now use the more sane get_uintX() and get_intX() type calls that make a bit more sense, also solves the annoying signed return value casting issues. 20051231-1055:PLD: ---Development update Improved the image signature detection routines to allow for variable length signatures and possible non-zero offsets. Signatures are now stored as an array of struct typesig. It could be possible to use an external filetype signature library to do this process but because we're only wanting to seek out images and of very few formats it simply isn't worth the overheads or speed penalty (we don't want to have to search through 200 bytes looking for up to 1000 different filetypes). 20051224-1030:PLD: ---Development update Added primative image detection routines to pull out PNG or JPG encoded data from an Escher formatted stream. The Escher format is rather complex so for now instead of trying to decode it properly we just scan ahead in the data a short distance to look for specific PNG or JPG signatures. 20051212-1100:PLD: ---Version 0.2.0 RELEASE Fixed up OLE Stream decoding - attachments now come out with the stream headers correctly stripped off. FINALLY! Reverted the sector-ID handling back to a SIGNED 4-byte integer, as negative values are required to signal special sector ID's. 20050315-1544:PLD: Added last-sector check sanitisation while stepping along FAT/miniFAT streams 20050119-2108:PLD: Added filename sanitization, so that obscure 8-bit values didn't get used. See OLEUNWRAP_sanitize_filename() 20041127-2051:PLD: Added sanity checking for the OLE header, see the fn OLE_header_sanity_check(). If the OLE file fails the sanity check, a return code of 103 will be issued. 2004-Oct-18: Changed unsigned int sectors to signed in OLE_follow_minichain() so that negative sector requests could be detected and prevent segfaults. Thanks to Gabriele Cariole for supplying the offending mailpack. 2004-Sep-30: Added a loop detection system into OLE_follow_chain to detect situations where the loop isn't tight (ie, if it goes A->B->C->D->A). This requires two new files to be added to the archive (bt-int.[ch]) Thanks to Brian for offering the mailpack which exposed this condition. 2004-Sep-25: Fixed old style fprintf(stdout) logging calls. Removed exit(1) calls. Fixed up memory leak in OLE_get_block(), where bb would not be explicitly free'd on either errors or normal exit. 2004-Aug-16: Added ole->FAT_limit into the general OLE struct so that when traversing the FAT chain later, it can be possible to check for requests beyond the memory block limit (which would other- wise cause segfaults) 2004-Jul-17: Fixed up unwanted verbosity about read mismatch in ole.c:321 Added macro VOLE which is 'if (ole->verbose)'. Fixed up unwanted verbosity from ole when a negative sector read request is made and not in verbosity mode. (ole.c:891) 2004-May-22: Fixed up minifat walk routines, made current_sector comparisons use hex notation rather than assumed signed int comparison. Added start section sanity checking with minifat walker. ie, ensuring that the starting sector is infact greater than zero 2004-May-21: Fixed up various memory leaks which were due to premature function exits, but without cleaning up any preallocated memory blocks. 2004-Apr-5: 19H50:PLD:REL Released as v0.1.3 19H48:PLD:DEV Added 'help' output for when no paramters are given. 14H22:PLD:DEV Added stream size sanity checking when decoding the attachment size in olestream-unwrap which would occasionally generate some rather unlrealistc stream sizes. OLEUNWRAP_decode_attachment(); 01H21:PLD:DEV Finally fixed occasional segfault bug with some OLE2 files. Fix was to define the memory boundary limit of the ole properties field and check on each pass of the loop that it wasn't being breached. 2003-Nov-26: 20H13:PLD:DEV Release 0.0.4 Fixed up some potential logging segfaults if used in conjunction with syslog output. 2003-Nov-17: 16H20:PLD:DEV Added bounds checking to entire processing system so that it cannot request a sector outside of the real limits of the loaded OLE file. I consider this only to be a partial fix to a problem of various documents which do not seem to be able to be decoded reliably, fortunately at least the bounds checking stops the segfaults. 2003-Oct-31: 07H38:PLD:DEV Added -q (quiet) option, which silences various non-fatal error messages. 2003-Aug-28: 22H04:PLD:DEV Added bounds checking on Mini-FAT loader, to ensure it would not attempt to load up a FAT chain from a negative starting sector. 2003-Jul-16: 21H23:PLD:DEV Added bounds check on chain follower/loader so that it would not attempt to seek from a starting sector < 0 2003-Jul-11: 19H53:PLD:DEV Added bounds checking to OLE_dbstosbs() 2003-Jul-05: 01H18:PLD:DEV Added --save-unknown-streams facility, this allows saving of streams which ripOLE doesn't yet know how to explicitly handle. 2003-Jul-04: 20H52:PLD:DEV Posted to Freshmeat Applied small patch to stop compile warnings about bp and buffer pointers being used (possibly) uninitialised. 08H13:PLD:DEV Fixed segfault in code when extended-FAT/BAT/DIF was required. This was caused by the header-conversion fn because it did not stop attempting to copy sectors beyond the first 109. 00H10:PLD:DEV: Fixed all 3 FAT modes, mini, standard and extended. All files now decode assuming they have the 'Ole10Native' element-name 2003-Jul-03: Initial code release, not currently usable to extract files but the code does dump the OLE streams to file, in which you can see the attachment information. ripole-0.2-dev/README0000644000175000001440000000066011102627641013001 0ustar pldusers--------- 2005-December-12 ripOLE has now started to become a useful tool in its own right, though it is more directly being developed for incorporation into ripMIME and subsequently Xamime. pldaniels@pldaniels.com --------- To check for [and save] attachments in a MS Office file, simply do the following: ./ripole -i officefile.doc -v -d tmp ..and ripOLE will decode the attachments to the 'tmp' directory -END. ripole-0.2-dev/CONTRIBUTORS0000644000175000001440000000025411102627641014000 0ustar pldusers Original code by Paul L Daniels Source documentation supplied by: defrost, Chris Hine and google Patches: Chris Hine:0.0.3:2003-07-04: Buffer,bp initialisation patch. ripole-0.2-dev/LICENSE0000644000175000001440000000270411102627641013127 0ustar pldusersCopyright (c) 2003, PLD All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the PLD nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ripole-0.2-dev/INSTALL0000644000175000001440000000005511102627641013150 0ustar pldusers -----INSTALL make ./ripole your-ole.doc ripole-0.2-dev/TODO0000644000175000001440000000005711102627641012611 0ustar pldusers ----------------------- Make things work :-) ripole-0.2-dev/Makefile0000644000175000001440000000047611102627641013566 0ustar pldusers OBJS= ole.o olestream-unwrap.o bytedecoders.o logger.o pldstr.o bt-int.o CFLAGS=-Wall -g -O2 -I. -Werror .c.o: $(CC) $(CFLAGS) $(DEFINES) -c $*.c default: ripole clean: rm -f *.o ripole ripole: $(OBJS) ripole.[ch] $(CC) $(CFLAGS) $(OBJS) $(DEFINES) ripole.c -o ripole validate: ripole cp ripole validate