confline.c 11 KB

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