confline.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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-2018, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. /**
  7. * \file confline.c
  8. *
  9. * \brief Functions to manipulate a linked list of key-value pairs, of the
  10. * type used in Tor's configuration files.
  11. *
  12. * Tor uses the config_line_t type and its associated serialized format for
  13. * human-readable key-value pairs in many places, including its configuration,
  14. * its state files, its consensus cache, and so on.
  15. **/
  16. #include "lib/encoding/confline.h"
  17. #include "lib/encoding/cstring.h"
  18. #include "lib/log/torlog.h"
  19. #include "lib/log/util_bug.h"
  20. #include "lib/malloc/util_malloc.h"
  21. #include "lib/string/compat_ctype.h"
  22. #include "lib/string/compat_string.h"
  23. #include "lib/string/util_string.h"
  24. #include <string.h>
  25. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  26. * append it to *<b>lst</b>. */
  27. void
  28. config_line_append(config_line_t **lst,
  29. const char *key,
  30. const char *val)
  31. {
  32. tor_assert(lst);
  33. config_line_t *newline;
  34. newline = tor_malloc_zero(sizeof(config_line_t));
  35. newline->key = tor_strdup(key);
  36. newline->value = tor_strdup(val);
  37. newline->next = NULL;
  38. while (*lst)
  39. lst = &((*lst)->next);
  40. (*lst) = newline;
  41. }
  42. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  43. * and prepend it to *<b>lst</b> */
  44. void
  45. config_line_prepend(config_line_t **lst,
  46. const char *key,
  47. const char *val)
  48. {
  49. tor_assert(lst);
  50. config_line_t *newline;
  51. newline = tor_malloc_zero(sizeof(config_line_t));
  52. newline->key = tor_strdup(key);
  53. newline->value = tor_strdup(val);
  54. newline->next = *lst;
  55. *lst = newline;
  56. }
  57. /** Return the first line in <b>lines</b> whose key is exactly <b>key</b>, or
  58. * NULL if no such key exists.
  59. *
  60. * (In options parsing, this is for handling commandline-only options only;
  61. * other options should be looked up in the appropriate data structure.) */
  62. const config_line_t *
  63. config_line_find(const config_line_t *lines,
  64. const char *key)
  65. {
  66. const config_line_t *cl;
  67. for (cl = lines; cl; cl = cl->next) {
  68. if (!strcmp(cl->key, key))
  69. return cl;
  70. }
  71. return NULL;
  72. }
  73. /** Auxiliary function that does all the work of config_get_lines.
  74. * <b>recursion_level</b> is the count of how many nested %includes we have.
  75. * <b>opened_lst</b> will have a list of opened files if provided.
  76. * Returns the a pointer to the last element of the <b>result</b> in
  77. * <b>last</b>. */
  78. int
  79. config_get_lines_aux(const char *string, config_line_t **result, int extended,
  80. int allow_include, int *has_include,
  81. struct smartlist_t *opened_lst, int recursion_level,
  82. config_line_t **last,
  83. include_handler_fn handle_include)
  84. {
  85. config_line_t *list = NULL, **next, *list_last = NULL;
  86. char *k, *v;
  87. const char *parse_err;
  88. int include_used = 0;
  89. if (recursion_level > MAX_INCLUDE_RECURSION_LEVEL) {
  90. log_warn(LD_CONFIG, "Error while parsing configuration: more than %d "
  91. "nested %%includes.", MAX_INCLUDE_RECURSION_LEVEL);
  92. return -1;
  93. }
  94. next = &list;
  95. do {
  96. k = v = NULL;
  97. string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
  98. if (!string) {
  99. log_warn(LD_CONFIG, "Error while parsing configuration: %s",
  100. parse_err?parse_err:"<unknown>");
  101. config_free_lines(list);
  102. tor_free(k);
  103. tor_free(v);
  104. return -1;
  105. }
  106. if (k && v) {
  107. unsigned command = CONFIG_LINE_NORMAL;
  108. if (extended) {
  109. if (k[0] == '+') {
  110. char *k_new = tor_strdup(k+1);
  111. tor_free(k);
  112. k = k_new;
  113. command = CONFIG_LINE_APPEND;
  114. } else if (k[0] == '/') {
  115. char *k_new = tor_strdup(k+1);
  116. tor_free(k);
  117. k = k_new;
  118. tor_free(v);
  119. v = tor_strdup("");
  120. command = CONFIG_LINE_CLEAR;
  121. }
  122. }
  123. if (allow_include && !strcmp(k, "%include") && handle_include) {
  124. tor_free(k);
  125. include_used = 1;
  126. config_line_t *include_list;
  127. if (handle_include(v, recursion_level, extended, &include_list,
  128. &list_last, opened_lst) < 0) {
  129. log_warn(LD_CONFIG, "Error reading included configuration "
  130. "file or directory: \"%s\".", v);
  131. config_free_lines(list);
  132. tor_free(v);
  133. return -1;
  134. }
  135. *next = include_list;
  136. if (list_last)
  137. next = &list_last->next;
  138. tor_free(v);
  139. } else {
  140. /* This list can get long, so we keep a pointer to the end of it
  141. * rather than using config_line_append over and over and getting
  142. * n^2 performance. */
  143. *next = tor_malloc_zero(sizeof(**next));
  144. (*next)->key = k;
  145. (*next)->value = v;
  146. (*next)->next = NULL;
  147. (*next)->command = command;
  148. list_last = *next;
  149. next = &((*next)->next);
  150. }
  151. } else {
  152. tor_free(k);
  153. tor_free(v);
  154. }
  155. } while (*string);
  156. if (last) {
  157. *last = list_last;
  158. }
  159. if (has_include) {
  160. *has_include = include_used;
  161. }
  162. *result = list;
  163. return 0;
  164. }
  165. /** Same as config_get_lines_include but does not allow %include */
  166. int
  167. config_get_lines(const char *string, config_line_t **result, int extended)
  168. {
  169. return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
  170. NULL, NULL);
  171. }
  172. /**
  173. * Free all the configuration lines on the linked list <b>front</b>.
  174. */
  175. void
  176. config_free_lines_(config_line_t *front)
  177. {
  178. config_line_t *tmp;
  179. while (front) {
  180. tmp = front;
  181. front = tmp->next;
  182. tor_free(tmp->key);
  183. tor_free(tmp->value);
  184. tor_free(tmp);
  185. }
  186. }
  187. /** Return a newly allocated deep copy of the lines in <b>inp</b>. */
  188. config_line_t *
  189. config_lines_dup(const config_line_t *inp)
  190. {
  191. return config_lines_dup_and_filter(inp, NULL);
  192. }
  193. /** Return a newly allocated deep copy of the lines in <b>inp</b>,
  194. * but only the ones whose keys begin with <b>key</b> (case-insensitive).
  195. * If <b>key</b> is NULL, do not filter. */
  196. config_line_t *
  197. config_lines_dup_and_filter(const config_line_t *inp,
  198. const char *key)
  199. {
  200. config_line_t *result = NULL;
  201. config_line_t **next_out = &result;
  202. while (inp) {
  203. if (key && strcasecmpstart(inp->key, key)) {
  204. inp = inp->next;
  205. continue;
  206. }
  207. *next_out = tor_malloc_zero(sizeof(config_line_t));
  208. (*next_out)->key = tor_strdup(inp->key);
  209. (*next_out)->value = tor_strdup(inp->value);
  210. inp = inp->next;
  211. next_out = &((*next_out)->next);
  212. }
  213. (*next_out) = NULL;
  214. return result;
  215. }
  216. /** Return true iff a and b contain identical keys and values in identical
  217. * order. */
  218. int
  219. config_lines_eq(config_line_t *a, config_line_t *b)
  220. {
  221. while (a && b) {
  222. if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
  223. return 0;
  224. a = a->next;
  225. b = b->next;
  226. }
  227. if (a || b)
  228. return 0;
  229. return 1;
  230. }
  231. /** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
  232. int
  233. config_count_key(const config_line_t *a, const char *key)
  234. {
  235. int n = 0;
  236. while (a) {
  237. if (!strcasecmp(a->key, key)) {
  238. ++n;
  239. }
  240. a = a->next;
  241. }
  242. return n;
  243. }
  244. /** Given a string containing part of a configuration file or similar format,
  245. * advance past comments and whitespace and try to parse a single line. If we
  246. * parse a line successfully, set *<b>key_out</b> to a new string holding the
  247. * key portion and *<b>value_out</b> to a new string holding the value portion
  248. * of the line, and return a pointer to the start of the next line. If we run
  249. * out of data, return a pointer to the end of the string. If we encounter an
  250. * error, return NULL and set *<b>err_out</b> (if provided) to an error
  251. * message.
  252. */
  253. const char *
  254. parse_config_line_from_str_verbose(const char *line, char **key_out,
  255. char **value_out,
  256. const char **err_out)
  257. {
  258. /*
  259. See torrc_format.txt for a description of the (silly) format this parses.
  260. */
  261. const char *key, *val, *cp;
  262. int continuation = 0;
  263. tor_assert(key_out);
  264. tor_assert(value_out);
  265. *key_out = *value_out = NULL;
  266. key = val = NULL;
  267. /* Skip until the first keyword. */
  268. while (1) {
  269. while (TOR_ISSPACE(*line))
  270. ++line;
  271. if (*line == '#') {
  272. while (*line && *line != '\n')
  273. ++line;
  274. } else {
  275. break;
  276. }
  277. }
  278. if (!*line) { /* End of string? */
  279. *key_out = *value_out = NULL;
  280. return line;
  281. }
  282. /* Skip until the next space or \ followed by newline. */
  283. key = line;
  284. while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
  285. ! (line[0] == '\\' && line[1] == '\n'))
  286. ++line;
  287. *key_out = tor_strndup(key, line-key);
  288. /* Skip until the value. */
  289. while (*line == ' ' || *line == '\t')
  290. ++line;
  291. val = line;
  292. /* Find the end of the line. */
  293. if (*line == '\"') { // XXX No continuation handling is done here
  294. if (!(line = unescape_string(line, value_out, NULL))) {
  295. if (err_out)
  296. *err_out = "Invalid escape sequence in quoted string";
  297. return NULL;
  298. }
  299. while (*line == ' ' || *line == '\t')
  300. ++line;
  301. if (*line == '\r' && *(++line) == '\n')
  302. ++line;
  303. if (*line && *line != '#' && *line != '\n') {
  304. if (err_out)
  305. *err_out = "Excess data after quoted string";
  306. return NULL;
  307. }
  308. } else {
  309. /* Look for the end of the line. */
  310. while (*line && *line != '\n' && (*line != '#' || continuation)) {
  311. if (*line == '\\' && line[1] == '\n') {
  312. continuation = 1;
  313. line += 2;
  314. } else if (*line == '#') {
  315. do {
  316. ++line;
  317. } while (*line && *line != '\n');
  318. if (*line == '\n')
  319. ++line;
  320. } else {
  321. ++line;
  322. }
  323. }
  324. if (*line == '\n') {
  325. cp = line++;
  326. } else {
  327. cp = line;
  328. }
  329. /* Now back cp up to be the last nonspace character */
  330. while (cp>val && TOR_ISSPACE(*(cp-1)))
  331. --cp;
  332. tor_assert(cp >= val);
  333. /* Now copy out and decode the value. */
  334. *value_out = tor_strndup(val, cp-val);
  335. if (continuation) {
  336. char *v_out, *v_in;
  337. v_out = v_in = *value_out;
  338. while (*v_in) {
  339. if (*v_in == '#') {
  340. do {
  341. ++v_in;
  342. } while (*v_in && *v_in != '\n');
  343. if (*v_in == '\n')
  344. ++v_in;
  345. } else if (v_in[0] == '\\' && v_in[1] == '\n') {
  346. v_in += 2;
  347. } else {
  348. *v_out++ = *v_in++;
  349. }
  350. }
  351. *v_out = '\0';
  352. }
  353. }
  354. if (*line == '#') {
  355. do {
  356. ++line;
  357. } while (*line && *line != '\n');
  358. }
  359. while (TOR_ISSPACE(*line)) ++line;
  360. return line;
  361. }