tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

cstring.c (3865B)


      1 /* Copyright (c) 2001 Matej Pfajfar.
      2 * Copyright (c) 2001-2004, Roger Dingledine.
      3 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      4 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      5 /* See LICENSE for licensing information */
      6 
      7 /**
      8 * \file cstring.c
      9 *
     10 * \brief Decode data that has been written as a C literal.
     11 **/
     12 
     13 #include "lib/encoding/cstring.h"
     14 #include "lib/log/log.h"
     15 #include "lib/log/util_bug.h"
     16 #include "lib/malloc/malloc.h"
     17 #include "lib/string/compat_ctype.h"
     18 
     19 #include <string.h>
     20 
     21 #define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7')
     22 
     23 /** Given a c-style double-quoted escaped string in <b>s</b>, extract and
     24 * decode its contents into a newly allocated string.  On success, assign this
     25 * string to *<b>result</b>, assign its length to <b>size_out</b> (if
     26 * provided), and return a pointer to the position in <b>s</b> immediately
     27 * after the string.  On failure, return NULL.
     28 */
     29 const char *
     30 unescape_string(const char *s, char **result, size_t *size_out)
     31 {
     32  const char *cp;
     33  char *out;
     34  if (s[0] != '\"')
     35    return NULL;
     36  cp = s+1;
     37  while (1) {
     38    switch (*cp) {
     39      case '\0':
     40      case '\n':
     41        return NULL;
     42      case '\"':
     43        goto end_of_loop;
     44      case '\\':
     45        if (cp[1] == 'x' || cp[1] == 'X') {
     46          if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3])))
     47            return NULL;
     48          cp += 4;
     49        } else if (TOR_ISODIGIT(cp[1])) {
     50          cp += 2;
     51          if (TOR_ISODIGIT(*cp)) ++cp;
     52          if (TOR_ISODIGIT(*cp)) ++cp;
     53        } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"'
     54                   || cp[1] == '\\' || cp[1] == '\'') {
     55          cp += 2;
     56        } else {
     57          return NULL;
     58        }
     59        break;
     60      default:
     61        ++cp;
     62        break;
     63    }
     64  }
     65 end_of_loop:
     66  out = *result = tor_malloc(cp-s + 1);
     67  cp = s+1;
     68  while (1) {
     69    switch (*cp)
     70      {
     71      case '\"':
     72        *out = '\0';
     73        if (size_out) *size_out = out - *result;
     74        return cp+1;
     75 
     76        /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */
     77      case '\0':
     78        tor_fragile_assert();
     79        tor_free(*result);
     80        return NULL;
     81        /* LCOV_EXCL_STOP */
     82      case '\\':
     83        switch (cp[1])
     84          {
     85          case 'n': *out++ = '\n'; cp += 2; break;
     86          case 'r': *out++ = '\r'; cp += 2; break;
     87          case 't': *out++ = '\t'; cp += 2; break;
     88          case 'x': case 'X':
     89            {
     90              int x1, x2;
     91 
     92              x1 = hex_decode_digit(cp[2]);
     93              x2 = hex_decode_digit(cp[3]);
     94              if (x1 == -1 || x2 == -1) {
     95                /* LCOV_EXCL_START */
     96                /* we caught this above in the initial loop. */
     97                tor_assert_nonfatal_unreached();
     98                tor_free(*result);
     99                return NULL;
    100                /* LCOV_EXCL_STOP */
    101              }
    102 
    103              *out++ = ((x1<<4) + x2);
    104              cp += 4;
    105            }
    106            break;
    107          case '0': case '1': case '2': case '3': case '4': case '5':
    108          case '6': case '7':
    109            {
    110              int n = cp[1]-'0';
    111              cp += 2;
    112              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
    113              if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; }
    114              if (n > 255) { tor_free(*result); return NULL; }
    115              *out++ = (char)n;
    116            }
    117            break;
    118          case '\'':
    119          case '\"':
    120          case '\\':
    121          case '\?':
    122            *out++ = cp[1];
    123            cp += 2;
    124            break;
    125 
    126            /* LCOV_EXCL_START */
    127          default:
    128            /* we caught this above in the initial loop. */
    129            tor_assert_nonfatal_unreached();
    130            tor_free(*result); return NULL;
    131            /* LCOV_EXCL_STOP */
    132          }
    133        break;
    134      default:
    135        *out++ = *cp++;
    136      }
    137  }
    138 }