confline.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  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-2017, The Tor Project, Inc. */
  5. /* See LICENSE for licensing information */
  6. #include "compat.h"
  7. #include "confline.h"
  8. #include "torlog.h"
  9. #include "util.h"
  10. #include "container.h"
  11. static int config_get_lines_aux(const char *string, config_line_t **result,
  12. int extended, int allow_include,
  13. int *has_include, int recursion_level,
  14. config_line_t **last);
  15. static smartlist_t *config_get_file_list(const char *path);
  16. static int config_get_included_list(const char *path, int recursion_level,
  17. int extended, config_line_t **list,
  18. config_line_t **list_last);
  19. static int config_process_include(const char *path, int recursion_level,
  20. int extended, config_line_t **list,
  21. config_line_t **list_last);
  22. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  23. * append it to *<b>lst</b>. */
  24. void
  25. config_line_append(config_line_t **lst,
  26. const char *key,
  27. const char *val)
  28. {
  29. tor_assert(lst);
  30. config_line_t *newline;
  31. newline = tor_malloc_zero(sizeof(config_line_t));
  32. newline->key = tor_strdup(key);
  33. newline->value = tor_strdup(val);
  34. newline->next = NULL;
  35. while (*lst)
  36. lst = &((*lst)->next);
  37. (*lst) = newline;
  38. }
  39. /** Helper: allocate a new configuration option mapping 'key' to 'val',
  40. * and prepend it to *<b>lst</b> */
  41. void
  42. config_line_prepend(config_line_t **lst,
  43. const char *key,
  44. const char *val)
  45. {
  46. tor_assert(lst);
  47. config_line_t *newline;
  48. newline = tor_malloc_zero(sizeof(config_line_t));
  49. newline->key = tor_strdup(key);
  50. newline->value = tor_strdup(val);
  51. newline->next = *lst;
  52. *lst = newline;
  53. }
  54. /** Return the first line in <b>lines</b> whose key is exactly <b>key</b>, or
  55. * NULL if no such key exists.
  56. *
  57. * (In options parsing, this is for handling commandline-only options only;
  58. * other options should be looked up in the appropriate data structure.) */
  59. const config_line_t *
  60. config_line_find(const config_line_t *lines,
  61. const char *key)
  62. {
  63. const config_line_t *cl;
  64. for (cl = lines; cl; cl = cl->next) {
  65. if (!strcmp(cl->key, key))
  66. return cl;
  67. }
  68. return NULL;
  69. }
  70. /** Auxiliary function that does all the work of config_get_lines.
  71. * <b>recursion_level</b> is the count of how many nested %includes we have.
  72. * Returns the a pointer to the last element of the <b>result</b> in
  73. * <b>last</b>. */
  74. static int
  75. config_get_lines_aux(const char *string, config_line_t **result, int extended,
  76. int allow_include, int *has_include, int recursion_level,
  77. config_line_t **last)
  78. {
  79. config_line_t *list = NULL, **next, *list_last = NULL;
  80. char *k, *v;
  81. const char *parse_err;
  82. int include_used = 0;
  83. if (recursion_level > MAX_INCLUDE_RECURSION_LEVEL) {
  84. log_warn(LD_CONFIG, "Error while parsing configuration: more than %d "
  85. "nested %%includes.", MAX_INCLUDE_RECURSION_LEVEL);
  86. return -1;
  87. }
  88. next = &list;
  89. do {
  90. k = v = NULL;
  91. string = parse_config_line_from_str_verbose(string, &k, &v, &parse_err);
  92. if (!string) {
  93. log_warn(LD_CONFIG, "Error while parsing configuration: %s",
  94. parse_err?parse_err:"<unknown>");
  95. config_free_lines(list);
  96. tor_free(k);
  97. tor_free(v);
  98. return -1;
  99. }
  100. if (k && v) {
  101. unsigned command = CONFIG_LINE_NORMAL;
  102. if (extended) {
  103. if (k[0] == '+') {
  104. char *k_new = tor_strdup(k+1);
  105. tor_free(k);
  106. k = k_new;
  107. command = CONFIG_LINE_APPEND;
  108. } else if (k[0] == '/') {
  109. char *k_new = tor_strdup(k+1);
  110. tor_free(k);
  111. k = k_new;
  112. tor_free(v);
  113. v = tor_strdup("");
  114. command = CONFIG_LINE_CLEAR;
  115. }
  116. }
  117. if (allow_include && !strcmp(k, "%include")) {
  118. tor_free(k);
  119. include_used = 1;
  120. config_line_t *include_list;
  121. if (config_process_include(v, recursion_level, extended, &include_list,
  122. &list_last) < 0) {
  123. log_warn(LD_CONFIG, "Error reading included configuration "
  124. "file or directory: \"%s\".", v);
  125. config_free_lines(list);
  126. tor_free(v);
  127. return -1;
  128. }
  129. *next = include_list;
  130. if (list_last)
  131. next = &list_last->next;
  132. tor_free(v);
  133. } else {
  134. /* This list can get long, so we keep a pointer to the end of it
  135. * rather than using config_line_append over and over and getting
  136. * n^2 performance. */
  137. *next = tor_malloc_zero(sizeof(**next));
  138. (*next)->key = k;
  139. (*next)->value = v;
  140. (*next)->next = NULL;
  141. (*next)->command = command;
  142. list_last = *next;
  143. next = &((*next)->next);
  144. }
  145. } else {
  146. tor_free(k);
  147. tor_free(v);
  148. }
  149. } while (*string);
  150. if (last) {
  151. *last = list_last;
  152. }
  153. if (has_include) {
  154. *has_include = include_used;
  155. }
  156. *result = list;
  157. return 0;
  158. }
  159. /** Helper: parse the config string and strdup into key/value
  160. * strings. Set *result to the list, or NULL if parsing the string
  161. * failed. Set *has_include to 1 if <b>result</b> has values from
  162. * %included files. Return 0 on success, -1 on failure. Warn and ignore any
  163. * misformatted lines.
  164. *
  165. * If <b>extended</b> is set, then treat keys beginning with / and with + as
  166. * indicating "clear" and "append" respectively. */
  167. int
  168. config_get_lines_include(const char *string, config_line_t **result,
  169. int extended, int *has_include)
  170. {
  171. return config_get_lines_aux(string, result, extended, 1, has_include, 1,
  172. NULL);
  173. }
  174. /** Same as config_get_lines_include but does not allow %include */
  175. int
  176. config_get_lines(const char *string, config_line_t **result, int extended)
  177. {
  178. return config_get_lines_aux(string, result, extended, 0, NULL, 1, NULL);
  179. }
  180. /** Adds a list of configuration files present on <b>path</b> to
  181. * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file,
  182. * only that file will be added to <b>file_list</b>. If it is a directory,
  183. * all paths for files on that directory root (no recursion) except for files
  184. * whose name starts with a dot will be added to <b>file_list</b>.
  185. * Return 0 on success, -1 on failure. Ignores empty files.
  186. */
  187. static smartlist_t *
  188. config_get_file_list(const char *path)
  189. {
  190. smartlist_t *file_list = smartlist_new();
  191. file_status_t file_type = file_status(path);
  192. if (file_type == FN_FILE) {
  193. smartlist_add_strdup(file_list, path);
  194. return file_list;
  195. } else if (file_type == FN_DIR) {
  196. smartlist_t *all_files = tor_listdir(path);
  197. if (!all_files) {
  198. smartlist_free(file_list);
  199. return NULL;
  200. }
  201. smartlist_sort_strings(all_files);
  202. SMARTLIST_FOREACH_BEGIN(all_files, char *, f) {
  203. if (f[0] == '.') {
  204. tor_free(f);
  205. continue;
  206. }
  207. char *fullname;
  208. tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f);
  209. tor_free(f);
  210. if (file_status(fullname) != FN_FILE) {
  211. tor_free(fullname);
  212. continue;
  213. }
  214. smartlist_add(file_list, fullname);
  215. } SMARTLIST_FOREACH_END(f);
  216. smartlist_free(all_files);
  217. return file_list;
  218. } else if (file_type == FN_EMPTY) {
  219. return file_list;
  220. } else {
  221. smartlist_free(file_list);
  222. return NULL;
  223. }
  224. }
  225. /** Creates a list of config lines present on included <b>path</b>.
  226. * Set <b>list</b> to the list and <b>list_last</b> to the last element of
  227. * <b>list</b>. Return 0 on success, -1 on failure. */
  228. static int
  229. config_get_included_list(const char *path, int recursion_level, int extended,
  230. config_line_t **list, config_line_t **list_last)
  231. {
  232. char *included_conf = read_file_to_str(path, 0, NULL);
  233. if (!included_conf) {
  234. return -1;
  235. }
  236. if (config_get_lines_aux(included_conf, list, extended, 1, NULL,
  237. recursion_level+1, list_last) < 0) {
  238. tor_free(included_conf);
  239. return -1;
  240. }
  241. tor_free(included_conf);
  242. return 0;
  243. }
  244. /** Process an %include <b>path</b> in a config file. Set <b>list</b> to the
  245. * list of configuration settings obtained and <b>list_last</b> to the last
  246. * element of the same list. Return 0 on success, -1 on failure. */
  247. static int
  248. config_process_include(const char *path, int recursion_level, int extended,
  249. config_line_t **list, config_line_t **list_last)
  250. {
  251. config_line_t *ret_list = NULL;
  252. config_line_t **next = &ret_list;
  253. #if 0
  254. // Disabled -- we already unescape_string() on the result. */
  255. char *unquoted_path = get_unquoted_path(path);
  256. if (!unquoted_path) {
  257. return -1;
  258. }
  259. smartlist_t *config_files = config_get_file_list(unquoted_path);
  260. if (!config_files) {
  261. tor_free(unquoted_path);
  262. return -1;
  263. }
  264. tor_free(unquoted_path);
  265. #endif /* 0 */
  266. smartlist_t *config_files = config_get_file_list(path);
  267. if (!config_files) {
  268. return -1;
  269. }
  270. int rv = -1;
  271. SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) {
  272. config_line_t *included_list = NULL;
  273. if (config_get_included_list(config_file, recursion_level, extended,
  274. &included_list, list_last) < 0) {
  275. goto done;
  276. }
  277. *next = included_list;
  278. if (*list_last)
  279. next = &(*list_last)->next;
  280. } SMARTLIST_FOREACH_END(config_file);
  281. *list = ret_list;
  282. rv = 0;
  283. done:
  284. SMARTLIST_FOREACH(config_files, char *, f, tor_free(f));
  285. smartlist_free(config_files);
  286. return rv;
  287. }
  288. /**
  289. * Free all the configuration lines on the linked list <b>front</b>.
  290. */
  291. void
  292. config_free_lines(config_line_t *front)
  293. {
  294. config_line_t *tmp;
  295. while (front) {
  296. tmp = front;
  297. front = tmp->next;
  298. tor_free(tmp->key);
  299. tor_free(tmp->value);
  300. tor_free(tmp);
  301. }
  302. }
  303. /** Return a newly allocated deep copy of the lines in <b>inp</b>. */
  304. config_line_t *
  305. config_lines_dup(const config_line_t *inp)
  306. {
  307. return config_lines_dup_and_filter(inp, NULL);
  308. }
  309. /** Return a newly allocated deep copy of the lines in <b>inp</b>,
  310. * but only the ones whose keys begin with <b>key</b> (case-insensitive).
  311. * If <b>key</b> is NULL, do not filter. */
  312. config_line_t *
  313. config_lines_dup_and_filter(const config_line_t *inp,
  314. const char *key)
  315. {
  316. config_line_t *result = NULL;
  317. config_line_t **next_out = &result;
  318. while (inp) {
  319. if (key && strcasecmpstart(inp->key, key)) {
  320. inp = inp->next;
  321. continue;
  322. }
  323. *next_out = tor_malloc_zero(sizeof(config_line_t));
  324. (*next_out)->key = tor_strdup(inp->key);
  325. (*next_out)->value = tor_strdup(inp->value);
  326. inp = inp->next;
  327. next_out = &((*next_out)->next);
  328. }
  329. (*next_out) = NULL;
  330. return result;
  331. }
  332. /** Return true iff a and b contain identical keys and values in identical
  333. * order. */
  334. int
  335. config_lines_eq(config_line_t *a, config_line_t *b)
  336. {
  337. while (a && b) {
  338. if (strcasecmp(a->key, b->key) || strcmp(a->value, b->value))
  339. return 0;
  340. a = a->next;
  341. b = b->next;
  342. }
  343. if (a || b)
  344. return 0;
  345. return 1;
  346. }
  347. /** Return the number of lines in <b>a</b> whose key is <b>key</b>. */
  348. int
  349. config_count_key(const config_line_t *a, const char *key)
  350. {
  351. int n = 0;
  352. while (a) {
  353. if (!strcasecmp(a->key, key)) {
  354. ++n;
  355. }
  356. a = a->next;
  357. }
  358. return n;
  359. }
  360. /** Given a string containing part of a configuration file or similar format,
  361. * advance past comments and whitespace and try to parse a single line. If we
  362. * parse a line successfully, set *<b>key_out</b> to a new string holding the
  363. * key portion and *<b>value_out</b> to a new string holding the value portion
  364. * of the line, and return a pointer to the start of the next line. If we run
  365. * out of data, return a pointer to the end of the string. If we encounter an
  366. * error, return NULL and set *<b>err_out</b> (if provided) to an error
  367. * message.
  368. */
  369. const char *
  370. parse_config_line_from_str_verbose(const char *line, char **key_out,
  371. char **value_out,
  372. const char **err_out)
  373. {
  374. /*
  375. See torrc_format.txt for a description of the (silly) format this parses.
  376. */
  377. const char *key, *val, *cp;
  378. int continuation = 0;
  379. tor_assert(key_out);
  380. tor_assert(value_out);
  381. *key_out = *value_out = NULL;
  382. key = val = NULL;
  383. /* Skip until the first keyword. */
  384. while (1) {
  385. while (TOR_ISSPACE(*line))
  386. ++line;
  387. if (*line == '#') {
  388. while (*line && *line != '\n')
  389. ++line;
  390. } else {
  391. break;
  392. }
  393. }
  394. if (!*line) { /* End of string? */
  395. *key_out = *value_out = NULL;
  396. return line;
  397. }
  398. /* Skip until the next space or \ followed by newline. */
  399. key = line;
  400. while (*line && !TOR_ISSPACE(*line) && *line != '#' &&
  401. ! (line[0] == '\\' && line[1] == '\n'))
  402. ++line;
  403. *key_out = tor_strndup(key, line-key);
  404. /* Skip until the value. */
  405. while (*line == ' ' || *line == '\t')
  406. ++line;
  407. val = line;
  408. /* Find the end of the line. */
  409. if (*line == '\"') { // XXX No continuation handling is done here
  410. if (!(line = unescape_string(line, value_out, NULL))) {
  411. if (err_out)
  412. *err_out = "Invalid escape sequence in quoted string";
  413. return NULL;
  414. }
  415. while (*line == ' ' || *line == '\t')
  416. ++line;
  417. if (*line == '\r' && *(++line) == '\n')
  418. ++line;
  419. if (*line && *line != '#' && *line != '\n') {
  420. if (err_out)
  421. *err_out = "Excess data after quoted string";
  422. return NULL;
  423. }
  424. } else {
  425. /* Look for the end of the line. */
  426. while (*line && *line != '\n' && (*line != '#' || continuation)) {
  427. if (*line == '\\' && line[1] == '\n') {
  428. continuation = 1;
  429. line += 2;
  430. } else if (*line == '#') {
  431. do {
  432. ++line;
  433. } while (*line && *line != '\n');
  434. if (*line == '\n')
  435. ++line;
  436. } else {
  437. ++line;
  438. }
  439. }
  440. if (*line == '\n') {
  441. cp = line++;
  442. } else {
  443. cp = line;
  444. }
  445. /* Now back cp up to be the last nonspace character */
  446. while (cp>val && TOR_ISSPACE(*(cp-1)))
  447. --cp;
  448. tor_assert(cp >= val);
  449. /* Now copy out and decode the value. */
  450. *value_out = tor_strndup(val, cp-val);
  451. if (continuation) {
  452. char *v_out, *v_in;
  453. v_out = v_in = *value_out;
  454. while (*v_in) {
  455. if (*v_in == '#') {
  456. do {
  457. ++v_in;
  458. } while (*v_in && *v_in != '\n');
  459. if (*v_in == '\n')
  460. ++v_in;
  461. } else if (v_in[0] == '\\' && v_in[1] == '\n') {
  462. v_in += 2;
  463. } else {
  464. *v_out++ = *v_in++;
  465. }
  466. }
  467. *v_out = '\0';
  468. }
  469. }
  470. if (*line == '#') {
  471. do {
  472. ++line;
  473. } while (*line && *line != '\n');
  474. }
  475. while (TOR_ISSPACE(*line)) ++line;
  476. return line;
  477. }