Tor  0.4.7.0-alpha-dev
kvline.c
Go to the documentation of this file.
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 
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"
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
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
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 *
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  */
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 }
Locale-independent character-type inspection (header)
Header for confline.c.
const char * unescape_string(const char *s, char **result, size_t *size_out)
Definition: cstring.c:30
Header for cstring.c.
char * esc_for_log(const char *s)
Definition: escape.c:30
Header for escape.c.
static bool needs_escape(const char *s, bool as_keyless_val)
Definition: kvline.c:39
config_line_t * kvline_parse(const char *line, unsigned flags)
Definition: kvline.c:199
static bool kvline_can_encode_lines(const config_line_t *line, unsigned flags)
Definition: kvline.c:79
char * kvline_encode(const config_line_t *line, unsigned flags)
Definition: kvline.c:126
static bool line_has_no_key(const config_line_t *line)
Definition: kvline.c:60
static bool line_has_no_val(const config_line_t *line)
Definition: kvline.c:69
Header for kvline.c.
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:52
Header for printf.c.
const char * decode_qstring(const char *start, size_t in_len_max, char **out, size_t *out_len)
Definition: qstring.c:64
Header for qstring.c.
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
Header for smartlist.c.
smartlist_t * smartlist_new(void)
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102
Header for util_string.c.