/*-----------------------------------------------------------------\ 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; } wcfopen(f, full_name, "wb"); 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 : RIPMIME_report_filename_decoded Returns Type : int ----Parameter List 1. char *filename, 2. char *contenttype, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int RIPMIME_report_filename_decoded (char *filename, char *contenttype) { char *p; p = strrchr(filename,'/'); if (!p) p = filename; else p++; if (contenttype != NULL) { LOGGER_log ("Decoding content-type=%s filename=%s", contenttype, p); } else { LOGGER_log ("Decoding filename=%s", p); } return 0; }
int qp_encode_from_file( char *fname ) { size_t bc; struct stat st; int stat_result; char *in_buffer; char *out_buffer; size_t in_size, out_size; FILE *f; stat_result = stat( fname, &st ); if (stat_result != 0){ QPD fprintf(stderr, "Cannot locate file '%s' for loading and QP encoding (%s)\n", fname, strerror(errno)); return -1; } in_size = st.st_size; out_size = in_size *3; in_buffer = malloc( sizeof(char) *in_size +1); if (in_buffer == NULL) { QPD fprintf(stdout,"Error allocating %d bytes for input buffer\n", in_size); return -1; } out_buffer = malloc( sizeof(char) *out_size *3 +1); if (in_buffer == NULL) { QPD fprintf(stdout,"Error allocating %d bytes for output buffer\n", out_size); return -1; } f = fopen( fname, "r" ); bc = fread( in_buffer, 1, in_size, f ); if (bc != in_size) LOGGER_log("%s:%d:qp_encode_from_file:ERROR: Read %d bytes but requested %d", FL, bc, in_size); fclose(f); /** zero terminate the buffer -- uhuh, if you forget that you'll wonder why ** we segfault ;) **/ *(in_buffer +in_size) = '\0'; QPD fprintf(stdout,"file %s is loaded, size = %d\n", fname, in_size); qp_encode( out_buffer, out_size, in_buffer, in_size ); fprintf( stdout, "%s", out_buffer ); free(in_buffer); free(out_buffer); return 0; }
/*-----------------------------------------------------------------\ 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) { OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path ); } else { if (oleuw->debug) LOGGER_log(_("Unable to decode stream with element string '%s'\n"), element_string); result = OLEUW_STREAM_NOT_DECODED; } return result; }
/*-----------------------------------------------------------------\ Function Name : FFGET_seek Returns Type : int ----Parameter List 1. FFGET_FILE *f, 2. size_t offset , ------------------ Exit Codes : -1 = error, check logs for reason of failure. Side Effects : -------------------------------------------------------------------- Comments: Seeks to 'offset' bytes from the first byte of the file. Reloads the buffer block. -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int FFGET_seek( FFGET_FILE *f, long offset, int whence ) { int result = 0; /** Move to the new block location **/ result = fseek(f->f, offset, whence); if (result == -1) { LOGGER_log("%s:%d:FFGET_seek:ERROR: While attempting to seek to offset %ld from %d - [%s]", FL, offset, whence, strerror(errno)); return -1; } /** Read a whole new block **/ result = FFGET_getnewblock(f); return result; }
/*-----------------------------------------------------------------\ 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_4byte_value( (unsigned char *) sp ); sp += 4; DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: attachsize = %d, stream length = %d\n", FL, oh.attach_size_1, 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) { /* If we only had the stream byte-lenght in our header*/ /* then we know we don't have a complex header.*/ oh.attach_name = PLD_dprintf("unknown-%ld",oh.attach_size_1); oh.attach_size = oh.attach_size_1; } 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_4byte_value( (unsigned char*) 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); result = OLEUNWRAP_save_stream( oleuw, oh.attach_name, decode_path, data_start_point, oh.attach_size ); if (result == OLEUW_OK) { if (oleuw->debug > 0) 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*/ } /* 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); return OLEUW_OK; }
/*------------------------------------------------------------------------ Procedure: FFGET_fgets ID:1 Purpose: Gets a single line from the input buffer. The line can be either \r \n \r\n terminated based on the status flags set/unset by previous reads. This function is the key to making tools like ripMIME be able to see double-vision, that is, to see emails like Outlook does, and also like RFC. Input: line: Buffer to write to max_size: Maximum number of bytes to write to line. f: FFGET record to use to read. Output: Pointer to line. Errors: ------------------------------------------------------------------------*/ char *FFGET_fgets( char *linein, int maxsize, FFGET_FILE *f ) { char *line = linein; char *crlfpos = NULL; int charstoCRLF = 0; int chardiff = 0; int result = 0; int max_size = maxsize; int endpoint_tainted = 0; int extra_char_kept=0; int c, nextchar; f->trueblank = 0; f->linebreak = FFGET_LINEBREAK_NONE; f->lastbreak[0] = '\0'; if (f->FFEOF != 0) { return NULL; } if ((FFGET_SDL_WATCH > 0)||(FFGET_SDL_MODE != 0)) { DELIMITERS = SDL_MODE_DELIMITS; } else DELIMITERS = NORM_MODE_DELIMITS; // fprintf(stderr,"FFGET_called, SDLMODE = %d, Offset = %d, maxsize = %d, DATA left = %d, first char is '%02X'\n", FFGET_SDL_MODE, (f->startpoint -f->buffer), max_size, (f->endpoint -f->startpoint)+1, (int)(*f->startpoint)); max_size = maxsize = maxsize -2; // memset(line, 0, max_size+1); // If we dont have enough data in the buffer to fill up the fgets request // we'll have to do a two step fill //fprintf(stderr,"DATA Reminianing : %d\n", (int)(f->endpoint -f->startpoint)+1); if ((f->startpoint > f->endpoint)) { result = FFGET_getnewblock(f); if (result == 0) { *linein = '\0'; return NULL; } } // This loop does not go around too many times, once, maybe twice max. while ((max_size > 0)&&(f->FFEOF == 0)) { crlfpos = strpbrk( f->startpoint, DELIMITERS); if (crlfpos) { extra_char_kept = 0; endpoint_tainted = 0; nextchar = -1; // if our next char is a CR or LF, then pick it up and // return it with the line. NOTE - this is to deal with // CRLF pairings which are common on DOS files. In fact, // this is a case of where UNIX is actually -wrong-. It // should have also used CRLF pairing to mark line ends, but // someone obviously (and understandably, to save space) // thought they'd leave make LF imply a CR as well. // Well done... another bugger up in life. // The logic of this nested IF statement is as follows... // If we do have another char available... // and if the pairing is not \n\n (which should be treated as two lines // and if the next char is a \n or a \r, // THEN we should increment the end of line pointer so that we // include the additional \n or \r into the line we're going to // return // If we are NOT in the Single-delimeter mode (SDL_MODE), and the next // char is available, then commence the delimeter testing routines if ((0==f->FILEEND)&&(0==f->FFEOF)&&( ((crlfpos +1) > f->endpoint))) { // We have an EOL character, get 1 more from the stream to test the next character nextchar = c = fgetc(f->f); if (c==EOF) { // fprintf(stderr,"EOF hit due to fgetc()\n"); f->FILEEND = 1; } else { if (c == '\0') c = ' '; // Check for character value vadality if ((c > 0) && (c <= 255)) { if (FFGET_DNORMAL) LOGGER_log("%s:%d:FFGET_fgets:DEBUG: Tainting endpoint +1 (%p -> %p, hard buffer end = %p, file read bytes = %ld)", FL, f->endpoint, f->endpoint+1, f->buffer_end, f->bytes); f->endpoint++; *(f->endpoint) = c; *(f->endpoint+1) = '\0'; endpoint_tainted = 1; } } } // If (crlfpos +1) is /not/ within our buffer bounds // If the next char from our CRLF pickup is within the bounds of // our endpoint, then proceed to test the CRLF combo if ( ((crlfpos +1) <= f->endpoint)) { // fprintf(stderr,"Found '%02X' [next is '%02X']\n",*crlfpos, *(crlfpos+1)); if ( *crlfpos == '\n' ) { f->linebreak = FFGET_LINEBREAK_LF; snprintf(f->lastbreak,sizeof(f->lastbreak),"\n"); if ( *(crlfpos +1) == '\r' ) { f->linebreak |= FFGET_LINEBREAK_CR; snprintf(f->lastbreak,sizeof(f->lastbreak),"\n\r"); crlfpos++; extra_char_kept = 1; } } // If our combo starts with a \r, then test it to see // if we have another \r after it, in which case, we // turn on SINGLE_DELIMETER_MODE. if ( (*crlfpos == '\r') ) { f->linebreak = FFGET_LINEBREAK_CR; snprintf(f->lastbreak,sizeof(f->lastbreak),"\r"); if ( *(crlfpos +1) == '\r' ) { // A \r\r sequence has just been detected, set our doubleCR flag // so that MIME_headers can read it and react accordingly. // Look out for single \r's from here on, as they are now seen as // EOL markers in Outlook. f->linebreak = FFGET_LINEBREAK_CR; FFGET_doubleCR=1; FFGET_SDL_MODE=1; crlfpos++; extra_char_kept = 1; } else if ( *(crlfpos +1) == '\n' ) { // If we see a \n after our \r, then treat this as a single // line delimeter if we are NOT in Single Delimeter mode // snprintf(f->lastbreak,sizeof(f->lastbreak),"\r\n"); f->linebreak |= FFGET_LINEBREAK_LF; if (!FFGET_SDL_MODE) { crlfpos++; extra_char_kept = 1; }// 20040208-1706:PLD //crlfpos++;// 20040208-1706:PLD // 20040306-0003:PLD - this line causes a CRCR test to fail; mailpack.virus.badtrans } else { // If we saw a \r, but then there was no other EOL type char (\r or \n) // then switch to SDL mode (Single delimeter). FFGET_SDL_MODE=1; } } // If combo starts with a \r } // If crlfpos +1 is within the bounds of our buffer. // Determine how many characters/bytes there are from the startpoint, // to the CRLF position. charstoCRLF = crlfpos -f->startpoint; // If the number of chars is -less- than that of the maximum line read // size which our calling program has specified, then we set the max_size // to be the number of chars. //DEBUG fprintf(stderr, "MAX_size = %d, charstoCRLF = %d\n", max_size, charstoCRLF); if ((charstoCRLF >= 0)&&(charstoCRLF < max_size)) max_size = charstoCRLF; if ((extra_char_kept == 0) && (nextchar != -1)) ungetc(nextchar,f->f); } // If CRLF pos found. // else crlfpos = (f->endpoint +1); // If the buffer amount remaining in our FFGET buffer is greater than // the maximum size available in our line buffer, then we // only copy the max_size amount across if (( f->endpoint -f->startpoint) >= max_size) { if (max_size < 0) LOGGER_log("%s:%d:FFGET_fgets:ERROR: Max size < 0\n", FL); memcpy(line, f->startpoint, max_size +1);//+1 f->startpoint += (max_size +1); //+1 *(line +max_size +1) = '\0'; //+1 max_size = 0; } else { // else, if the amount of data available is /LESS/ than what we can // accept in the line buffer then copy what remains out to the line // buffer and then tack on the results of a new read. chardiff = f->endpoint -f->startpoint; // fprintf(stderr,"CHARDiff = %d, FFEOF = %d, FILEEND = %d\n",chardiff, f->FFEOF, f->FILEEND); if (chardiff >= 0) { memcpy(line, f->startpoint, chardiff +1); *(line +chardiff +1) = '\0'; // 12-11-2002: Added this line to terminate the input buffer incase it wasn't already flushed with \0's line += (chardiff +1); max_size -= (chardiff +1); f->startpoint = f->endpoint +1; if (max_size < 0) max_size = 0; } FFGET_getnewblock(f); endpoint_tainted=0; } // If there wasn't enough data to satisfy ends. if (endpoint_tainted) { FFGET_getnewblock(f); endpoint_tainted = 0; } } // While we've got space to fill, and we've got data to read line = linein; f->trueblank = 0; if ((f->lastchar == '\n')||(f->lastchar == '\r')) { if ((line[0] == '\n')||(line[0] == '\r')) { f->trueblank = 1; } } f->lastchar = line[strlen(line) -1]; f->linecount++; // LOGGER_log("%s:%d:LINE='%s'",FL,linein); return linein; }
/*------------------------------------------------------------------------ Procedure: FFGET_getnewblock ID:1 Purpose: Reads a new block of data from the input file Input: FFGET_FILE record Output: Returns number of bytes read Errors: ------------------------------------------------------------------------*/ int FFGET_getnewblock( FFGET_FILE *f ) { int i; int bs = 0; char *p; // We read the maximum of FFGET_BUFFER_MAX -2, because later, when we // use fgets(), we may need to read in an /additional/ single byte // and if we dont allocate spare room, we may have a buffer overflow if (f->FILEEND > 0) { f->endpoint = f->buffer; f->startpoint = f->buffer +1; f->FFEOF = 1; return 0; } else { long block_pos; block_pos = ftell(f->f); /** Get our current read position so we can use it in FFGET_ftell if required **/ bs = fread( f->buffer, 1, FFGET_BUFFER_MAX -FFGET_BUFFER_PADDING, f->f ); if (bs < (FFGET_BUFFER_MAX -FFGET_BUFFER_PADDING)) { if (feof(f->f)) { f->FILEEND = 1; } else { LOGGER_log("%s:%d:FFGET_getnewblock:ERROR: File read failed with error:%s", FL, strerror(errno)); return 0; } } if (bs > 0) { // If we read in some data, then adjust the buffer to deal with it // // First we set the start point back to the start of the buffer, // then we set the end point to be the start +datasize we read, -1 // then we adjust the total bytes read (for the sake of record keeping // though it has no /real/ purpose) // f->buffer[bs] = '\0'; //20040208-1703:PLD:JS f->last_block_read_from = block_pos; // 200607150941:PLD f->startpoint = f->buffer; f->endpoint = f->startpoint +bs -1; f->bytes += bs; // Check the buffer for poisioning \0's // As these routines are being used for 7-bit valid text data, // we have to filter out any nasty \0's. if (FFGET_ALLOW_NUL == 0) { p = f->startpoint; for (i = 0; i < bs; i++) { if (*p == '\0') *p = ' '; p++; } *p = '\0'; } if (FFGET_DPEDANTIC) LOGGER_log("%s:%d:FFGET_getnewblock:DEBUG-PEDANTIC: Size: %ld bytes\n", FL, f->bytes); } } return bs; }
/*-----------------------------------------------------------------\ 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 = (int)strlen( replace_details->source ); source_end = replace_details->source + source_length; searchfor_length = (int)strlen(replace_details->searchfor); replacewith_length = (int)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 : 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 RIPMIME_globals glb; int result = 0; /* if the user has just typed in "ripmime" and nothing else, then we had better give them * the rundown on how to use this program */ if (argc < 2) { fprintf (stderr, "%s\n%s", version, help); return RIPMIME_ERROR_INSUFFICIENT_PARAMETERS; } // Set the global pointer ripmime_globals to point to // the glb struct, so that if we have a timeout condition // we can use the data ripmime_globals = &glb; // Set up our initial logging mode - so that we can always get // report messages if need be. LOGGER_set_output_mode (_LOGGER_STDOUT); // Perform system initialisations MIME_init (); RIPMIME_init (&glb); // Setup our default behaviours */ MIME_set_uniquenames (1); MIME_set_paranoid (0); MIME_set_header_longsearch(1); // 20040310-0117:PLD - Added by default as it seems stable, use --disable-qmail-bounce to turn off MIME_set_renamemethod (_MIME_RENAME_METHOD_INFIX); RIPMIME_parse_parameters (&glb, argc, argv); // if our input filename wasn't specified, then we better let the user know! if (!glb.inputfile) { LOGGER_log("Error: No input file was specified\n"); return RIPMIME_ERROR_NO_INPUT_FILE; } // Fire up the randomizer srand (time (NULL)); // clean up the output directory name if required (remove any trailing /'s, as suggested by James Cownie 03/02/2001 if (glb.dir[strlen (glb.dir) - 1] == '/') { glb.dir[strlen (glb.dir) - 1] = '\0'; } // Create the output directory required as specified by the -d parameter if (glb.dir != defaultdir) { result = mkdir (glb.dir, S_IRWXU); // if we had a problem creating a directory, and it wasn't just // due to the directory already existing, then we have a bit of // a problem on our hands, hence, report it. // if ((result == -1) && (errno != EEXIST)) { LOGGER_log("ripMIME: Cannot create directory '%s' (%s)\n", glb.dir, strerror (errno)); return RIPMIME_ERROR_CANT_CREATE_OUTPUT_DIR; } } // Unpack the contents RIPMIME_unpack(&glb); // Possible exit codes include; // 0 - all okay // 240 - processing stopped due to recursion limit if (glb.use_return_codes == 0) result = 0; return result; }
/*-----------------------------------------------------------------\ Function Name : RIPMIME_signal_alarm Returns Type : void ----Parameter List 1. int sig , ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ void RIPMIME_signal_alarm( int sig ) { if (ripmime_globals->quiet == 0) LOGGER_log("%s:%d:RIPMIME_signal_alarm: ripMIME took too long to complete. Mailpack is \"%s\", output dir is \"%s\"",FL, ripmime_globals->inputfile, ripmime_globals->dir ); exit(RIPMIME_ERROR_TIMEOUT); }
/*-----------------------------------------------------------------\ Function Name : RIPMIME_parse_parameters Returns Type : int ----Parameter List 1. struct RIPMIME_globals *glb, 2. int argc, 3. char **argv, ------------------ Exit Codes : Side Effects : -------------------------------------------------------------------- Comments: -------------------------------------------------------------------- Changes: \------------------------------------------------------------------*/ int RIPMIME_parse_parameters (struct RIPMIME_globals *glb, int argc, char **argv) { int i; int result = 0; MIME_set_filename_report_fn (RIPMIME_report_filename_decoded); for (i = 1; i < argc; i++) { // if the first char of the argument is a '-', then we possibly have a flag if (argv[i][0] == '-') { // test the 2nd char of the parameter switch (argv[i][1]) { case 'i': if (argv[i][2] != '\0') { glb->inputfile = &argv[i][2]; } else { i++; if (i < argc) { glb->inputfile = argv[i]; } else { LOGGER_log("ERROR: insufficient parameters after '-i'\n"); } } break; case 'd': if (argv[i][2] != '\0') { glb->dir = &(argv[i][2]); } else { i++; if (i < argc) { glb->dir = argv[i]; } else { LOGGER_log("ERROR: insufficient parameters after '-d'\n"); } } break; case 'p': if (argv[i][2] != '\0') { MIME_set_blankfileprefix (&argv[i][2]); } else { i++; if (i < argc) { MIME_set_blankfileprefix (argv[i]); } else { LOGGER_log("ERROR: insufficient parameters after '-p'\n"); } } break; // this is in mime.h case 'e': MIME_set_dumpheaders (1); if (argv[i][2] != '\0') { MIME_set_headersname (&argv[i][2]); } else { if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) MIME_set_headersname (argv[++i]); } break; // makes MIME dump out the headers to a file case 'x': if (argv[i][2] != '\0') { MIME_set_out_charset(&argv[i][2]); } else { LOGGER_log("ERROR: insufficient parameters after '-x'\n"); abort(); } break; #ifdef RIPMIME_BLANKZONE case 'b': if (argv[i][2] != '\0') { MIME_set_blankzone_filename (&argv[i][2]); } else { if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) MIME_set_blankzone_filename (argv[++i]); } break; // blankzone storage option #endif case 'v': MIME_set_verbosity (1); glb->verbose = 1; break; case 'q': glb->quiet = 1; MIME_set_quiet(glb->quiet); 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-contenttype", strlen ("verbose-contenttype")) == 0) { MIME_set_verbosity_contenttype (1); /** 20051117-0927:PLD: ** If client uses --verbose-mime, then make ripMIME report when it ** detects a MIME encoded email **/ } else if (strncmp(&(argv[i][2]), "verbose-mime", strlen("verbose-mime"))==0) { MIME_set_report_MIME(1); } else if (strncmp (&(argv[i][2]), "verbose-oldstyle", strlen ("verbose-oldstyle")) == 0) { MIME_set_verbosity_12x_style (1); MIME_set_filename_report_fn (NULL); } else if (strncmp (&(argv[i][2]), "verbose-defects",15) == 0) { glb->verbose_defects = 1; MIME_set_verbose_defects(1); } else if (strncmp (&(argv[i][2]), "paranoid", 8) == 0) { MIME_set_paranoid (1); } else if (strncmp (&(argv[i][2]), "no_paranoid", 11) == 0) { MIME_set_paranoid (0); } else if (strncmp (&(argv[i][2]), "no-paranoid", 11) == 0) { MIME_set_paranoid (0); } else if (strncmp (&(argv[i][2]), "prefix", 6) == 0) { MIME_set_renamemethod (_MIME_RENAME_METHOD_PREFIX); } else if (strncmp (&(argv[i][2]), "postfix", 7) == 0) { MIME_set_renamemethod (_MIME_RENAME_METHOD_POSTFIX); } else if (strncmp (&(argv[i][2]), "infix", 5) == 0) { MIME_set_renamemethod (_MIME_RENAME_METHOD_INFIX); } else if (strncmp (&(argv[i][2]), "overwrite", 9) == 0) { MIME_set_uniquenames (0); } else if (strncmp (&(argv[i][2]), "unique_names", 12) == 0) { MIME_set_uniquenames (1); } else if (strncmp (&(argv[i][2]), "unique-names", 12) == 0) { MIME_set_uniquenames (1); } else if (strncmp(&(argv[i][2]), "name-by-type", 12) == 0) { MIME_set_name_by_type(1); } else if (strncmp (&(argv[i][2]), "syslog", 9) == 0) { LOGGER_set_output_mode (_LOGGER_SYSLOG); LOGGER_set_syslog_mode (LOG_MAIL | LOG_INFO); } else if (strncmp (&(argv[i][2]), "stderr", 10) == 0) { LOGGER_set_output_mode (_LOGGER_STDERR); } else if (strncmp (&(argv[i][2]), "stdout", 9) == 0) { LOGGER_set_output_mode (_LOGGER_STDOUT); } else if (strncmp (&(argv[i][2]), "no_nameless", 11) == 0) { MIME_set_no_nameless (1); } else if (strncmp (&(argv[i][2]), "no-nameless", 11) == 0) { MIME_set_no_nameless (1); } else if (strncmp (&(argv[i][2]), "debug", 5) == 0) { MIME_set_debug (1); } else if (strncmp (&(argv[i][2]), "mailbox", 7) == 0) { MIME_set_mailboxformat (1); } else if (strncmp(&(argv[i][2]), "formdata", 8) == 0) { // Form data usually contains embedded \0 sequences // so we need to explicitly turn this off. FFGET_set_allow_nul(1); } else if (strncmp (&(argv[i][2]), "no_uudecode", 11) == 0) { // We are transitioning away from negative-logic function // names because they can cause confusion when reading, so // from here on, we will use things like _set_foo() rather // than _set_no_foo() MIME_set_decode_uudecode(0); } else if (strncmp (&(argv[i][2]), "no-uudecode", 11) == 0) { MIME_set_decode_uudecode(0); } else if (strncmp (&(argv[i][2]), "no-tnef", 7) == 0) { MIME_set_decode_tnef (0); } else if (strncmp (&(argv[i][2]), "no-ole", 6) == 0) { MIME_set_decode_ole(0); } else if (strncmp (&(argv[i][2]), "no-base64", 9) == 0) { MIME_set_decode_base64(0); } else if (strncmp (&(argv[i][2]), "no-quotedprintable", strlen("no-quotedprintable")) == 0) { MIME_set_decode_qp(0); } else if (strncmp(&(argv[i][2]), "no-doublecr", strlen("no-doublecr")) == 0) { MIME_set_decode_doubleCR(0); } else if (strncmp(&(argv[i][2]), "no-mht", strlen("no-mht")) == 0) { MIME_set_decode_mht(0); } else if (strncmp(&(argv[i][2]), "disable-header-fix", strlen("disable-headerfix")) == 0) { MIMEH_set_headerfix(0); } else if (strncmp(&(argv[i][2]), "qmail-bounce", strlen("qmail-bounce")) == 0) { MIME_set_header_longsearch(1); } else if (strncmp(&(argv[i][2]), "disable-qmail-bounce", strlen("disable-qmail-bounce")) == 0) { MIME_set_header_longsearch(0); } else if (strncmp(&(argv[i][2]), "no-multiple-filenames", strlen("no-multiple-filenames")) == 0) { MIME_set_multiple_filenames(0); } else if (strncmp(&(argv[i][2]), "recursion-max", strlen("recursion-max")) == 0) { if (argv[i+1] != NULL) { int level; level = atoi(argv[i+1]); if (level > 0) { MIME_set_recursion_level(level); } } } else if (strncmp(&(argv[i][2]), "timeout", strlen("timeout")) == 0) { if (argv[i+1] != NULL) { int seconds; seconds = atoi(argv[i+1]); if (seconds > 0) { glb->timeout = seconds; } } } else if (strncmp (&(argv[i][2]), "buildcodes", 10) == 0) { fprintf(stdout,"%s\n%s\n%s\n", BUILD_CODE, BUILD_DATE, BUILD_BOX); exit(0); } else if (strncmp (&(argv[i][2]), "version", 7) == 0) { fprintf (stdout, "%s\n", version); exit (0); } else if (strncmp(&(argv[i][2]), "extended-errors", strlen("extended-errors")) == 0) { glb->use_return_codes = 1; } else { LOGGER_log ("Cannot interpret option \"%s\"\n%s\n", argv[i], help); exit (1); break; } break; // else, just dump out the help message default: LOGGER_log ("Cannot interpret option \"%s\"\n%s\n", argv[i], help); exit (1); break; } // Switch argv[i][1] } // if argv[i][0] == - } // for return result; }