Line data Source code
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 77 : unescape_string(const char *s, char **result, size_t *size_out) 31 : { 32 77 : const char *cp; 33 77 : char *out; 34 77 : if (s[0] != '\"') 35 : return NULL; 36 77 : cp = s+1; 37 806 : while (1) { 38 806 : switch (*cp) { 39 : case '\0': 40 : case '\n': 41 : return NULL; 42 61 : case '\"': 43 61 : goto end_of_loop; 44 39 : case '\\': 45 39 : if (cp[1] == 'x' || cp[1] == 'X') { 46 9 : if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) 47 : return NULL; 48 5 : cp += 4; 49 30 : } else if (TOR_ISODIGIT(cp[1])) { 50 5 : cp += 2; 51 5 : if (TOR_ISODIGIT(*cp)) ++cp; 52 5 : 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 19 : cp += 2; 56 : } else { 57 : return NULL; 58 : } 59 : break; 60 700 : default: 61 700 : ++cp; 62 700 : break; 63 : } 64 : } 65 61 : end_of_loop: 66 61 : out = *result = tor_malloc(cp-s + 1); 67 61 : cp = s+1; 68 674 : while (1) { 69 674 : switch (*cp) 70 : { 71 61 : case '\"': 72 61 : *out = '\0'; 73 61 : if (size_out) *size_out = out - *result; 74 61 : 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 28 : case '\\': 83 28 : switch (cp[1]) 84 : { 85 3 : case 'n': *out++ = '\n'; cp += 2; break; 86 1 : case 'r': *out++ = '\r'; cp += 2; break; 87 3 : case 't': *out++ = '\t'; cp += 2; break; 88 5 : case 'x': case 'X': 89 : { 90 5 : int x1, x2; 91 : 92 5 : x1 = hex_decode_digit(cp[2]); 93 5 : x2 = hex_decode_digit(cp[3]); 94 5 : 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 5 : *out++ = ((x1<<4) + x2); 104 5 : cp += 4; 105 : } 106 5 : break; 107 5 : case '0': case '1': case '2': case '3': case '4': case '5': 108 : case '6': case '7': 109 : { 110 5 : int n = cp[1]-'0'; 111 5 : cp += 2; 112 5 : if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } 113 5 : if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } 114 5 : if (n > 255) { tor_free(*result); return NULL; } 115 5 : *out++ = (char)n; 116 : } 117 5 : break; 118 11 : case '\'': 119 : case '\"': 120 : case '\\': 121 : case '\?': 122 11 : *out++ = cp[1]; 123 11 : cp += 2; 124 11 : 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 585 : default: 135 585 : *out++ = *cp++; 136 : } 137 : } 138 : }