kvline.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. /**
  7. * \file kvline.c
  8. *
  9. * \brief Manipulating lines of key-value pairs.
  10. **/
  11. #include "orconfig.h"
  12. #include "lib/container/smartlist.h"
  13. #include "lib/encoding/confline.h"
  14. #include "lib/encoding/cstring.h"
  15. #include "lib/encoding/kvline.h"
  16. #include "lib/malloc/malloc.h"
  17. #include "lib/string/compat_ctype.h"
  18. #include "lib/string/printf.h"
  19. #include "lib/string/util_string.h"
  20. #include "lib/log/escape.h"
  21. #include "lib/log/util_bug.h"
  22. #include <stdbool.h>
  23. #include <stddef.h>
  24. #include <string.h>
  25. /** Return true iff we need to quote and escape the string <b>s</b> to encode
  26. * it. */
  27. static bool
  28. needs_escape(const char *s, bool as_keyless_val)
  29. {
  30. if (as_keyless_val && *s == 0)
  31. return true;
  32. for (; *s; ++s) {
  33. if (*s >= 127 || TOR_ISSPACE(*s) || ! TOR_ISPRINT(*s) ||
  34. *s == '\'' || *s == '\"') {
  35. return true;
  36. }
  37. }
  38. return false;
  39. }
  40. /**
  41. * Return true iff the key in <b>line</b> is not set.
  42. **/
  43. static bool
  44. line_has_no_key(const config_line_t *line)
  45. {
  46. return line->key == NULL || strlen(line->key) == 0;
  47. }
  48. /**
  49. * Return true iff the all the lines in <b>line</b> can be encoded
  50. * using <b>flags</b>.
  51. **/
  52. static bool
  53. kvline_can_encode_lines(const config_line_t *line, unsigned flags)
  54. {
  55. for ( ; line; line = line->next) {
  56. const bool keyless = line_has_no_key(line);
  57. if (keyless) {
  58. if (! (flags & KV_OMIT_KEYS)) {
  59. /* If KV_OMIT_KEYS is not set, we can't encode a line with no key. */
  60. return false;
  61. }
  62. if (strchr(line->value, '=') && !( flags & KV_QUOTED)) {
  63. /* We can't have a keyless value with = without quoting it. */
  64. return false;
  65. }
  66. }
  67. if (needs_escape(line->value, keyless) && ! (flags & KV_QUOTED)) {
  68. /* If KV_QUOTED is false, we can't encode a value that needs quotes. */
  69. return false;
  70. }
  71. if (line->key && strlen(line->key) &&
  72. (needs_escape(line->key, false) || strchr(line->key, '='))) {
  73. /* We can't handle keys that need quoting. */
  74. return false;
  75. }
  76. }
  77. return true;
  78. }
  79. /**
  80. * Encode a linked list of lines in <b>line</b> as a series of 'Key=Value'
  81. * pairs, using the provided <b>flags</b> to encode it. Return a newly
  82. * allocated string on success, or NULL on failure.
  83. *
  84. * If KV_QUOTED is set in <b>flags</b>, then all values that contain
  85. * spaces or unusual characters are escaped and quoted. Otherwise, such
  86. * values are not allowed.
  87. *
  88. * If KV_OMIT_KEYS is set in <b>flags</b>, then pairs with empty keys are
  89. * allowed, and are encoded as 'Value'. Otherwise, such pairs are not
  90. * allowed.
  91. */
  92. char *
  93. kvline_encode(const config_line_t *line,
  94. unsigned flags)
  95. {
  96. if (!kvline_can_encode_lines(line, flags))
  97. return NULL;
  98. smartlist_t *elements = smartlist_new();
  99. for (; line; line = line->next) {
  100. const char *k = "";
  101. const char *eq = "=";
  102. const char *v = "";
  103. const bool keyless = line_has_no_key(line);
  104. bool esc = needs_escape(line->value, keyless);
  105. char *tmp = NULL;
  106. if (! keyless) {
  107. k = line->key;
  108. } else {
  109. eq = "";
  110. if (strchr(line->value, '=')) {
  111. esc = true;
  112. }
  113. }
  114. if (esc) {
  115. tmp = esc_for_log(line->value);
  116. v = tmp;
  117. } else {
  118. v = line->value;
  119. }
  120. smartlist_add_asprintf(elements, "%s%s%s", k, eq, v);
  121. tor_free(tmp);
  122. }
  123. char *result = smartlist_join_strings(elements, " ", 0, NULL);
  124. SMARTLIST_FOREACH(elements, char *, cp, tor_free(cp));
  125. smartlist_free(elements);
  126. return result;
  127. }
  128. /**
  129. * Decode a <b>line</b> containing a series of space-separated 'Key=Value'
  130. * pairs, using the provided <b>flags</b> to decode it. Return a newly
  131. * allocated list of pairs on success, or NULL on failure.
  132. *
  133. * If KV_QUOTED is set in <b>flags</b>, then (double-)quoted values are
  134. * allowed. Otherwise, such values are not allowed.
  135. *
  136. * If KV_OMIT_KEYS is set in <b>flags</b>, then values without keys are
  137. * allowed. Otherwise, such values are not allowed.
  138. */
  139. config_line_t *
  140. kvline_parse(const char *line, unsigned flags)
  141. {
  142. const char *cp = line, *cplast = NULL;
  143. bool omit_keys = (flags & KV_OMIT_KEYS) != 0;
  144. bool quoted = (flags & KV_QUOTED) != 0;
  145. config_line_t *result = NULL;
  146. config_line_t **next_line = &result;
  147. char *key = NULL;
  148. char *val = NULL;
  149. while (*cp) {
  150. key = val = NULL;
  151. {
  152. size_t idx = strspn(cp, " \t\r\v\n");
  153. cp += idx;
  154. }
  155. if (BUG(cp == cplast)) {
  156. /* If we didn't parse anything, this code is broken. */
  157. goto err; // LCOV_EXCL_LINE
  158. }
  159. cplast = cp;
  160. if (! *cp)
  161. break; /* End of string; we're done. */
  162. /* Possible formats are K=V, K="V", V, and "V", depending on flags. */
  163. /* Find the key. */
  164. if (*cp != '\"') {
  165. size_t idx = strcspn(cp, " \t\r\v\n=");
  166. if (cp[idx] == '=') {
  167. key = tor_memdup_nulterm(cp, idx);
  168. cp += idx + 1;
  169. } else {
  170. if (!omit_keys)
  171. goto err;
  172. }
  173. }
  174. if (*cp == '\"') {
  175. /* The type is "V". */
  176. if (!quoted)
  177. goto err;
  178. size_t len=0;
  179. cp = unescape_string(cp, &val, &len);
  180. if (cp == NULL || len != strlen(val)) {
  181. // The string contains a NUL or is badly coded.
  182. goto err;
  183. }
  184. } else {
  185. size_t idx = strcspn(cp, " \t\r\v\n");
  186. val = tor_memdup_nulterm(cp, idx);
  187. cp += idx;
  188. }
  189. if (key && strlen(key) == 0) {
  190. /* We don't allow empty keys. */
  191. goto err;
  192. }
  193. *next_line = tor_malloc_zero(sizeof(config_line_t));
  194. (*next_line)->key = key ? key : tor_strdup("");
  195. (*next_line)->value = val;
  196. next_line = &(*next_line)->next;
  197. key = val = NULL;
  198. }
  199. if (!kvline_can_encode_lines(result, flags)) {
  200. goto err;
  201. }
  202. return result;
  203. err:
  204. tor_free(key);
  205. tor_free(val);
  206. config_free_lines(result);
  207. return NULL;
  208. }