confline.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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/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. 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. log_notice(LD_CONFIG, "Included configuration file or "
  136. "directory at recursion level %d: \"%s\".",
  137. recursion_level, v);
  138. *next = include_list;
  139. if (list_last)
  140. next = &list_last->next;
  141. tor_free(v);
  142. } else {
  143. /* This list can get long, so we keep a pointer to the end of it
  144. * rather than using config_line_append over and over and getting
  145. * n^2 performance. */
  146. *next = tor_malloc_zero(sizeof(**next));
  147. (*next)->key = k;
  148. (*next)->value = v;
  149. (*next)->next = NULL;
  150. (*next)->command = command;
  151. list_last = *next;
  152. next = &((*next)->next);
  153. }
  154. } else {
  155. tor_free(k);
  156. tor_free(v);
  157. }
  158. } while (*string);
  159. if (last) {
  160. *last = list_last;
  161. }
  162. if (has_include) {
  163. *has_include = include_used;
  164. }
  165. *result = list;
  166. return 0;
  167. }
  168. /** Same as config_get_lines_include but does not allow %include */
  169. int
  170. config_get_lines(const char *string, config_line_t **result, int extended)
  171. {
  172. return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1,
  173. NULL, NULL);
  174. }
  175. /**
  176. * Free all the configuration lines on the linked list <b>front</b>.
  177. */
  178. void
  179. config_free_lines_(config_line_t *front)
  180. {
  181. config_line_t *tmp;
  182. while (front) {
  183. tmp = front;
  184. front = tmp->next;
  185. tor_free(tmp->key);
  186. tor_free(tmp->value);
  187. tor_free(tmp);
  188. }
  189. }
  190. /** Return a newly allocated deep copy of the lines in <b>inp</b>. */
  191. config_line_t *
  192. config_lines_dup(const config_line_t *inp)
  193. {
  194. return config_lines_dup_and_filter(inp, NULL);
  195. }
  196. /** Return a newly allocated deep copy of the lines in <b>inp</b>,
  197. * but only the ones whose keys begin with <b>key</b> (case-insensitive).
  198. * If <b>key</b> is NULL, do not filter. */
  199. config_line_t *
  200. config_lines_dup_and_filter(const config_line_t *inp,
  201. const char *key)
  202. {
  203. config_line_t *result = NULL;
  204. config_line_t **next_out = &result;
  205. while (inp) {
  206. if (key && strcasecmpstart(inp->key, key)) {
  207. inp = inp->next;
  208. continue;
  209. }
  210. *next_out = tor_malloc_zero(sizeof(config_line_t));
  211. (*next_out)->key = tor_strdup(inp->key);
  212. (*next_out)->value = tor_strdup(inp->value);
  213. inp = inp->next;
  214. next_out = &((*next_out)->next);
  215. }
  216. (*next_out) = NULL;
  217. return result;
  218. }
  219. /** Return true iff a and b contain identical keys and values in identical
  220. * order. */
  221. int
  222. config_lines_eq(config_line_t *a, config_line_t *b)
  223. {
  224. while (a && b) {
  225. if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
  226. return 0;
  227. a = a->next;
  228. b = b->next;
  229. }
  230. if (a || b)
  231. return 0;
  232. return 1;
  233. }
  234. /** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
  235. int
  236. config_count_key(const config_line_t *a, const char *key)
  237. {
  238. int n = 0;
  239. while (a) {
  240. if (!strcasecmp(a->key, key)) {
  241. ++n;
  242. }
  243. a = a->next;
  244. }
  245. return n;
  246. }
  247. /** Given a string containing part of a configuration file or similar format,
  248. * advance past comments and whitespace and try to parse a single line. If we
  249. * parse a line successfully, set *<b>key_out</b> to a new string holding the
  250. * key portion and *<b>value_out</b> to a new string holding the value portion
  251. * of the line, and return a pointer to the start of the next line. If we run
  252. * out of data, return a pointer to the end of the string. If we encounter an
  253. * error, return NULL and set *<b>err_out</b> (if provided) to an error
  254. * message.
  255. */
  256. const char *
  257. parse_config_line_from_str_verbose(const char *line, char **key_out,
  258. char **value_out,
  259. const char **err_out)
  260. {
  261. /*
  262. See torrc_format.txt for a description of the (silly) format this parses.
  263. */
  264. const char *key, *val, *cp;
  265. int continuation = 0;
  266. tor_assert(key_out);
  267. tor_assert(value_out);
  268. *key_out = *value_out = NULL;
  269. key = val = NULL;
  270. /* Skip until the first keyword. */
  271. while (1) {
  272. while (TOR_ISSPACE(*line))
  273. ++line;
  274. if (*line == '#') {
  275. while (*line && *line != '\n')
  276. ++line;
  277. } else {
  278. break;
  279. }
  280. }
  281. if (!*line) { /* End of string? */
  282. *key_out = *value_out = NULL;
  283. return line;
  284. }
  285. /* Skip until the next space or \ followed by newline. */
  286. key = line;
  287. while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
  288. ! (line[0] == '\\' && line[1] == '\n'))
  289. ++line;
  290. *key_out = tor_strndup(key, line-key);
  291. /* Skip until the value. */
  292. while (*line == ' ' || *line == '\t')
  293. ++line;
  294. val = line;
  295. /* Find the end of the line. */
  296. if (*line == '\"') { // XXX No continuation handling is done here
  297. if (!(line = unescape_string(line, value_out, NULL))) {
  298. if (err_out)
  299. *err_out = "Invalid escape sequence in quoted string";
  300. return NULL;
  301. }
  302. while (*line == ' ' || *line == '\t')
  303. ++line;
  304. if (*line == '\r' && *(++line) == '\n')
  305. ++line;
  306. if (*line && *line != '#' && *line != '\n') {
  307. if (err_out)
  308. *err_out = "Excess data after quoted string";
  309. return NULL;
  310. }
  311. } else {
  312. /* Look for the end of the line. */
  313. while (*line && *line != '\n' && (*line != '#' || continuation)) {
  314. if (*line == '\\' && line[1] == '\n') {
  315. continuation = 1;
  316. line += 2;
  317. } else if (*line == '#') {
  318. do {
  319. ++line;
  320. } while (*line && *line != '\n');
  321. if (*line == '\n')
  322. ++line;
  323. } else {
  324. ++line;
  325. }
  326. }
  327. if (*line == '\n') {
  328. cp = line++;
  329. } else {
  330. cp = line;
  331. }
  332. /* Now back cp up to be the last nonspace character */
  333. while (cp>val && TOR_ISSPACE(*(cp-1)))
  334. --cp;
  335. tor_assert(cp >= val);
  336. /* Now copy out and decode the value. */
  337. *value_out = tor_strndup(val, cp-val);
  338. if (continuation) {
  339. char *v_out, *v_in;
  340. v_out = v_in = *value_out;
  341. while (*v_in) {
  342. if (*v_in == '#') {
  343. do {
  344. ++v_in;
  345. } while (*v_in && *v_in != '\n');
  346. if (*v_in == '\n')
  347. ++v_in;
  348. } else if (v_in[0] == '\\' && v_in[1] == '\n') {
  349. v_in += 2;
  350. } else {
  351. *v_out++ = *v_in++;
  352. }
  353. }
  354. *v_out = '\0';
  355. }
  356. }
  357. if (*line == '#') {
  358. do {
  359. ++line;
  360. } while (*line && *line != '\n');
  361. }
  362. while (TOR_ISSPACE(*line)) ++line;
  363. return line;
  364. }