tor  0.4.1.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/malloc/malloc.h"
21 #include "lib/string/printf.h"
22 #include "lib/string/util_string.h"
23 #include "lib/log/escape.h"
24 #include "lib/log/util_bug.h"
25 
26 #include <stdbool.h>
27 #include <stddef.h>
28 #include <string.h>
29 
32 static bool
33 needs_escape(const char *s, bool as_keyless_val)
34 {
35  if (as_keyless_val && *s == 0)
36  return true;
37 
38  for (; *s; ++s) {
39  if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
40  *s == '\'' || *s == '\"') {
41  return true;
42  }
43  }
44  return false;
45 }
46 
50 static bool
52 {
53  return line->key == NULL || strlen(line->key) == 0;
54 }
55 
60 static bool
61 kvline_can_encode_lines(const config_line_t *line, unsigned flags)
62 {
63  for ( ; line; line = line->next) {
64  const bool keyless = line_has_no_key(line);
65  if (keyless) {
66  if (! (flags & KV_OMIT_KEYS)) {
67  /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
68  return false;
69  }
70  if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
71  /* We can't have a keyless value with = without quoting it. */
72  return false;
73  }
74  }
75 
76  if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
77  /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
78  return false;
79  }
80  if (line->key && strlen(line->key) &&
81  (needs_escape(line->key, false) || strchr(line->key, '='))) {
82  /* We can't handle keys that need quoting. */
83  return false;
84  }
85  }
86  return true;
87 }
88 
102 char *
104  unsigned flags)
105 {
106  if (!kvline_can_encode_lines(line, flags))
107  return NULL;
108 
109  smartlist_t *elements = smartlist_new();
110 
111  for (; line; line = line->next) {
112 
113  const char *k = "";
114  const char *eq = "=";
115  const char *v = "";
116  const bool keyless = line_has_no_key(line);
117  bool esc = needs_escape(line->value, keyless);
118  char *tmp = NULL;
119 
120  if (! keyless) {
121  k = line->key;
122  } else {
123  eq = "";
124  if (strchr(line->value, '=')) {
125  esc = true;
126  }
127  }
128 
129  if (esc) {
130  tmp = esc_for_log(line->value);
131  v = tmp;
132  } else {
133  v = line->value;
134  }
135 
136  smartlist_add_asprintf(elements, "%s%s%s", k, eq, v);
137  tor_free(tmp);
138  }
139 
140  char *result = smartlist_join_strings(elements, " ", 0, NULL);
141 
142  SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
143  smartlist_free(elements);
144 
145  return result;
146 }
147 
160 kvline_parse(const char *line, unsigned flags)
161 {
162  const char *cp = line, *cplast = NULL;
163  bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
164  bool quoted = (flags & KV_QUOTED) != 0;
165 
166  config_line_t *result = NULL;
167  config_line_t **next_line = &result;
168 
169  char *key = NULL;
170  char *val = NULL;
171 
172  while (*cp) {
173  key = val = NULL;
174  {
175  size_t idx = strspn(cp, " \t\r\v\n");
176  cp += idx;
177  }
178  if (BUG(cp == cplast)) {
179  /* If we didn't parse anything, this code is broken. */
180  goto err; // LCOV_EXCL_LINE
181  }
182  cplast = cp;
183  if (! *cp)
184  break; /* End of string; we're done. */
185 
186  /* Possible formats are K=V, K="V", V, and "V", depending on flags. */
187 
188  /* Find the key. */
189  if (*cp != '\"') {
190  size_t idx = strcspn(cp, " \t\r\v\n=");
191 
192  if (cp[idx] == '=') {
193  key = tor_memdup_nulterm(cp, idx);
194  cp += idx + 1;
195  } else {
196  if (!omit_keys)
197  goto err;
198  }
199  }
200 
201  if (*cp == '\"') {
202  /* The type is "V". */
203  if (!quoted)
204  goto err;
205  size_t len=0;
206  cp = unescape_string(cp, &val, &len);
207  if (cp == NULL || len != strlen(val)) {
208  // The string contains a NUL or is badly coded.
209  goto err;
210  }
211  } else {
212  size_t idx = strcspn(cp, " \t\r\v\n");
213  val = tor_memdup_nulterm(cp, idx);
214  cp += idx;
215  }
216 
217  if (key && strlen(key) == 0) {
218  /* We don't allow empty keys. */
219  goto err;
220  }
221 
222  *next_line = tor_malloc_zero(sizeof(config_line_t));
223  (*next_line)->key = key ? key : tor_strdup("");
224  (*next_line)->value = val;
225  next_line = &(*next_line)->next;
226  key = val = NULL;
227  }
228 
229  if (!kvline_can_encode_lines(result, flags)) {
230  goto err;
231  }
232  return result;
233 
234  err:
235  tor_free(key);
236  tor_free(val);
237  config_free_lines(result);
238  return NULL;
239 }
Header for confline.c.
config_line_t * kvline_parse(const char *line, unsigned flags)
Definition: kvline.c:160
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:33
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:51
char * smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, size_t *len_out)
Definition: smartlist.c:279
#define SMARTLIST_FOREACH(sl, type, var, cmd)
Locale-independent character-type inspection (header)
static bool kvline_can_encode_lines(const config_line_t *line, unsigned flags)
Definition: kvline.c:61
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:103
Macros to manage assertions, fatal and non-fatal.