Esempio n. 1
0
File: pcrs.c Progetto: alltom/rumble
/*********************************************************************
 *
 * Function    :  pcrs_execute_single_command
 *
 * Description :  Apply single pcrs command to the subject.
 *                The subject itself is left untouched, memory for the result
 *                is malloc()ed and it is the caller's responsibility to free
 *                the result when it's no longer needed.
 *
 * Parameters  :
 *          1  :  subject = the subject (== original) string
 *          2  :  pcrs_command = the pcrs command as string (s@foo@bar@)
 *          3  :  hits = int* for returning  the number of modifications
 *
 * Returns     :  NULL in case of errors, otherwise the
 *                result of the pcrs command.
 *
 *********************************************************************/
char *pcrs_execute_single_command(const char *subject, const char *pcrs_command, int *hits)
{
   size_t size;
   char *result = NULL;
   pcrs_job *job;

   assert(subject);
   assert(pcrs_command);

   *hits = 0;
   size = strlen(subject);

   job = pcrs_compile_command(pcrs_command, hits);
   if (NULL != job)
   {
      *hits = pcrs_execute(job, subject, size, &result, &size);
      if (*hits < 0)
      {
         freez(result);
      }
      pcrs_free_job(job);
   }
   return result;

}
Esempio n. 2
0
File: pcrs.c Progetto: alltom/rumble
/*********************************************************************
 *
 * Function    :  pcrs_compile_dynamic_command
 *
 * Description :  Takes a dynamic pcrs command, fills in the
 *                values of the variables and compiles it.
 *
 * Parameters  :
 *          1  :  pcrs_command = The dynamic pcrs command to compile
 *          2  :  v = NULL terminated array of variables and their values.
 *          3  :  error = pcrs error code
 *
 * Returns     :  NULL in case of hard errors, otherwise the
 *                compiled pcrs job.
 *
 *********************************************************************/
pcrs_job *pcrs_compile_dynamic_command(char *pcrs_command, const struct pcrs_variable v[], int *error)
{
   char buf[PCRS_BUFFER_SIZE];
   const char *original_pcrs_command = pcrs_command;
   char *pcrs_command_tmp = NULL;
   pcrs_job *job = NULL;
   int truncation = 0;
   char d;
   int ret;

   while ((NULL != v->name) && (NULL != pcrs_command))
   {
      assert(NULL != v->value);

      if (NULL == strstr(pcrs_command, v->name))
      {
         /*
          * Skip the substitution if the variable
          * name isn't part of the pattern.
          */
         v++;
         continue;
      }

      /* Use pcrs to replace the variable with its value. */
      d = pcrs_get_delimiter(v->value);
      if ('\0' == d)
      {
         /* No proper delimiter found */
         *error = PCRS_ERR_CMDSYNTAX;
         return NULL;
      }

      /*
       * Variable names are supposed to contain alpha
       * numerical characters plus '_' only.
       */
      assert(NULL == strchr(v->name, d));

      ret = snprintf(buf, sizeof(buf), "s%c\\$%s%c%s%cgT", d, v->name, d, v->value, d);
      assert(ret >= 0);
      if (ret >= sizeof(buf))
      {
         /*
          * Value didn't completely fit into buffer,
          * overwrite the end of the substitution text
          * with a truncation message and close the pattern
          * properly.
          */
         const size_t trailer_size = sizeof(warning) + 3; /* 3 for d + "gT" */
         char *trailer_start = buf + sizeof(buf) - trailer_size;

         ret = snprintf(trailer_start, trailer_size, "%s%cgT", warning, d);
         assert(ret == trailer_size - 1);
         assert(sizeof(buf) == strlen(buf) + 1);
         truncation = 1;
      }

      pcrs_command_tmp = pcrs_execute_single_command(pcrs_command, buf, error);
      if (NULL == pcrs_command_tmp)
      {
         return NULL;
      }

      if (pcrs_command != original_pcrs_command)
      {
         freez(pcrs_command);
      }
      pcrs_command = pcrs_command_tmp;

      v++;
   }

   job = pcrs_compile_command(pcrs_command, error);
   if (pcrs_command != original_pcrs_command)
   {
      freez(pcrs_command);
   }

   if (truncation)
   {
      *error = PCRS_WARN_TRUNCATION;
   }

   return job;

}
Esempio n. 3
0
File: loaders.c Progetto: mfb/orbot
/*********************************************************************
 *
 * Function    :  load_one_re_filterfile
 *
 * Description :  Load a re_filterfile. 
 *                Generate a chained list of re_filterfile_spec's from
 *                the "FILTER: " blocks, compiling all their substitutions
 *                into chained lists of pcrs_job structs.
 *
 * Parameters  :
 *          1  :  csp = Current client state (buffers, headers, etc...)
 *
 * Returns     :  0 => Ok, everything else is an error.
 *
 *********************************************************************/
