tor  0.4.2.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-2019, The Tor Project, Inc. */
5 /* See LICENSE for licensing information */
6 
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 
33 static bool
34 needs_escape(const char *s, bool as_keyless_val)
35 {
36  if (as_keyless_val && *s == 0)
37  return true;
38 
39  for (; *s; ++s) {
40  if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
41  *s == '\'' || *s == '\"') {
42  return true;
43  }
44  }
45  return false;
46 }
47 
51 static bool
53 {
54  return line->key == NULL || strlen(line->key) == 0;
55 }
56 
60 static bool
62 {
63  return line->value == NULL || strlen(line->value) == 0;
64 }
65 
70 static bool
71 kvline_can_encode_lines(const config_line_t *line, unsigned flags)
72 {
73  for ( ; line; line = line->next) {
74  const bool keyless = line_has_no_key(line);
75  if (keyless) {
76  if (! (flags & KV_OMIT_KEYS)) {
77  /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
78  return false;
79  }
80  if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
81  /* We can't have a keyless value with = without quoting it. */
82  return false;
83  }
84  }
85 
86  if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
87  /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
88  return false;
89  }
90  if (line->key && strlen(line->key) &&
91  (needs_escape(line->key, false) || strchr(line->key, '='))) {
92  /* We can't handle keys that need quoting. */
93  return false;
94  }
95  }
96  return true;
97 }
98 
118 char *
120  unsigned flags)
121 {
122  tor_assert(! (flags & KV_QUOTED_QSTRING));
123 
124  if (!kvline_can_encode_lines(line, flags))
125  return NULL;
126 
127  tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
128  (KV_OMIT_KEYS|KV_OMIT_VALS));
129 
130  smartlist_t *elements = smartlist_new();
131 
132  for (; line; line = line->next) {
133 
134  const char *k = "";
135  const char *eq = "=";
136  const char *v = "";
137  const bool keyless = line_has_no_key(line);
138  bool esc = needs_escape(line->value, keyless);
139  char *tmp = NULL;
140 
141  if (! keyless) {
142  k = line->key;
143  } else {
144  eq = "";
145  if (strchr(line->value, '=')) {
146  esc = true;
147  }
148  }
149 
150  if ((flags & KV_OMIT_VALS) && line_has_no_val(line)) {
151  eq = "";
152  v = "";
153  } else if (esc) {
154  tmp = esc_for_log(line->value);
155  v = tmp;
156  } else {
157  v = line->value;
158  }
159 
160  smartlist_add_asprintf(elements, "%s%s%s", k, eq, v);
161  tor_free(tmp);
162  }
163 
164  char *result = smartlist_join_strings(elements, " ", 0, NULL);
165 
166  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
167  smartlist_free(elements);
168 
169  return result;
170 }
171 
192 kvline_parse(const char *line, unsigned flags)
193 {
194  tor_assert((flags & (KV_OMIT_KEYS|KV_OMIT_VALS)) !=
195  (KV_OMIT_KEYS|KV_OMIT_VALS));
196 
197  const char *cp = line, *cplast = NULL;
198  const bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
199  const bool omit_vals = (flags & KV_OMIT_VALS) != 0;
200  const bool quoted = (flags & (KV_QUOTED|KV_QUOTED_QSTRING)) != 0;
201  const bool c_quoted = (flags & (KV_QUOTED)) != 0;
202 
203  config_line_t *result = NULL;
204  config_line_t **next_line = &result;
205 
206  char *key = NULL;
207  char *val = NULL;
208 
209  while (*cp) {
210  key = val = NULL;
211  /* skip all spaces */
212  {
213  size_t idx = strspn(cp, " \t\r\v\n");
214  cp += idx;
215  }
216  if (BUG(cp == cplast)) {
217  /* If we didn't parse anything since the last loop, this code is
218  * broken. */
219  goto err; // LCOV_EXCL_LINE
220  }
221  cplast = cp;
222  if (! *cp)
223  break; /* End of string; we're done. */
224 
225  /* Possible formats are K=V, K="V", K, V, and "V", depending on flags. */
226 
227  /* Find where the key ends */
228  if (*cp != '\"') {
229  size_t idx = strcspn(cp, " \t\r\v\n=");
230 
231  if (cp[idx] == '=') {
232  key = tor_memdup_nulterm(cp, idx);
233  cp += idx + 1;
234  } else if (omit_vals) {
235  key = tor_memdup_nulterm(cp, idx);
236  cp += idx;
237  goto commit;
238  } else {
239  if (!omit_keys)
240  goto err;
241  }
242  }
243 
244  if (*cp == '\"') {
245  /* The type is "V". */
246  if (!quoted)
247  goto err;
248  size_t len=0;
249  if (c_quoted) {
250  cp = unescape_string(cp, &val, &len);
251  } else {
252  cp = decode_qstring(cp, strlen(cp), &val, &len);
253  }
254  if (cp == NULL || len != strlen(val)) {
255  // The string contains a NUL or is badly coded.
256  goto err;
257  }
258  } else {
259  size_t idx = strcspn(cp, " \t\r\v\n");
260  val = tor_memdup_nulterm(cp, idx);
261  cp += idx;
262  }
263 
264  commit:
265  if (key && strlen(key) == 0) {
266  /* We don't allow empty keys. */
267  goto err;
268  }
269 
270  *next_line = tor_malloc_zero(sizeof(config_line_t));
271  (*next_line)->key = key ? key : tor_strdup("");
272  (*next_line)->value = val ? val : tor_strdup("");
273  next_line = &(*next_line)->next;
274  key = val = NULL;
275  }
276 
277  if (! (flags & KV_QUOTED_QSTRING)) {
278  if (!kvline_can_encode_lines(result, flags)) {
279  goto err;
280  }
281  }
282  return result;
283 
284  err:
285  tor_free(key);
286  tor_free(val);
287  config_free_lines(result);
288  return NULL;
289 }
Header for confline.c.
config_line_t * kvline_parse(const char *line, unsigned flags)
Definition: kvline.c:192
Header for printf.c.
Header for smartlist.c.
Header for cstring.c.
#define tor_free(p)
Definition: malloc.h:52
Header for util_string.c.
Headers for util_malloc.c.
static bool needs_escape(const char *s, bool as_keyless_val)
Definition: kvline.c:34
static bool line_has_no_val(const config_line_t *line)
Definition: kvline.c:61
tor_assert(buffer)
void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern,...)
Definition: smartlist.c:36
static bool line_has_no_key(const config_line_t *line)
Definition: kvline.c:52
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
const char * decode_qstring(const char *start, size_t in_len_max, char **out, size_t *out_len)
Definition: qstring.c:64
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Locale-independent character-type inspection (header)
Header for qstring.c.
static bool kvline_can_encode_lines(const config_line_t *line, unsigned flags)
Definition: kvline.c:71
Header for kvline.c.
Header for escape.c.
const char * unescape_string(const char *s, char **result, size_t *size_out)
Definition: cstring.c:30
char * esc_for_log(const char *s)
Definition: escape.c:30
char * kvline_encode(const config_line_t *line, unsigned flags)
Definition: kvline.c:119
Macros to manage assertions, fatal and non-fatal.