hackedteam/vector-ipa

View on GitHub
src/strings.c

Summary

Maintainability
Test Coverage
/*
    MODULE -- string manipulation functions

    Copyright (C) Alberto Ornaghi

    $Id: strings.c 2854 2010-09-10 15:04:07Z alor $
*/

#include <main.h>

#include <ctype.h>

/* globals */


/* protos... */

#ifndef HAVE_CTYPE_H
   int isprint(int c);
#endif
int match_pattern(const char *s, const char *pattern);
int base64_decode(char *bufplain, const char *bufcoded);
static int hextoint(int c);
int strescape(char *dst, char *src);
int str_replace(char **text, const char *s, const char *d);
size_t strlen_utf8(const char *s);
char * my_strtok(char *s, const char *delim, char **ptrptr);
void str_decode_url(u_char *src);
char * str_tohex(u_char *bin, size_t len, char *dst, size_t dst_len);
char * hex_format(const u_char *buf, size_t len, char *dst);

/*******************************************/

/* implement the function if it is not available */
#ifndef HAVE_CTYPE_H
int isprint(int c)
{
   return ( (c > 31 && c < 127) ? 1 : 0 );
}
#endif

/* Pattern matching code from OpenSSH. */

int match_pattern(const char *s, const char *pattern)
{
   for (;;) {
      if (!*pattern) return (!*s);

      if (*pattern == '*') {
         pattern++;

         if (!*pattern) return (1);

         if (*pattern != '?' && *pattern != '*') {
            for (; *s; s++) {
               if (*s == *pattern && match_pattern(s + 1, pattern + 1))
                  return (1);
            }
            return (0);
         }
         for (; *s; s++) {
            if (match_pattern(s, pattern))
               return (1);
         }
         return (0);
      }
      if (!*s) return (0);

      if (*pattern != '?' && *pattern != *s)
         return (0);

      s++;
      pattern++;
   }
   /* NOTREACHED */
}

/* stolen from ap_base64.c (apache source code) */

static const unsigned char pr2six[256] =
{
    /* ASCII table */
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
    64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
    64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
    64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};


int base64_decode(char *bufplain, const char *bufcoded)
{
    int nbytesdecoded;
    register const unsigned char *bufin;
    register unsigned char *bufout;
    register int nprbytes;

    bufin = (const unsigned char *) bufcoded;
    while (pr2six[*(bufin++)] <= 63);
    nprbytes = (bufin - (const unsigned char *) bufcoded) - 1;
    nbytesdecoded = ((nprbytes + 3) / 4) * 3;

    bufout = (unsigned char *) bufplain;
    bufin = (const unsigned char *) bufcoded;

    while (nprbytes > 4)
    {
      *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
      *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
      *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
      bufin += 4;
      nprbytes -= 4;
    }

    /* Note: (nprbytes == 1) would be an error, so just ingore that case */
    if (nprbytes > 1)
      *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);

    if (nprbytes > 2)
      *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);

    if (nprbytes > 3)
      *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);

    nbytesdecoded -= (4 - nprbytes) & 3;

    bufplain[nbytesdecoded] = '\0';
    return nbytesdecoded;
}


/* adapted from magic.c part of dsniff <dugsong@monkey.org> source code... */

/*
 * convert an HEX rapresentation into int
 */
static int hextoint(int c)
{
   if (!isascii((int) c))
      return (-1);

   if (isdigit((int) c))
      return (c - '0');

   if ((c >= 'a') && (c <= 'f'))
      return (c + 10 - 'a');

   if ((c >= 'A') && (c <= 'F'))
      return (c + 10 - 'A');

   return (-1);
}

/*
 * convert the escaped string into a binary one
 */
int strescape(char *dst, char *src)
{
   char  *olddst = dst;
   int   c;
   int   val;

   while ((c = *src++) != '\0') {
      if (c == '\\') {
         switch ((c = *src++)) {
            case '\0':
               goto strend;
            default:
               *dst++ = (char) c;
               break;
            case 'n':
               *dst++ = '\n';
               break;
            case 'r':
               *dst++ = '\r';
               break;
            case 'b':
               *dst++ = '\b';
               break;
            case 't':
               *dst++ = '\t';
               break;
            case 'f':
               *dst++ = '\f';
               break;
            case 'v':
               *dst++ = '\v';
               break;
            /* \ and up to 3 octal digits */
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
               val = c - '0';
               c = *src++;
               /* try for 2 */
               if (c >= '0' && c <= '7') {
                  val = (val << 3) | (c - '0');
                  c = *src++;
                  /* try for 3 */
                  if (c >= '0' && c <= '7')
                     val = (val << 3) | (c - '0');
                  else
                     --src;
               } else
                  --src;
               *dst++ = (char) val;
               break;

            case 'x':
               val = 'x';      /* Default if no digits */
               c = hextoint(*src++);     /* Get next char */
               if (c >= 0) {
                       val = c;
                       c = hextoint(*src++);
                       if (c >= 0)
                          val = (val << 4) + c;
                       else
                          --src;
               } else
                  --src;
               *dst++ = (char) val;
               break;
         }
      } else if (c == 8 || c == 263)  /* the backspace */
         dst--;
      else
         *dst++ = (char) c;
   }

strend:
   *dst = '\0';

   return (dst - olddst);
}


