kvline.c (8084B)
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 kvline.c 9 * 10 * \brief Manipulating lines of key-value pairs. 11 **/ 12 13 #include "orconfig.h" 14 15 #include "lib/container/smartlist.h" 16 #include "lib/encoding/confline.h" 17 #include "lib/encoding/cstring.h" 18 #include "lib/encoding/kvline.h" 19 #include "lib/encoding/qstring.h" 20 #include "lib/malloc/malloc.h" 21 #include "lib/string/compat_ctype.h" 22 #include "lib/string/printf.h" 23 #include "lib/string/util_string.h" 24 #include "lib/log/escape.h" 25 #include "lib/log/util_bug.h" 26 27 #include <stdbool.h> 28 #include <stddef.h> 29 #include <string.h> 30 31 /** Return true iff we need to quote and escape the string <b>s</b> to encode 32 * it. 33 * 34 * kvline_can_encode_lines() also uses this (with 35 * <b>as_keyless_val</b> true) to check whether a key would require 36 * quoting. 37 */ 38 static bool 39 needs_escape(const char *s, bool as_keyless_val) 40 { 41 if (as_keyless_val && *s == 0) 42 return true; 43 /* Keyless values containing '=' need to be escaped. */ 44 if (as_keyless_val && strchr(s, '=')) 45 return true; 46 47 for (; *s; ++s) { 48 if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) || 49 *s == '\'' || *s == '\"') { 50 return true; 51 } 52 } 53 return false; 54 } 55 56 /** 57 * Return true iff the key in <b>line</b> is not set. 58 **/ 59 static bool 60 line_has_no_key(const config_line_t *line) 61 { 62 return line->key == NULL || strlen(line->key) == 0; 63 } 64 65 /** 66 * Return true iff the value in <b>line</b> is not set. 67 **/ 68 static bool 69 line_has_no_val(const config_line_t *line) 70 { 71 return line->value == NULL || strlen(line->value) == 0; 72 } 73 74 /** 75 * Return true iff the all the lines in <b>line</b> can be encoded 76 * using <b>flags</b>. 77 **/ 78 static bool 79 kvline_can_encode_lines(const config_line_t *line, unsigned flags) 80 { 81 for ( ; line; line = line->next) { 82 const bool keyless = line_has_no_key(line); 83 if (keyless && ! (flags & KV_OMIT_KEYS)) { 84 /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */ 85 return false; 86 } 87 88 if (needs_escape(line->value, keyless) && ! (flags & (KV_QUOTED|KV_RAW))) { 89 /* If both KV_QUOTED and KV_RAW are false, we can't encode a 90 value that needs quotes. */ 91 return false; 92 } 93 if (!keyless && needs_escape(line->key, true)) { 94 /* We can't handle keys that need quoting. */ 95 return false; 96 } 97 } 98 return true; 99 } 100 101 /** 102 * Encode a linked list of lines in <b>line</b> as a series of 'Key=Value' 103 * pairs, using the provided <b>flags</b> to encode it. Return a newly 104 * allocated string on success, or NULL on failure. 105 * 106 * If KV_QUOTED is set in <b>flags</b>, then all values that contain 107 * spaces or unusual characters are escaped and quoted. Otherwise, such 108 * values are not allowed. Mutually exclusive with KV_RAW. 109 * 110 * If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are 111 * allowed, and are encoded as 'Value'. Otherwise, such pairs are not 112 * allowed. 113 * 114 * If KV_OMIT_VALS is set in <b>flags</b>, then an empty value is 115 * encoded as 'Key', not as 'Key=' or 'Key=""'. Mutually exclusive with 116 * KV_OMIT_KEYS. 117 * 118 * If KV_RAW is set in <b>flags</b>, then don't apply any quoting to 119 * the value, and assume that the caller has adequately quoted it. 120 * (The control protocol has some quirks that make this necessary.) 121 * Mutually exclusive with KV_QUOTED. 122 * 123 * KV_QUOTED_QSTRING is not supported. 124 */ 125 char * 126 kvline_encode(const config_line_t *line, 127 unsigned flags) 128 { 129 tor_assert(! (flags & KV_QUOTED_QSTRING)); 130 131 tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) != 132 (KV_OMIT_KEYS|KV_OMIT_VALS)); 133 tor_assert((flags & (KV_QUOTED|KV_RAW)) != (KV_QUOTED|KV_RAW)); 134 135 if (!kvline_can_encode_lines(line, flags)) 136 return NULL; 137 138 smartlist_t *elements = smartlist_new(); 139 140 for (; line; line = line->next) { 141 142 const char *k = ""; 143 const char *eq = "="; 144 const char *v = ""; 145 const bool keyless = line_has_no_key(line); 146 bool esc = needs_escape(line->value, keyless); 147 char *tmp = NULL; 148 149 if (! keyless) { 150 k = line->key; 151 } else { 152 eq = ""; 153 } 154 155 if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) { 156 eq = ""; 157 v = ""; 158 } else if (!(flags & KV_RAW) && esc) { 159 tmp = esc_for_log(line->value); 160 v = tmp; 161 } else { 162 v = line->value; 163 } 164 165 smartlist_add_asprintf(elements, "%s%s%s", k, eq, v); 166 tor_free(tmp); 167 } 168 169 char *result = smartlist_join_strings(elements, " ", 0, NULL); 170 171 SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp)); 172 smartlist_free(elements); 173 174 return result; 175 } 176 177 /** 178 * Decode a <b>line</b> containing a series of space-separated 'Key=Value' 179 * pairs, using the provided <b>flags</b> to decode it. Return a newly 180 * allocated list of pairs on success, or NULL on failure. 181 * 182 * If KV_QUOTED is set in <b>flags</b>, then (double-)quoted values are 183 * allowed and handled as C strings. Otherwise, such values are not allowed. 184 * 185 * If KV_OMIT_KEYS is set in <b>flags</b>, then values without keys are 186 * allowed. Otherwise, such values are not allowed. 187 * 188 * If KV_OMIT_VALS is set in <b>flags</b>, then keys without values are 189 * allowed. Otherwise, such keys are not allowed. Mutually exclusive with 190 * KV_OMIT_KEYS. 191 * 192 * If KV_QUOTED_QSTRING is set in <b>flags</b>, then double-quoted values 193 * are allowed and handled as QuotedStrings per qstring.c. Do not add 194 * new users of this flag. 195 * 196 * KV_RAW is not supported. 197 */ 198 config_line_t * 199 kvline_parse(const char *line, unsigned flags) 200 { 201 tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) != 202 (KV_OMIT_KEYS|KV_OMIT_VALS)); 203 tor_assert(!(flags & KV_RAW)); 204 205 const char *cp = line, *cplast = NULL; 206 const bool omit_keys = (flags & KV_OMIT_KEYS) != 0; 207 const bool omit_vals = (flags & KV_OMIT_VALS) != 0; 208 const bool quoted = (flags & (KV_QUOTED|KV_QUOTED_QSTRING)) != 0; 209 const bool c_quoted = (flags & (KV_QUOTED)) != 0; 210 211 config_line_t *result = NULL; 212 config_line_t **next_line = &result; 213 214 char *key = NULL; 215 char *val = NULL; 216 217 while (*cp) { 218 key = val = NULL; 219 /* skip all spaces */ 220 { 221 size_t idx = strspn(cp, " \t\r\v\n"); 222 cp += idx; 223 } 224 if (BUG(cp == cplast)) { 225 /* If we didn't parse anything since the last loop, this code is 226 * broken. */ 227 goto err; // LCOV_EXCL_LINE 228 } 229 cplast = cp; 230 if (! *cp) 231 break; /* End of string; we're done. */ 232 233 /* Possible formats are K=V, K="V", K, V, and "V", depending on flags. */ 234 235 /* Find where the key ends */ 236 if (*cp != '\"') { 237 size_t idx = strcspn(cp, " \t\r\v\n="); 238 239 if (cp[idx] == '=') { 240 key = tor_memdup_nulterm(cp, idx); 241 cp += idx + 1; 242 } else if (omit_vals) { 243 key = tor_memdup_nulterm(cp, idx); 244 cp += idx; 245 goto commit; 246 } else { 247 if (!omit_keys) 248 goto err; 249 } 250 } 251 252 if (*cp == '\"') { 253 /* The type is "V". */ 254 if (!quoted) 255 goto err; 256 size_t len=0; 257 if (c_quoted) { 258 cp = unescape_string(cp, &val, &len); 259 } else { 260 cp = decode_qstring(cp, strlen(cp), &val, &len); 261 } 262 if (cp == NULL || len != strlen(val)) { 263 // The string contains a NUL or is badly coded. 264 goto err; 265 } 266 } else { 267 size_t idx = strcspn(cp, " \t\r\v\n"); 268 val = tor_memdup_nulterm(cp, idx); 269 cp += idx; 270 } 271 272 commit: 273 if (key && strlen(key) == 0) { 274 /* We don't allow empty keys. */ 275 goto err; 276 } 277 278 *next_line = tor_malloc_zero(sizeof(config_line_t)); 279 (*next_line)->key = key ? key : tor_strdup(""); 280 (*next_line)->value = val ? val : tor_strdup(""); 281 next_line = &(*next_line)->next; 282 key = val = NULL; 283 } 284 285 if (! (flags & KV_QUOTED_QSTRING)) { 286 if (!kvline_can_encode_lines(result, flags)) { 287 goto err; 288 } 289 } 290 return result; 291 292 err: 293 tor_free(key); 294 tor_free(val); 295 config_free_lines(result); 296 return NULL; 297 }