int load_one_re_filterfile(struct client_state *csp, int fileid)
{
   FILE *fp;

   struct re_filterfile_spec *new_bl, *bl = NULL;
   struct file_list *fs;

   char  buf[BUFFER_SIZE];
   int error;
   unsigned long linenum = 0;
   pcrs_job *dummy, *lastjob = NULL;

   /*
    * No need to reload if unchanged
    */
   if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs))
   {
      if (csp)
      {
         csp->rlist[fileid] = current_re_filterfile[fileid];
      }
      return(0);
   }
   if (!fs)
   {
      goto load_re_filterfile_error;
   }

   /* 
    * Open the file or fail
    */
   if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL)
   {
      goto load_re_filterfile_error;
   }

   /* 
    * Read line by line
    */
   while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
   {
      int new_filter = NO_NEW_FILTER;

      if (strncmp(buf, "FILTER:", 7) == 0)
      {
         new_filter = FT_CONTENT_FILTER;
      }
      else if (strncmp(buf, "SERVER-HEADER-FILTER:", 21) == 0)
      {
         new_filter = FT_SERVER_HEADER_FILTER;
      }
      else if (strncmp(buf, "CLIENT-HEADER-FILTER:", 21) == 0)
      {
         new_filter = FT_CLIENT_HEADER_FILTER;
      }
      else if (strncmp(buf, "CLIENT-HEADER-TAGGER:", 21) == 0)
      {
         new_filter = FT_CLIENT_HEADER_TAGGER;
      }
      else if (strncmp(buf, "SERVER-HEADER-TAGGER:", 21) == 0)
      {
         new_filter = FT_SERVER_HEADER_TAGGER;
      }

      /*
       * If this is the head of a new filter block, make it a
       * re_filterfile spec of its own and chain it to the list:
       */
      if (new_filter != NO_NEW_FILTER)
      {
         new_bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
         if (new_bl == NULL)
         {
            goto load_re_filterfile_error;
         }
         if (new_filter == FT_CONTENT_FILTER)
         {
            new_bl->name = chomp(buf + 7);
         }
         else
         {
            new_bl->name = chomp(buf + 21);
         }
         new_bl->type = new_filter;

         /*
          * If a filter description is available,
          * encode it to HTML and save it.
          */
         if (NULL != (new_bl->description = strpbrk(new_bl->name, " \t")))
         {
            *new_bl->description++ = '\0';
            new_bl->description = html_encode(chomp(new_bl->description));
            if (NULL == new_bl->description)
            {
               new_bl->description = strdup("Out of memory while encoding this filter's description to HTML");
            }
         }
         else
         {
            new_bl->description = strdup("No description available for this filter");
         }

         new_bl->name = strdup(chomp(new_bl->name));
         
         /*
          * If this is the first filter block, chain it
          * to the file_list rather than its (nonexistant)
          * predecessor
          */
         if (fs->f == NULL)
         {
            fs->f = new_bl;
         }
         else
         {
            assert(NULL != bl);
            bl->next = new_bl;
         }
         bl = new_bl;

         log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);

         continue;
      }

      /* 
       * Else, save the expression, make it a pcrs_job
       * and chain it into the current filter's joblist 
       */
      if (bl != NULL)
      {
         error = enlist(bl->patterns, buf);
         if (JB_ERR_MEMORY == error)
         {
            log_error(LOG_LEVEL_FATAL,
               "Out of memory while enlisting re_filter job \'%s\' for filter %s.", buf, bl->name);
         }
         assert(JB_ERR_OK == error);

         if (pcrs_job_is_dynamic(buf))
         {
            /*
             * Dynamic pattern that might contain variables
             * and has to be recompiled for every request
             */
            if (bl->joblist != NULL)
            {
                pcrs_free_joblist(bl->joblist);
                bl->joblist = NULL;
            }
            bl->dynamic = 1;
            log_error(LOG_LEVEL_RE_FILTER,
               "Adding dynamic re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
            continue;             
         }
         else if (bl->dynamic)
         {
            /*
             * A previous job was dynamic and as we
             * recompile the whole filter anyway, it
             * makes no sense to compile this job now.
             */
            log_error(LOG_LEVEL_RE_FILTER,
               "Adding static re_filter job \'%s\' to dynamic filter %s succeeded.", buf, bl->name);
            continue;
         }

         if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
         {
            log_error(LOG_LEVEL_ERROR,
               "Adding re_filter job \'%s\' to filter %s failed with error %d.", buf, bl->name, error);
            continue;
         }
         else
         {
            if (bl->joblist == NULL)
            {
               bl->joblist = dummy;
            }
            else if (NULL != lastjob)
            {
               lastjob->next = dummy;
            }
            lastjob = dummy;
            log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
         }
      }
      else
      {
         log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d",
            buf, csp->config->re_filterfile[fileid], linenum);
      }
   }

   fclose(fp);

   /* 
    * Schedule the now-obsolete old data for unloading
    */
   if ( NULL != current_re_filterfile[fileid] )
   {
      current_re_filterfile[fileid]->unloader = unload_re_filterfile;
   }

   /*
    * Chain this file into the global list of loaded files
    */
   fs->next    = files->next;
   files->next = fs;
   current_re_filterfile[fileid] = fs;

   if (csp)
   {
      csp->rlist[fileid] = fs;
   }

   return( 0 );

load_re_filterfile_error:
   log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
             csp->config->re_filterfile[fileid]);
   return(-1);

}