/*
 * replace 's' with 'd' in the string 'text'
 * text will be realloc'ed, so a pointer is needed
 * and stack based array can't be used
 */
int str_replace(char **text, const char *s, const char *d)
{
   size_t slen = strlen(s);
   size_t dlen = strlen(d);
   int diff = dlen - slen;
   char *p, *q = *text;
   size_t size;

   /* the search string does not exist */
   if (strstr(*text, s) == NULL)
      return -ENOTFOUND;

   /* search all the occurrence of 's' */
   while ( (p = strstr(q, s)) != NULL ) {

      /* the new size */
      if (diff > 0) {
         size = strlen(*text) + diff + 1;
         SAFE_REALLOC(*text, size);
      } else {
         size = strlen(*text);
         /* if the substituted len is smaller, don't realloc */
      }

      q = *text;

      /*
       * make sure the pointer p is within the *text memory.
       * realloc may have moved it...
       */
      p = strstr(q, s);

      /* do the actual replacement */
      memmove(p + dlen, p + slen, strlen(p + slen) + 1);
      memcpy(p, d, dlen);
      /* avoid recursion on substituted string */
      q = p + dlen;
   }

   return ESUCCESS;
}


/*
 * Calculate the correct length of characters in an UTF-8 encoded string.
 */
size_t strlen_utf8(const char *s)
{
   u_char c;
   size_t len = 0;

   while ((c = *s++)) {
      if ((c & 0xC0) != 0x80)
         ++len;
   }

   return len;
}


/*
 * a reentrant version of strtok
 */
char * my_strtok(char *s, const char *delim, char **ptrptr)
{
#ifdef HAVE_STRTOK_R
   return strtok_r(s, delim, ptrptr);
#else
   #warning unsafe strtok
   /* to avoid the warning on this function (the wrapper macro) */
   #undef strtok
   return strtok(s, delim);
#endif
}

/* Unescape the string */
void str_decode_url(u_char *src)
{
   u_char t[3];
   u_int32 i, j, ch;

   /* Paranoid test */
   if (!src)
      return;

   /* NULL terminate for the strtoul */
   t[2] = 0;

   for (i=0, j=0; src[i] != 0; i++, j++) {
      ch = (u_int32)src[i];
      if (ch == '%' && isxdigit((u_int32)src[i + 1]) && isxdigit((u_int32)src[i + 2])) {
         memcpy(t, src+i+1, 2);
         ch = strtoul((char *)t, NULL, 16);
         i += 2;
      }
      src[j] = (u_char)ch;
   }
   src[j] = 0;
}

/* convert a string of hex values into an array of bytes */
int str_hex_to_bytes(char *string, u_char *bytes)
{
   char value[3]; /* two for the hex and the NULL terminator */
   unsigned int value_bin;
   u_int i;

   for (i = 0; i < strlen(string); i++) {
      strncpy(value, string + i*2, 2);
      if (sscanf(value, "%02X", &value_bin) != 1)
         return -EINVALID;
      bytes[i] = value_bin & 0x000000FF;
   }

   return 0;
}


/* print a binary string in hex format */
char * str_tohex(u_char *bin, size_t len, char *dst, size_t dst_len)
{
   size_t i;

   memset(dst, 0, dst_len);

   for (i = 0; i < len; i++)
      sprintf(dst + i*2, "%02X", bin[i]);

   return dst;
}


/*
 * convert a buffer to a hex notation
 *
 * the string  "HTTP/1.1 304 Not Modified" becomes:
 *
 * 0000: 4854 5450 2f31 2e31 2033 3034 204e 6f74  HTTP/1.1 304 Not
 * 0010: 204d 6f64 6966 6965 64                    Modified
 */

char * hex_format(const u_char *buf, size_t len, char *dst)
{
   u_int i, j, jm, c;
   int dim = 0;

   /* some sanity checks */
   if (len == 0 || buf == NULL) {
      strcpy(dst, "");
      return 0;
   }

   for (i = 0; i < len; i += HEX_CHAR_PER_LINE) {
      sprintf(dst, "%s %04x: ", dst, i );
      jm = len - i;
      jm = jm > HEX_CHAR_PER_LINE ? HEX_CHAR_PER_LINE : jm;

      for (j = 0; j < jm; j++) {
         if ((j % 2) == 1) {
            sprintf(dst, "%s%02x ", dst, (u_char) buf[i+j]);
         } else {
            sprintf(dst, "%s%02x", dst, (u_char) buf[i+j]);
         }
      }
      for (; j < HEX_CHAR_PER_LINE; j++) {
         if ((j % 2) == 1) {
            strcat(dst, "   ");
         } else {
            strcat(dst, "  ");
         }
      }
      strcat(dst, " ");

      for (j = 0; j < jm; j++) {
         c = (u_char) buf[i+j];
         c = isprint(c) ? c : '.';
         dim = sprintf(dst, "%s%c", dst, c);
      }
      strcat(dst, "\n");
   }

   //return dim + 1;
   return dst;
}

/* EOF */

// vim:ts=3:expandtab