Logo Search packages:      
Sourcecode: p3scan version File versions  Download package

ripmime.c

/*----------------------------------------
 * ripMIME -
 *
 * Written by Paul L Daniels
 * pldaniels@pldaniels.com
 *
 * (C)2001 P.L.Daniels
 * http://www.pldaniels.com/ripmime
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <syslog.h>
#include <signal.h>

#include "buildcodes.h"
#include "logger.h"
#include "ffget.h"
#include "mime.h"
#include "strstack.h"
#include "MIME_headers.h"


#define RIPMIME_ERROR_CANT_CREATE_OUTPUT_DIR 1
#define RIPMIME_ERROR_CANT_OPEN_INPUT_FILE 2
#define RIPMIME_ERROR_NO_INPUT_FILE 3
#define RIPMIME_ERROR_INSUFFICIENT_PARAMETERS 4
#define RIPMIME_ERROR_TIMEOUT 5


struct RIPMIME_globals
{
      char *inputfile;
      char *dir;
      int use_return_codes;
      int timeout;
      int quiet;
      int verbose_defects;
};

//-b [blankzone file name] : Dump the contents of the MIME blankzone to 'filename'


char defaultdir[] = ".";
struct RIPMIME_globals *ripmime_globals = NULL;

char version[] = "v1.4.0.3 - Dec 17, 2004 (C) PLDaniels http://www.pldaniels.com/ripmime";
char help[] = "ripMIME -i <mime file> -d <directory>\
      [-p prefix] [-e [header file]] [-vVh] [--version]\
      [--no_nameless] [--unique_names [--prefix|--postfix|--infix]]\
      [--paranoid] [--mailbox] [--formdata] [--debug]\
      [--no-tnef] [--no-quotedprintable] [--no-uudecode]\n\
Options available :\n\
      -i : Input MIME encoded file (use '-' to input from STDIN)\n\
      -d : Output directory\n\
      -p : Specify prefix filename to be used on files without a filename (default 'text')\n\
      -e [headers file name] : Dump headers from mailpack (default '_headers_')\n\
      -v : Turn on verbosity\n\
      -q : Run quietly, do no report non-fatal errors\n\
      \n\
      --verbose-contenttype : Turn on verbosity of file content type\n\
      --verbose-oldstyle : Uses the v1.2.x style or filename reporting\n\
      --verbose-defects: Display a summary of defects in the email\n\
      --stdout : All reporting goes to stdout (Default)\n\
      --stderr : All reporting goes to stderr\n\
      --syslog : All reporting goes to syslog\n\
      \n\
      --no-paranoid : [ Deprecated ] Turns off strict ascii-alnum filenaming\n\
      --paranoid: Converts all filenames to strict 7-bit compliance\n\
      --name-by-type: Saves a given attachment by its content-type if it has no other name\n\
      --no-nameless : Do not save nameless attachments\n\
      --overwrite : Overwrite files if they have the same name on extraction\n\
      --unique-names : Dont overwrite existing files (This is the default behaviour)\n\
      --prefix : rename by putting unique code at the front of the filename\n\
      --postfix : rename by putting unique code at the end of the filename\n\
      --infix : rename by putting unique code in the middle of the filename\n\
      \n\
      --mailbox : Process mailbox file\n\
      --formdata : Process as form data (from HTML form etc)\n\
      \n\
      --no-tnef : Turn off TNEF/winmail.dat decoding\n\
      --no-ole : Turn off OLE decoding\n\
      --no-uudecode : Turns off the facility of detecting UUencoded attachments in emails\n\
      --no-quotedprintable : Turns off the facility of decoding QuotedPrintable data\n\
      --no-doublecr : Turns off saving of double-CR embedded data\n\
      --no-mht : Turns off MHT (a Microsoft mailpack attachment format ) decoding\n\
      --no-multiple-filenames : Turns off the multiple filename exploit handling\n\
      \n\
      --disable-qmail-bounce : Turns off qmail bounced email testing\n\
      --recursion-max <level> : Set the maximum recursion level to 'level'\n\
      --timeout <seconds>     : Set the maximum number of CPU seconds ripMIME can run for\n\
      \n\
      --debug : Produces detailed information about the whole decoding process\n\
      --extended-errors:      Produces more return codes, even for non-fatals\n\
      -V --version : Give version information\n\
      --buildcodes : Give the build information (tstamp, date and system information)\n\
      -h : This message (help)\n\n\n";

/*-----------------------------------------------------------------\
 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;
}



/*-----------------------------------------------------------------\
 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
#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);
                              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);
                              }
                              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]), "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;
}



/*-----------------------------------------------------------------\
 Function Name    : RIPMIME_init
 Returns Type     : int
      ----Parameter List
      1. struct RIPMIME_globals *glb, 
      ------------------
 Exit Codes : 
 Side Effects     : 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int RIPMIME_init (struct RIPMIME_globals *glb)
{
      glb->dir = defaultdir;
      glb->inputfile = NULL;
      glb->use_return_codes = 0;
      glb->timeout = 0;
      glb->quiet = 0;
      glb->verbose_defects = 0;

      return 0;
}

/*-----------------------------------------------------------------\
 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    : 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);

      // Set the alarm timeout feature.
      if (glb.timeout > 0)
      {
            signal(SIGALRM, RIPMIME_signal_alarm);
            alarm(glb.timeout);
      }

      // 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

      MIMEH_set_outputdir (glb.dir);
      result = MIME_unpack (glb.dir, glb.inputfile, 0);

      // do any last minute things

      MIME_close ();


      // Possible exit codes include;
      //          0 - all okay
      //          240 - processing stopped due to recursion limit

      if (glb.use_return_codes == 0) result = 0;

      return result;

}

/*-END-----------------------------------------------------------*/

Generated by  Doxygen 1.6.0   Back to index