Tor 0.4.9.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
18#include "lib/encoding/kvline.h"
20#include "lib/malloc/malloc.h"
22#include "lib/string/printf.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 */
38static bool
39needs_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 **/
59static 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 **/
68static 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 **/
78static bool
79kvline_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 */
125char *
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 */
199kvline_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.
char * kvline_encode(const config_line_t *line, unsigned flags)
Definition: kvline.c:126
config_line_t * kvline_parse(const char *line, unsigned flags)
Definition: kvline.c:199
static bool needs_escape(const char *s, bool as_keyless_val)
Definition: kvline.c:39
static bool kvline_can_encode_lines(const config_line_t *line, unsigned flags)
Definition: kvline.c:79
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:56
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:103
Header for util_string.c.