PageRenderTime 64ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/contrib/bind9/lib/isccfg/parser.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2477 lines | 2199 code | 202 blank | 76 comment | 267 complexity | 65d7ffeb7b54f4c36192aab7889403d0 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, LGPL-2.0, LGPL-2.1, BSD-2-Clause, 0BSD, JSON, AGPL-1.0, GPL-2.0
  1. /*
  2. * Copyright (C) 2004-2012 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 2000-2003 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id$ */
  18. /*! \file */
  19. #include <config.h>
  20. #include <isc/buffer.h>
  21. #include <isc/dir.h>
  22. #include <isc/formatcheck.h>
  23. #include <isc/lex.h>
  24. #include <isc/log.h>
  25. #include <isc/mem.h>
  26. #include <isc/net.h>
  27. #include <isc/netaddr.h>
  28. #include <isc/netscope.h>
  29. #include <isc/print.h>
  30. #include <isc/string.h>
  31. #include <isc/sockaddr.h>
  32. #include <isc/symtab.h>
  33. #include <isc/util.h>
  34. #include <isccfg/cfg.h>
  35. #include <isccfg/grammar.h>
  36. #include <isccfg/log.h>
  37. /* Shorthand */
  38. #define CAT CFG_LOGCATEGORY_CONFIG
  39. #define MOD CFG_LOGMODULE_PARSER
  40. #define MAP_SYM 1 /* Unique type for isc_symtab */
  41. #define TOKEN_STRING(pctx) (pctx->token.value.as_textregion.base)
  42. /* Check a return value. */
  43. #define CHECK(op) \
  44. do { result = (op); \
  45. if (result != ISC_R_SUCCESS) goto cleanup; \
  46. } while (0)
  47. /* Clean up a configuration object if non-NULL. */
  48. #define CLEANUP_OBJ(obj) \
  49. do { if ((obj) != NULL) cfg_obj_destroy(pctx, &(obj)); } while (0)
  50. /*
  51. * Forward declarations of static functions.
  52. */
  53. static void
  54. free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj);
  55. static isc_result_t
  56. parse_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret);
  57. static void
  58. print_list(cfg_printer_t *pctx, const cfg_obj_t *obj);
  59. static void
  60. free_list(cfg_parser_t *pctx, cfg_obj_t *obj);
  61. static isc_result_t
  62. create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp);
  63. static isc_result_t
  64. create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
  65. cfg_obj_t **ret);
  66. static void
  67. free_string(cfg_parser_t *pctx, cfg_obj_t *obj);
  68. static isc_result_t
  69. create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **objp);
  70. static void
  71. free_map(cfg_parser_t *pctx, cfg_obj_t *obj);
  72. static isc_result_t
  73. parse_symtab_elt(cfg_parser_t *pctx, const char *name,
  74. cfg_type_t *elttype, isc_symtab_t *symtab,
  75. isc_boolean_t callback);
  76. static void
  77. free_noop(cfg_parser_t *pctx, cfg_obj_t *obj);
  78. static isc_result_t
  79. cfg_getstringtoken(cfg_parser_t *pctx);
  80. static void
  81. parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
  82. unsigned int flags, const char *format, va_list args);
  83. /*
  84. * Data representations. These correspond to members of the
  85. * "value" union in struct cfg_obj (except "void", which does
  86. * not need a union member).
  87. */
  88. cfg_rep_t cfg_rep_uint32 = { "uint32", free_noop };
  89. cfg_rep_t cfg_rep_uint64 = { "uint64", free_noop };
  90. cfg_rep_t cfg_rep_string = { "string", free_string };
  91. cfg_rep_t cfg_rep_boolean = { "boolean", free_noop };
  92. cfg_rep_t cfg_rep_map = { "map", free_map };
  93. cfg_rep_t cfg_rep_list = { "list", free_list };
  94. cfg_rep_t cfg_rep_tuple = { "tuple", free_tuple };
  95. cfg_rep_t cfg_rep_sockaddr = { "sockaddr", free_noop };
  96. cfg_rep_t cfg_rep_netprefix = { "netprefix", free_noop };
  97. cfg_rep_t cfg_rep_void = { "void", free_noop };
  98. /*
  99. * Configuration type definitions.
  100. */
  101. /*%
  102. * An implicit list. These are formed by clauses that occur multiple times.
  103. */
  104. static cfg_type_t cfg_type_implicitlist = {
  105. "implicitlist", NULL, print_list, NULL, &cfg_rep_list, NULL };
  106. /* Functions. */
  107. void
  108. cfg_print_obj(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  109. obj->type->print(pctx, obj);
  110. }
  111. void
  112. cfg_print_chars(cfg_printer_t *pctx, const char *text, int len) {
  113. pctx->f(pctx->closure, text, len);
  114. }
  115. static void
  116. print_open(cfg_printer_t *pctx) {
  117. cfg_print_chars(pctx, "{\n", 2);
  118. pctx->indent++;
  119. }
  120. static void
  121. print_indent(cfg_printer_t *pctx) {
  122. int indent = pctx->indent;
  123. while (indent > 0) {
  124. cfg_print_chars(pctx, "\t", 1);
  125. indent--;
  126. }
  127. }
  128. static void
  129. print_close(cfg_printer_t *pctx) {
  130. pctx->indent--;
  131. print_indent(pctx);
  132. cfg_print_chars(pctx, "}", 1);
  133. }
  134. isc_result_t
  135. cfg_parse_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  136. isc_result_t result;
  137. INSIST(ret != NULL && *ret == NULL);
  138. result = type->parse(pctx, type, ret);
  139. if (result != ISC_R_SUCCESS)
  140. return (result);
  141. INSIST(*ret != NULL);
  142. return (ISC_R_SUCCESS);
  143. }
  144. void
  145. cfg_print(const cfg_obj_t *obj,
  146. void (*f)(void *closure, const char *text, int textlen),
  147. void *closure)
  148. {
  149. cfg_printer_t pctx;
  150. pctx.f = f;
  151. pctx.closure = closure;
  152. pctx.indent = 0;
  153. obj->type->print(&pctx, obj);
  154. }
  155. /* Tuples. */
  156. isc_result_t
  157. cfg_create_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  158. isc_result_t result;
  159. const cfg_tuplefielddef_t *fields = type->of;
  160. const cfg_tuplefielddef_t *f;
  161. cfg_obj_t *obj = NULL;
  162. unsigned int nfields = 0;
  163. int i;
  164. for (f = fields; f->name != NULL; f++)
  165. nfields++;
  166. CHECK(cfg_create_obj(pctx, type, &obj));
  167. obj->value.tuple = isc_mem_get(pctx->mctx,
  168. nfields * sizeof(cfg_obj_t *));
  169. if (obj->value.tuple == NULL) {
  170. result = ISC_R_NOMEMORY;
  171. goto cleanup;
  172. }
  173. for (f = fields, i = 0; f->name != NULL; f++, i++)
  174. obj->value.tuple[i] = NULL;
  175. *ret = obj;
  176. return (ISC_R_SUCCESS);
  177. cleanup:
  178. if (obj != NULL)
  179. isc_mem_put(pctx->mctx, obj, sizeof(*obj));
  180. return (result);
  181. }
  182. isc_result_t
  183. cfg_parse_tuple(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
  184. {
  185. isc_result_t result;
  186. const cfg_tuplefielddef_t *fields = type->of;
  187. const cfg_tuplefielddef_t *f;
  188. cfg_obj_t *obj = NULL;
  189. unsigned int i;
  190. CHECK(cfg_create_tuple(pctx, type, &obj));
  191. for (f = fields, i = 0; f->name != NULL; f++, i++)
  192. CHECK(cfg_parse_obj(pctx, f->type, &obj->value.tuple[i]));
  193. *ret = obj;
  194. return (ISC_R_SUCCESS);
  195. cleanup:
  196. CLEANUP_OBJ(obj);
  197. return (result);
  198. }
  199. void
  200. cfg_print_tuple(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  201. unsigned int i;
  202. const cfg_tuplefielddef_t *fields = obj->type->of;
  203. const cfg_tuplefielddef_t *f;
  204. isc_boolean_t need_space = ISC_FALSE;
  205. for (f = fields, i = 0; f->name != NULL; f++, i++) {
  206. const cfg_obj_t *fieldobj = obj->value.tuple[i];
  207. if (need_space)
  208. cfg_print_chars(pctx, " ", 1);
  209. cfg_print_obj(pctx, fieldobj);
  210. need_space = ISC_TF(fieldobj->type->print != cfg_print_void);
  211. }
  212. }
  213. void
  214. cfg_doc_tuple(cfg_printer_t *pctx, const cfg_type_t *type) {
  215. const cfg_tuplefielddef_t *fields = type->of;
  216. const cfg_tuplefielddef_t *f;
  217. isc_boolean_t need_space = ISC_FALSE;
  218. for (f = fields; f->name != NULL; f++) {
  219. if (need_space)
  220. cfg_print_chars(pctx, " ", 1);
  221. cfg_doc_obj(pctx, f->type);
  222. need_space = ISC_TF(f->type->print != cfg_print_void);
  223. }
  224. }
  225. static void
  226. free_tuple(cfg_parser_t *pctx, cfg_obj_t *obj) {
  227. unsigned int i;
  228. const cfg_tuplefielddef_t *fields = obj->type->of;
  229. const cfg_tuplefielddef_t *f;
  230. unsigned int nfields = 0;
  231. if (obj->value.tuple == NULL)
  232. return;
  233. for (f = fields, i = 0; f->name != NULL; f++, i++) {
  234. CLEANUP_OBJ(obj->value.tuple[i]);
  235. nfields++;
  236. }
  237. isc_mem_put(pctx->mctx, obj->value.tuple,
  238. nfields * sizeof(cfg_obj_t *));
  239. }
  240. isc_boolean_t
  241. cfg_obj_istuple(const cfg_obj_t *obj) {
  242. REQUIRE(obj != NULL);
  243. return (ISC_TF(obj->type->rep == &cfg_rep_tuple));
  244. }
  245. const cfg_obj_t *
  246. cfg_tuple_get(const cfg_obj_t *tupleobj, const char* name) {
  247. unsigned int i;
  248. const cfg_tuplefielddef_t *fields;
  249. const cfg_tuplefielddef_t *f;
  250. REQUIRE(tupleobj != NULL && tupleobj->type->rep == &cfg_rep_tuple);
  251. fields = tupleobj->type->of;
  252. for (f = fields, i = 0; f->name != NULL; f++, i++) {
  253. if (strcmp(f->name, name) == 0)
  254. return (tupleobj->value.tuple[i]);
  255. }
  256. INSIST(0);
  257. return (NULL);
  258. }
  259. isc_result_t
  260. cfg_parse_special(cfg_parser_t *pctx, int special) {
  261. isc_result_t result;
  262. CHECK(cfg_gettoken(pctx, 0));
  263. if (pctx->token.type == isc_tokentype_special &&
  264. pctx->token.value.as_char == special)
  265. return (ISC_R_SUCCESS);
  266. cfg_parser_error(pctx, CFG_LOG_NEAR, "'%c' expected", special);
  267. return (ISC_R_UNEXPECTEDTOKEN);
  268. cleanup:
  269. return (result);
  270. }
  271. /*
  272. * Parse a required semicolon. If it is not there, log
  273. * an error and increment the error count but continue
  274. * parsing. Since the next token is pushed back,
  275. * care must be taken to make sure it is eventually
  276. * consumed or an infinite loop may result.
  277. */
  278. static isc_result_t
  279. parse_semicolon(cfg_parser_t *pctx) {
  280. isc_result_t result;
  281. CHECK(cfg_gettoken(pctx, 0));
  282. if (pctx->token.type == isc_tokentype_special &&
  283. pctx->token.value.as_char == ';')
  284. return (ISC_R_SUCCESS);
  285. cfg_parser_error(pctx, CFG_LOG_BEFORE, "missing ';'");
  286. cfg_ungettoken(pctx);
  287. cleanup:
  288. return (result);
  289. }
  290. /*
  291. * Parse EOF, logging and returning an error if not there.
  292. */
  293. static isc_result_t
  294. parse_eof(cfg_parser_t *pctx) {
  295. isc_result_t result;
  296. CHECK(cfg_gettoken(pctx, 0));
  297. if (pctx->token.type == isc_tokentype_eof)
  298. return (ISC_R_SUCCESS);
  299. cfg_parser_error(pctx, CFG_LOG_NEAR, "syntax error");
  300. return (ISC_R_UNEXPECTEDTOKEN);
  301. cleanup:
  302. return (result);
  303. }
  304. /* A list of files, used internally for pctx->files. */
  305. static cfg_type_t cfg_type_filelist = {
  306. "filelist", NULL, print_list, NULL, &cfg_rep_list,
  307. &cfg_type_qstring
  308. };
  309. isc_result_t
  310. cfg_parser_create(isc_mem_t *mctx, isc_log_t *lctx, cfg_parser_t **ret) {
  311. isc_result_t result;
  312. cfg_parser_t *pctx;
  313. isc_lexspecials_t specials;
  314. REQUIRE(mctx != NULL);
  315. REQUIRE(ret != NULL && *ret == NULL);
  316. pctx = isc_mem_get(mctx, sizeof(*pctx));
  317. if (pctx == NULL)
  318. return (ISC_R_NOMEMORY);
  319. result = isc_refcount_init(&pctx->references, 1);
  320. if (result != ISC_R_SUCCESS) {
  321. isc_mem_put(mctx, pctx, sizeof(*pctx));
  322. return (result);
  323. }
  324. pctx->mctx = mctx;
  325. pctx->lctx = lctx;
  326. pctx->lexer = NULL;
  327. pctx->seen_eof = ISC_FALSE;
  328. pctx->ungotten = ISC_FALSE;
  329. pctx->errors = 0;
  330. pctx->warnings = 0;
  331. pctx->open_files = NULL;
  332. pctx->closed_files = NULL;
  333. pctx->line = 0;
  334. pctx->callback = NULL;
  335. pctx->callbackarg = NULL;
  336. pctx->token.type = isc_tokentype_unknown;
  337. pctx->flags = 0;
  338. memset(specials, 0, sizeof(specials));
  339. specials['{'] = 1;
  340. specials['}'] = 1;
  341. specials[';'] = 1;
  342. specials['/'] = 1;
  343. specials['"'] = 1;
  344. specials['!'] = 1;
  345. CHECK(isc_lex_create(pctx->mctx, 1024, &pctx->lexer));
  346. isc_lex_setspecials(pctx->lexer, specials);
  347. isc_lex_setcomments(pctx->lexer, (ISC_LEXCOMMENT_C |
  348. ISC_LEXCOMMENT_CPLUSPLUS |
  349. ISC_LEXCOMMENT_SHELL));
  350. CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->open_files));
  351. CHECK(cfg_create_list(pctx, &cfg_type_filelist, &pctx->closed_files));
  352. *ret = pctx;
  353. return (ISC_R_SUCCESS);
  354. cleanup:
  355. if (pctx->lexer != NULL)
  356. isc_lex_destroy(&pctx->lexer);
  357. CLEANUP_OBJ(pctx->open_files);
  358. CLEANUP_OBJ(pctx->closed_files);
  359. isc_mem_put(mctx, pctx, sizeof(*pctx));
  360. return (result);
  361. }
  362. static isc_result_t
  363. parser_openfile(cfg_parser_t *pctx, const char *filename) {
  364. isc_result_t result;
  365. cfg_listelt_t *elt = NULL;
  366. cfg_obj_t *stringobj = NULL;
  367. result = isc_lex_openfile(pctx->lexer, filename);
  368. if (result != ISC_R_SUCCESS) {
  369. cfg_parser_error(pctx, 0, "open: %s: %s",
  370. filename, isc_result_totext(result));
  371. goto cleanup;
  372. }
  373. CHECK(create_string(pctx, filename, &cfg_type_qstring, &stringobj));
  374. CHECK(create_listelt(pctx, &elt));
  375. elt->obj = stringobj;
  376. ISC_LIST_APPEND(pctx->open_files->value.list, elt, link);
  377. return (ISC_R_SUCCESS);
  378. cleanup:
  379. CLEANUP_OBJ(stringobj);
  380. return (result);
  381. }
  382. void
  383. cfg_parser_setcallback(cfg_parser_t *pctx,
  384. cfg_parsecallback_t callback,
  385. void *arg)
  386. {
  387. pctx->callback = callback;
  388. pctx->callbackarg = arg;
  389. }
  390. /*
  391. * Parse a configuration using a pctx where a lexer has already
  392. * been set up with a source.
  393. */
  394. static isc_result_t
  395. parse2(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  396. isc_result_t result;
  397. cfg_obj_t *obj = NULL;
  398. result = cfg_parse_obj(pctx, type, &obj);
  399. if (pctx->errors != 0) {
  400. /* Errors have been logged. */
  401. if (result == ISC_R_SUCCESS)
  402. result = ISC_R_FAILURE;
  403. goto cleanup;
  404. }
  405. if (result != ISC_R_SUCCESS) {
  406. /* Parsing failed but no errors have been logged. */
  407. cfg_parser_error(pctx, 0, "parsing failed");
  408. goto cleanup;
  409. }
  410. CHECK(parse_eof(pctx));
  411. *ret = obj;
  412. return (ISC_R_SUCCESS);
  413. cleanup:
  414. CLEANUP_OBJ(obj);
  415. return (result);
  416. }
  417. isc_result_t
  418. cfg_parse_file(cfg_parser_t *pctx, const char *filename,
  419. const cfg_type_t *type, cfg_obj_t **ret)
  420. {
  421. isc_result_t result;
  422. REQUIRE(filename != NULL);
  423. CHECK(parser_openfile(pctx, filename));
  424. CHECK(parse2(pctx, type, ret));
  425. cleanup:
  426. return (result);
  427. }
  428. isc_result_t
  429. cfg_parse_buffer(cfg_parser_t *pctx, isc_buffer_t *buffer,
  430. const cfg_type_t *type, cfg_obj_t **ret)
  431. {
  432. isc_result_t result;
  433. REQUIRE(buffer != NULL);
  434. CHECK(isc_lex_openbuffer(pctx->lexer, buffer));
  435. CHECK(parse2(pctx, type, ret));
  436. cleanup:
  437. return (result);
  438. }
  439. void
  440. cfg_parser_attach(cfg_parser_t *src, cfg_parser_t **dest) {
  441. REQUIRE(src != NULL);
  442. REQUIRE(dest != NULL && *dest == NULL);
  443. isc_refcount_increment(&src->references, NULL);
  444. *dest = src;
  445. }
  446. void
  447. cfg_parser_destroy(cfg_parser_t **pctxp) {
  448. cfg_parser_t *pctx = *pctxp;
  449. unsigned int refs;
  450. isc_refcount_decrement(&pctx->references, &refs);
  451. if (refs == 0) {
  452. isc_lex_destroy(&pctx->lexer);
  453. /*
  454. * Cleaning up open_files does not
  455. * close the files; that was already done
  456. * by closing the lexer.
  457. */
  458. CLEANUP_OBJ(pctx->open_files);
  459. CLEANUP_OBJ(pctx->closed_files);
  460. isc_mem_put(pctx->mctx, pctx, sizeof(*pctx));
  461. }
  462. *pctxp = NULL;
  463. }
  464. /*
  465. * void
  466. */
  467. isc_result_t
  468. cfg_parse_void(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  469. UNUSED(type);
  470. return (cfg_create_obj(pctx, &cfg_type_void, ret));
  471. }
  472. void
  473. cfg_print_void(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  474. UNUSED(pctx);
  475. UNUSED(obj);
  476. }
  477. void
  478. cfg_doc_void(cfg_printer_t *pctx, const cfg_type_t *type) {
  479. UNUSED(pctx);
  480. UNUSED(type);
  481. }
  482. isc_boolean_t
  483. cfg_obj_isvoid(const cfg_obj_t *obj) {
  484. REQUIRE(obj != NULL);
  485. return (ISC_TF(obj->type->rep == &cfg_rep_void));
  486. }
  487. cfg_type_t cfg_type_void = {
  488. "void", cfg_parse_void, cfg_print_void, cfg_doc_void, &cfg_rep_void,
  489. NULL };
  490. /*
  491. * uint32
  492. */
  493. isc_result_t
  494. cfg_parse_uint32(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  495. isc_result_t result;
  496. cfg_obj_t *obj = NULL;
  497. UNUSED(type);
  498. CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER | ISC_LEXOPT_CNUMBER));
  499. if (pctx->token.type != isc_tokentype_number) {
  500. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected number");
  501. return (ISC_R_UNEXPECTEDTOKEN);
  502. }
  503. CHECK(cfg_create_obj(pctx, &cfg_type_uint32, &obj));
  504. obj->value.uint32 = pctx->token.value.as_ulong;
  505. *ret = obj;
  506. cleanup:
  507. return (result);
  508. }
  509. void
  510. cfg_print_cstr(cfg_printer_t *pctx, const char *s) {
  511. cfg_print_chars(pctx, s, strlen(s));
  512. }
  513. void
  514. cfg_print_rawuint(cfg_printer_t *pctx, unsigned int u) {
  515. char buf[32];
  516. snprintf(buf, sizeof(buf), "%u", u);
  517. cfg_print_cstr(pctx, buf);
  518. }
  519. void
  520. cfg_print_uint32(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  521. cfg_print_rawuint(pctx, obj->value.uint32);
  522. }
  523. isc_boolean_t
  524. cfg_obj_isuint32(const cfg_obj_t *obj) {
  525. REQUIRE(obj != NULL);
  526. return (ISC_TF(obj->type->rep == &cfg_rep_uint32));
  527. }
  528. isc_uint32_t
  529. cfg_obj_asuint32(const cfg_obj_t *obj) {
  530. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint32);
  531. return (obj->value.uint32);
  532. }
  533. cfg_type_t cfg_type_uint32 = {
  534. "integer", cfg_parse_uint32, cfg_print_uint32, cfg_doc_terminal,
  535. &cfg_rep_uint32, NULL
  536. };
  537. /*
  538. * uint64
  539. */
  540. isc_boolean_t
  541. cfg_obj_isuint64(const cfg_obj_t *obj) {
  542. REQUIRE(obj != NULL);
  543. return (ISC_TF(obj->type->rep == &cfg_rep_uint64));
  544. }
  545. isc_uint64_t
  546. cfg_obj_asuint64(const cfg_obj_t *obj) {
  547. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_uint64);
  548. return (obj->value.uint64);
  549. }
  550. void
  551. cfg_print_uint64(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  552. char buf[32];
  553. snprintf(buf, sizeof(buf), "%" ISC_PRINT_QUADFORMAT "u",
  554. obj->value.uint64);
  555. cfg_print_cstr(pctx, buf);
  556. }
  557. cfg_type_t cfg_type_uint64 = {
  558. "64_bit_integer", NULL, cfg_print_uint64, cfg_doc_terminal,
  559. &cfg_rep_uint64, NULL
  560. };
  561. /*
  562. * qstring (quoted string), ustring (unquoted string), astring
  563. * (any string)
  564. */
  565. /* Create a string object from a null-terminated C string. */
  566. static isc_result_t
  567. create_string(cfg_parser_t *pctx, const char *contents, const cfg_type_t *type,
  568. cfg_obj_t **ret)
  569. {
  570. isc_result_t result;
  571. cfg_obj_t *obj = NULL;
  572. int len;
  573. CHECK(cfg_create_obj(pctx, type, &obj));
  574. len = strlen(contents);
  575. obj->value.string.length = len;
  576. obj->value.string.base = isc_mem_get(pctx->mctx, len + 1);
  577. if (obj->value.string.base == 0) {
  578. isc_mem_put(pctx->mctx, obj, sizeof(*obj));
  579. return (ISC_R_NOMEMORY);
  580. }
  581. memcpy(obj->value.string.base, contents, len);
  582. obj->value.string.base[len] = '\0';
  583. *ret = obj;
  584. cleanup:
  585. return (result);
  586. }
  587. isc_result_t
  588. cfg_parse_qstring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  589. isc_result_t result;
  590. UNUSED(type);
  591. CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
  592. if (pctx->token.type != isc_tokentype_qstring) {
  593. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected quoted string");
  594. return (ISC_R_UNEXPECTEDTOKEN);
  595. }
  596. return (create_string(pctx,
  597. TOKEN_STRING(pctx),
  598. &cfg_type_qstring,
  599. ret));
  600. cleanup:
  601. return (result);
  602. }
  603. static isc_result_t
  604. parse_ustring(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  605. isc_result_t result;
  606. UNUSED(type);
  607. CHECK(cfg_gettoken(pctx, 0));
  608. if (pctx->token.type != isc_tokentype_string) {
  609. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected unquoted string");
  610. return (ISC_R_UNEXPECTEDTOKEN);
  611. }
  612. return (create_string(pctx,
  613. TOKEN_STRING(pctx),
  614. &cfg_type_ustring,
  615. ret));
  616. cleanup:
  617. return (result);
  618. }
  619. isc_result_t
  620. cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type,
  621. cfg_obj_t **ret)
  622. {
  623. isc_result_t result;
  624. UNUSED(type);
  625. CHECK(cfg_getstringtoken(pctx));
  626. return (create_string(pctx,
  627. TOKEN_STRING(pctx),
  628. &cfg_type_qstring,
  629. ret));
  630. cleanup:
  631. return (result);
  632. }
  633. isc_boolean_t
  634. cfg_is_enum(const char *s, const char *const *enums) {
  635. const char * const *p;
  636. for (p = enums; *p != NULL; p++) {
  637. if (strcasecmp(*p, s) == 0)
  638. return (ISC_TRUE);
  639. }
  640. return (ISC_FALSE);
  641. }
  642. static isc_result_t
  643. check_enum(cfg_parser_t *pctx, cfg_obj_t *obj, const char *const *enums) {
  644. const char *s = obj->value.string.base;
  645. if (cfg_is_enum(s, enums))
  646. return (ISC_R_SUCCESS);
  647. cfg_parser_error(pctx, 0, "'%s' unexpected", s);
  648. return (ISC_R_UNEXPECTEDTOKEN);
  649. }
  650. isc_result_t
  651. cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  652. isc_result_t result;
  653. cfg_obj_t *obj = NULL;
  654. CHECK(parse_ustring(pctx, NULL, &obj));
  655. CHECK(check_enum(pctx, obj, type->of));
  656. *ret = obj;
  657. return (ISC_R_SUCCESS);
  658. cleanup:
  659. CLEANUP_OBJ(obj);
  660. return (result);
  661. }
  662. void
  663. cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) {
  664. const char * const *p;
  665. cfg_print_chars(pctx, "( ", 2);
  666. for (p = type->of; *p != NULL; p++) {
  667. cfg_print_cstr(pctx, *p);
  668. if (p[1] != NULL)
  669. cfg_print_chars(pctx, " | ", 3);
  670. }
  671. cfg_print_chars(pctx, " )", 2);
  672. }
  673. void
  674. cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  675. cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length);
  676. }
  677. static void
  678. print_qstring(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  679. cfg_print_chars(pctx, "\"", 1);
  680. cfg_print_ustring(pctx, obj);
  681. cfg_print_chars(pctx, "\"", 1);
  682. }
  683. static void
  684. free_string(cfg_parser_t *pctx, cfg_obj_t *obj) {
  685. isc_mem_put(pctx->mctx, obj->value.string.base,
  686. obj->value.string.length + 1);
  687. }
  688. isc_boolean_t
  689. cfg_obj_isstring(const cfg_obj_t *obj) {
  690. REQUIRE(obj != NULL);
  691. return (ISC_TF(obj->type->rep == &cfg_rep_string));
  692. }
  693. const char *
  694. cfg_obj_asstring(const cfg_obj_t *obj) {
  695. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_string);
  696. return (obj->value.string.base);
  697. }
  698. /* Quoted string only */
  699. cfg_type_t cfg_type_qstring = {
  700. "quoted_string", cfg_parse_qstring, print_qstring, cfg_doc_terminal,
  701. &cfg_rep_string, NULL
  702. };
  703. /* Unquoted string only */
  704. cfg_type_t cfg_type_ustring = {
  705. "string", parse_ustring, cfg_print_ustring, cfg_doc_terminal,
  706. &cfg_rep_string, NULL
  707. };
  708. /* Any string (quoted or unquoted); printed with quotes */
  709. cfg_type_t cfg_type_astring = {
  710. "string", cfg_parse_astring, print_qstring, cfg_doc_terminal,
  711. &cfg_rep_string, NULL
  712. };
  713. /*
  714. * Booleans
  715. */
  716. isc_boolean_t
  717. cfg_obj_isboolean(const cfg_obj_t *obj) {
  718. REQUIRE(obj != NULL);
  719. return (ISC_TF(obj->type->rep == &cfg_rep_boolean));
  720. }
  721. isc_boolean_t
  722. cfg_obj_asboolean(const cfg_obj_t *obj) {
  723. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_boolean);
  724. return (obj->value.boolean);
  725. }
  726. isc_result_t
  727. cfg_parse_boolean(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
  728. {
  729. isc_result_t result;
  730. isc_boolean_t value;
  731. cfg_obj_t *obj = NULL;
  732. UNUSED(type);
  733. result = cfg_gettoken(pctx, 0);
  734. if (result != ISC_R_SUCCESS)
  735. return (result);
  736. if (pctx->token.type != isc_tokentype_string)
  737. goto bad_boolean;
  738. if ((strcasecmp(TOKEN_STRING(pctx), "true") == 0) ||
  739. (strcasecmp(TOKEN_STRING(pctx), "yes") == 0) ||
  740. (strcmp(TOKEN_STRING(pctx), "1") == 0)) {
  741. value = ISC_TRUE;
  742. } else if ((strcasecmp(TOKEN_STRING(pctx), "false") == 0) ||
  743. (strcasecmp(TOKEN_STRING(pctx), "no") == 0) ||
  744. (strcmp(TOKEN_STRING(pctx), "0") == 0)) {
  745. value = ISC_FALSE;
  746. } else {
  747. goto bad_boolean;
  748. }
  749. CHECK(cfg_create_obj(pctx, &cfg_type_boolean, &obj));
  750. obj->value.boolean = value;
  751. *ret = obj;
  752. return (result);
  753. bad_boolean:
  754. cfg_parser_error(pctx, CFG_LOG_NEAR, "boolean expected");
  755. return (ISC_R_UNEXPECTEDTOKEN);
  756. cleanup:
  757. return (result);
  758. }
  759. void
  760. cfg_print_boolean(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  761. if (obj->value.boolean)
  762. cfg_print_chars(pctx, "yes", 3);
  763. else
  764. cfg_print_chars(pctx, "no", 2);
  765. }
  766. cfg_type_t cfg_type_boolean = {
  767. "boolean", cfg_parse_boolean, cfg_print_boolean, cfg_doc_terminal,
  768. &cfg_rep_boolean, NULL
  769. };
  770. /*
  771. * Lists.
  772. */
  773. isc_result_t
  774. cfg_create_list(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **obj) {
  775. isc_result_t result;
  776. CHECK(cfg_create_obj(pctx, type, obj));
  777. ISC_LIST_INIT((*obj)->value.list);
  778. cleanup:
  779. return (result);
  780. }
  781. static isc_result_t
  782. create_listelt(cfg_parser_t *pctx, cfg_listelt_t **eltp) {
  783. cfg_listelt_t *elt;
  784. elt = isc_mem_get(pctx->mctx, sizeof(*elt));
  785. if (elt == NULL)
  786. return (ISC_R_NOMEMORY);
  787. elt->obj = NULL;
  788. ISC_LINK_INIT(elt, link);
  789. *eltp = elt;
  790. return (ISC_R_SUCCESS);
  791. }
  792. static void
  793. free_list_elt(cfg_parser_t *pctx, cfg_listelt_t *elt) {
  794. cfg_obj_destroy(pctx, &elt->obj);
  795. isc_mem_put(pctx->mctx, elt, sizeof(*elt));
  796. }
  797. static void
  798. free_list(cfg_parser_t *pctx, cfg_obj_t *obj) {
  799. cfg_listelt_t *elt, *next;
  800. for (elt = ISC_LIST_HEAD(obj->value.list);
  801. elt != NULL;
  802. elt = next)
  803. {
  804. next = ISC_LIST_NEXT(elt, link);
  805. free_list_elt(pctx, elt);
  806. }
  807. }
  808. isc_result_t
  809. cfg_parse_listelt(cfg_parser_t *pctx, const cfg_type_t *elttype,
  810. cfg_listelt_t **ret)
  811. {
  812. isc_result_t result;
  813. cfg_listelt_t *elt = NULL;
  814. cfg_obj_t *value = NULL;
  815. CHECK(create_listelt(pctx, &elt));
  816. result = cfg_parse_obj(pctx, elttype, &value);
  817. if (result != ISC_R_SUCCESS)
  818. goto cleanup;
  819. elt->obj = value;
  820. *ret = elt;
  821. return (ISC_R_SUCCESS);
  822. cleanup:
  823. isc_mem_put(pctx->mctx, elt, sizeof(*elt));
  824. return (result);
  825. }
  826. /*
  827. * Parse a homogeneous list whose elements are of type 'elttype'
  828. * and where each element is terminated by a semicolon.
  829. */
  830. static isc_result_t
  831. parse_list(cfg_parser_t *pctx, const cfg_type_t *listtype, cfg_obj_t **ret)
  832. {
  833. cfg_obj_t *listobj = NULL;
  834. const cfg_type_t *listof = listtype->of;
  835. isc_result_t result;
  836. cfg_listelt_t *elt = NULL;
  837. CHECK(cfg_create_list(pctx, listtype, &listobj));
  838. for (;;) {
  839. CHECK(cfg_peektoken(pctx, 0));
  840. if (pctx->token.type == isc_tokentype_special &&
  841. pctx->token.value.as_char == /*{*/ '}')
  842. break;
  843. CHECK(cfg_parse_listelt(pctx, listof, &elt));
  844. CHECK(parse_semicolon(pctx));
  845. ISC_LIST_APPEND(listobj->value.list, elt, link);
  846. elt = NULL;
  847. }
  848. *ret = listobj;
  849. return (ISC_R_SUCCESS);
  850. cleanup:
  851. if (elt != NULL)
  852. free_list_elt(pctx, elt);
  853. CLEANUP_OBJ(listobj);
  854. return (result);
  855. }
  856. static void
  857. print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  858. const cfg_list_t *list = &obj->value.list;
  859. const cfg_listelt_t *elt;
  860. for (elt = ISC_LIST_HEAD(*list);
  861. elt != NULL;
  862. elt = ISC_LIST_NEXT(elt, link)) {
  863. print_indent(pctx);
  864. cfg_print_obj(pctx, elt->obj);
  865. cfg_print_chars(pctx, ";\n", 2);
  866. }
  867. }
  868. isc_result_t
  869. cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type,
  870. cfg_obj_t **ret)
  871. {
  872. isc_result_t result;
  873. CHECK(cfg_parse_special(pctx, '{'));
  874. CHECK(parse_list(pctx, type, ret));
  875. CHECK(cfg_parse_special(pctx, '}'));
  876. cleanup:
  877. return (result);
  878. }
  879. void
  880. cfg_print_bracketed_list(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  881. print_open(pctx);
  882. print_list(pctx, obj);
  883. print_close(pctx);
  884. }
  885. void
  886. cfg_doc_bracketed_list(cfg_printer_t *pctx, const cfg_type_t *type) {
  887. cfg_print_chars(pctx, "{ ", 2);
  888. cfg_doc_obj(pctx, type->of);
  889. cfg_print_chars(pctx, "; ... }", 7);
  890. }
  891. /*
  892. * Parse a homogeneous list whose elements are of type 'elttype'
  893. * and where elements are separated by space. The list ends
  894. * before the first semicolon.
  895. */
  896. isc_result_t
  897. cfg_parse_spacelist(cfg_parser_t *pctx, const cfg_type_t *listtype,
  898. cfg_obj_t **ret)
  899. {
  900. cfg_obj_t *listobj = NULL;
  901. const cfg_type_t *listof = listtype->of;
  902. isc_result_t result;
  903. CHECK(cfg_create_list(pctx, listtype, &listobj));
  904. for (;;) {
  905. cfg_listelt_t *elt = NULL;
  906. CHECK(cfg_peektoken(pctx, 0));
  907. if (pctx->token.type == isc_tokentype_special &&
  908. pctx->token.value.as_char == ';')
  909. break;
  910. CHECK(cfg_parse_listelt(pctx, listof, &elt));
  911. ISC_LIST_APPEND(listobj->value.list, elt, link);
  912. }
  913. *ret = listobj;
  914. return (ISC_R_SUCCESS);
  915. cleanup:
  916. CLEANUP_OBJ(listobj);
  917. return (result);
  918. }
  919. void
  920. cfg_print_spacelist(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  921. const cfg_list_t *list = &obj->value.list;
  922. const cfg_listelt_t *elt;
  923. for (elt = ISC_LIST_HEAD(*list);
  924. elt != NULL;
  925. elt = ISC_LIST_NEXT(elt, link)) {
  926. cfg_print_obj(pctx, elt->obj);
  927. if (ISC_LIST_NEXT(elt, link) != NULL)
  928. cfg_print_chars(pctx, " ", 1);
  929. }
  930. }
  931. isc_boolean_t
  932. cfg_obj_islist(const cfg_obj_t *obj) {
  933. REQUIRE(obj != NULL);
  934. return (ISC_TF(obj->type->rep == &cfg_rep_list));
  935. }
  936. const cfg_listelt_t *
  937. cfg_list_first(const cfg_obj_t *obj) {
  938. REQUIRE(obj == NULL || obj->type->rep == &cfg_rep_list);
  939. if (obj == NULL)
  940. return (NULL);
  941. return (ISC_LIST_HEAD(obj->value.list));
  942. }
  943. const cfg_listelt_t *
  944. cfg_list_next(const cfg_listelt_t *elt) {
  945. REQUIRE(elt != NULL);
  946. return (ISC_LIST_NEXT(elt, link));
  947. }
  948. /*
  949. * Return the length of a list object. If obj is NULL or is not
  950. * a list, return 0.
  951. */
  952. unsigned int
  953. cfg_list_length(const cfg_obj_t *obj, isc_boolean_t recurse) {
  954. const cfg_listelt_t *elt;
  955. unsigned int count = 0;
  956. if (obj == NULL || !cfg_obj_islist(obj))
  957. return (0U);
  958. for (elt = cfg_list_first(obj);
  959. elt != NULL;
  960. elt = cfg_list_next(elt)) {
  961. if (recurse && cfg_obj_islist(elt->obj)) {
  962. count += cfg_list_length(elt->obj, recurse);
  963. } else {
  964. count++;
  965. }
  966. }
  967. return (count);
  968. }
  969. cfg_obj_t *
  970. cfg_listelt_value(const cfg_listelt_t *elt) {
  971. REQUIRE(elt != NULL);
  972. return (elt->obj);
  973. }
  974. /*
  975. * Maps.
  976. */
  977. /*
  978. * Parse a map body. That's something like
  979. *
  980. * "foo 1; bar { glub; }; zap true; zap false;"
  981. *
  982. * i.e., a sequence of option names followed by values and
  983. * terminated by semicolons. Used for the top level of
  984. * the named.conf syntax, as well as for the body of the
  985. * options, view, zone, and other statements.
  986. */
  987. isc_result_t
  988. cfg_parse_mapbody(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret)
  989. {
  990. const cfg_clausedef_t * const *clausesets = type->of;
  991. isc_result_t result;
  992. const cfg_clausedef_t * const *clauseset;
  993. const cfg_clausedef_t *clause;
  994. cfg_obj_t *value = NULL;
  995. cfg_obj_t *obj = NULL;
  996. cfg_obj_t *eltobj = NULL;
  997. cfg_obj_t *includename = NULL;
  998. isc_symvalue_t symval;
  999. cfg_list_t *list = NULL;
  1000. CHECK(create_map(pctx, type, &obj));
  1001. obj->value.map.clausesets = clausesets;
  1002. for (;;) {
  1003. cfg_listelt_t *elt;
  1004. redo:
  1005. /*
  1006. * Parse the option name and see if it is known.
  1007. */
  1008. CHECK(cfg_gettoken(pctx, 0));
  1009. if (pctx->token.type != isc_tokentype_string) {
  1010. cfg_ungettoken(pctx);
  1011. break;
  1012. }
  1013. /*
  1014. * We accept "include" statements wherever a map body
  1015. * clause can occur.
  1016. */
  1017. if (strcasecmp(TOKEN_STRING(pctx), "include") == 0) {
  1018. /*
  1019. * Turn the file name into a temporary configuration
  1020. * object just so that it is not overwritten by the
  1021. * semicolon token.
  1022. */
  1023. CHECK(cfg_parse_obj(pctx, &cfg_type_qstring, &includename));
  1024. CHECK(parse_semicolon(pctx));
  1025. CHECK(parser_openfile(pctx, includename->
  1026. value.string.base));
  1027. cfg_obj_destroy(pctx, &includename);
  1028. goto redo;
  1029. }
  1030. clause = NULL;
  1031. for (clauseset = clausesets; *clauseset != NULL; clauseset++) {
  1032. for (clause = *clauseset;
  1033. clause->name != NULL;
  1034. clause++) {
  1035. if (strcasecmp(TOKEN_STRING(pctx),
  1036. clause->name) == 0)
  1037. goto done;
  1038. }
  1039. }
  1040. done:
  1041. if (clause == NULL || clause->name == NULL) {
  1042. cfg_parser_error(pctx, CFG_LOG_NOPREP, "unknown option");
  1043. /*
  1044. * Try to recover by parsing this option as an unknown
  1045. * option and discarding it.
  1046. */
  1047. CHECK(cfg_parse_obj(pctx, &cfg_type_unsupported, &eltobj));
  1048. cfg_obj_destroy(pctx, &eltobj);
  1049. CHECK(parse_semicolon(pctx));
  1050. continue;
  1051. }
  1052. /* Clause is known. */
  1053. /* Issue warnings if appropriate */
  1054. if ((clause->flags & CFG_CLAUSEFLAG_OBSOLETE) != 0)
  1055. cfg_parser_warning(pctx, 0, "option '%s' is obsolete",
  1056. clause->name);
  1057. if ((clause->flags & CFG_CLAUSEFLAG_NOTIMP) != 0)
  1058. cfg_parser_warning(pctx, 0, "option '%s' is "
  1059. "not implemented", clause->name);
  1060. if ((clause->flags & CFG_CLAUSEFLAG_NYI) != 0)
  1061. cfg_parser_warning(pctx, 0, "option '%s' is "
  1062. "not implemented", clause->name);
  1063. if ((clause->flags & CFG_CLAUSEFLAG_NOTCONFIGURED) != 0) {
  1064. cfg_parser_warning(pctx, 0, "option '%s' is not "
  1065. "configured", clause->name);
  1066. result = ISC_R_FAILURE;
  1067. goto cleanup;
  1068. }
  1069. /*
  1070. * Don't log options with CFG_CLAUSEFLAG_NEWDEFAULT
  1071. * set here - we need to log the *lack* of such an option,
  1072. * not its presence.
  1073. */
  1074. /* See if the clause already has a value; if not create one. */
  1075. result = isc_symtab_lookup(obj->value.map.symtab,
  1076. clause->name, 0, &symval);
  1077. if ((clause->flags & CFG_CLAUSEFLAG_MULTI) != 0) {
  1078. /* Multivalued clause */
  1079. cfg_obj_t *listobj = NULL;
  1080. if (result == ISC_R_NOTFOUND) {
  1081. CHECK(cfg_create_list(pctx,
  1082. &cfg_type_implicitlist,
  1083. &listobj));
  1084. symval.as_pointer = listobj;
  1085. result = isc_symtab_define(obj->value.
  1086. map.symtab,
  1087. clause->name,
  1088. 1, symval,
  1089. isc_symexists_reject);
  1090. if (result != ISC_R_SUCCESS) {
  1091. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1092. "isc_symtab_define(%s) "
  1093. "failed", clause->name);
  1094. isc_mem_put(pctx->mctx, list,
  1095. sizeof(cfg_list_t));
  1096. goto cleanup;
  1097. }
  1098. } else {
  1099. INSIST(result == ISC_R_SUCCESS);
  1100. listobj = symval.as_pointer;
  1101. }
  1102. elt = NULL;
  1103. CHECK(cfg_parse_listelt(pctx, clause->type, &elt));
  1104. CHECK(parse_semicolon(pctx));
  1105. ISC_LIST_APPEND(listobj->value.list, elt, link);
  1106. } else {
  1107. /* Single-valued clause */
  1108. if (result == ISC_R_NOTFOUND) {
  1109. isc_boolean_t callback =
  1110. ISC_TF((clause->flags &
  1111. CFG_CLAUSEFLAG_CALLBACK) != 0);
  1112. CHECK(parse_symtab_elt(pctx, clause->name,
  1113. clause->type,
  1114. obj->value.map.symtab,
  1115. callback));
  1116. CHECK(parse_semicolon(pctx));
  1117. } else if (result == ISC_R_SUCCESS) {
  1118. cfg_parser_error(pctx, CFG_LOG_NEAR, "'%s' redefined",
  1119. clause->name);
  1120. result = ISC_R_EXISTS;
  1121. goto cleanup;
  1122. } else {
  1123. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1124. "isc_symtab_define() failed");
  1125. goto cleanup;
  1126. }
  1127. }
  1128. }
  1129. *ret = obj;
  1130. return (ISC_R_SUCCESS);
  1131. cleanup:
  1132. CLEANUP_OBJ(value);
  1133. CLEANUP_OBJ(obj);
  1134. CLEANUP_OBJ(eltobj);
  1135. CLEANUP_OBJ(includename);
  1136. return (result);
  1137. }
  1138. static isc_result_t
  1139. parse_symtab_elt(cfg_parser_t *pctx, const char *name,
  1140. cfg_type_t *elttype, isc_symtab_t *symtab,
  1141. isc_boolean_t callback)
  1142. {
  1143. isc_result_t result;
  1144. cfg_obj_t *obj = NULL;
  1145. isc_symvalue_t symval;
  1146. CHECK(cfg_parse_obj(pctx, elttype, &obj));
  1147. if (callback && pctx->callback != NULL)
  1148. CHECK(pctx->callback(name, obj, pctx->callbackarg));
  1149. symval.as_pointer = obj;
  1150. CHECK(isc_symtab_define(symtab, name,
  1151. 1, symval,
  1152. isc_symexists_reject));
  1153. return (ISC_R_SUCCESS);
  1154. cleanup:
  1155. CLEANUP_OBJ(obj);
  1156. return (result);
  1157. }
  1158. /*
  1159. * Parse a map; e.g., "{ foo 1; bar { glub; }; zap true; zap false; }"
  1160. */
  1161. isc_result_t
  1162. cfg_parse_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1163. isc_result_t result;
  1164. CHECK(cfg_parse_special(pctx, '{'));
  1165. CHECK(cfg_parse_mapbody(pctx, type, ret));
  1166. CHECK(cfg_parse_special(pctx, '}'));
  1167. cleanup:
  1168. return (result);
  1169. }
  1170. /*
  1171. * Subroutine for cfg_parse_named_map() and cfg_parse_addressed_map().
  1172. */
  1173. static isc_result_t
  1174. parse_any_named_map(cfg_parser_t *pctx, cfg_type_t *nametype, const cfg_type_t *type,
  1175. cfg_obj_t **ret)
  1176. {
  1177. isc_result_t result;
  1178. cfg_obj_t *idobj = NULL;
  1179. cfg_obj_t *mapobj = NULL;
  1180. CHECK(cfg_parse_obj(pctx, nametype, &idobj));
  1181. CHECK(cfg_parse_map(pctx, type, &mapobj));
  1182. mapobj->value.map.id = idobj;
  1183. idobj = NULL;
  1184. *ret = mapobj;
  1185. cleanup:
  1186. CLEANUP_OBJ(idobj);
  1187. return (result);
  1188. }
  1189. /*
  1190. * Parse a map identified by a string name. E.g., "name { foo 1; }".
  1191. * Used for the "key" and "channel" statements.
  1192. */
  1193. isc_result_t
  1194. cfg_parse_named_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1195. return (parse_any_named_map(pctx, &cfg_type_astring, type, ret));
  1196. }
  1197. /*
  1198. * Parse a map identified by a network address.
  1199. * Used to be used for the "server" statement.
  1200. */
  1201. isc_result_t
  1202. cfg_parse_addressed_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1203. return (parse_any_named_map(pctx, &cfg_type_netaddr, type, ret));
  1204. }
  1205. /*
  1206. * Parse a map identified by a network prefix.
  1207. * Used for the "server" statement.
  1208. */
  1209. isc_result_t
  1210. cfg_parse_netprefix_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1211. return (parse_any_named_map(pctx, &cfg_type_netprefix, type, ret));
  1212. }
  1213. void
  1214. cfg_print_mapbody(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1215. isc_result_t result = ISC_R_SUCCESS;
  1216. const cfg_clausedef_t * const *clauseset;
  1217. for (clauseset = obj->value.map.clausesets;
  1218. *clauseset != NULL;
  1219. clauseset++)
  1220. {
  1221. isc_symvalue_t symval;
  1222. const cfg_clausedef_t *clause;
  1223. for (clause = *clauseset;
  1224. clause->name != NULL;
  1225. clause++) {
  1226. result = isc_symtab_lookup(obj->value.map.symtab,
  1227. clause->name, 0, &symval);
  1228. if (result == ISC_R_SUCCESS) {
  1229. cfg_obj_t *obj = symval.as_pointer;
  1230. if (obj->type == &cfg_type_implicitlist) {
  1231. /* Multivalued. */
  1232. cfg_list_t *list = &obj->value.list;
  1233. cfg_listelt_t *elt;
  1234. for (elt = ISC_LIST_HEAD(*list);
  1235. elt != NULL;
  1236. elt = ISC_LIST_NEXT(elt, link)) {
  1237. print_indent(pctx);
  1238. cfg_print_cstr(pctx, clause->name);
  1239. cfg_print_chars(pctx, " ", 1);
  1240. cfg_print_obj(pctx, elt->obj);
  1241. cfg_print_chars(pctx, ";\n", 2);
  1242. }
  1243. } else {
  1244. /* Single-valued. */
  1245. print_indent(pctx);
  1246. cfg_print_cstr(pctx, clause->name);
  1247. cfg_print_chars(pctx, " ", 1);
  1248. cfg_print_obj(pctx, obj);
  1249. cfg_print_chars(pctx, ";\n", 2);
  1250. }
  1251. } else if (result == ISC_R_NOTFOUND) {
  1252. ; /* do nothing */
  1253. } else {
  1254. INSIST(0);
  1255. }
  1256. }
  1257. }
  1258. }
  1259. void
  1260. cfg_doc_mapbody(cfg_printer_t *pctx, const cfg_type_t *type) {
  1261. const cfg_clausedef_t * const *clauseset;
  1262. const cfg_clausedef_t *clause;
  1263. for (clauseset = type->of; *clauseset != NULL; clauseset++) {
  1264. for (clause = *clauseset;
  1265. clause->name != NULL;
  1266. clause++) {
  1267. cfg_print_cstr(pctx, clause->name);
  1268. cfg_print_chars(pctx, " ", 1);
  1269. cfg_doc_obj(pctx, clause->type);
  1270. cfg_print_chars(pctx, ";", 1);
  1271. /* XXX print flags here? */
  1272. cfg_print_chars(pctx, "\n\n", 2);
  1273. }
  1274. }
  1275. }
  1276. static struct flagtext {
  1277. unsigned int flag;
  1278. const char *text;
  1279. } flagtexts[] = {
  1280. { CFG_CLAUSEFLAG_NOTIMP, "not implemented" },
  1281. { CFG_CLAUSEFLAG_NYI, "not yet implemented" },
  1282. { CFG_CLAUSEFLAG_OBSOLETE, "obsolete" },
  1283. { CFG_CLAUSEFLAG_NEWDEFAULT, "default changed" },
  1284. { CFG_CLAUSEFLAG_TESTONLY, "test only" },
  1285. { CFG_CLAUSEFLAG_NOTCONFIGURED, "not configured" },
  1286. { 0, NULL }
  1287. };
  1288. void
  1289. cfg_print_map(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1290. if (obj->value.map.id != NULL) {
  1291. cfg_print_obj(pctx, obj->value.map.id);
  1292. cfg_print_chars(pctx, " ", 1);
  1293. }
  1294. print_open(pctx);
  1295. cfg_print_mapbody(pctx, obj);
  1296. print_close(pctx);
  1297. }
  1298. static void
  1299. print_clause_flags(cfg_printer_t *pctx, unsigned int flags) {
  1300. struct flagtext *p;
  1301. isc_boolean_t first = ISC_TRUE;
  1302. for (p = flagtexts; p->flag != 0; p++) {
  1303. if ((flags & p->flag) != 0) {
  1304. if (first)
  1305. cfg_print_chars(pctx, " // ", 4);
  1306. else
  1307. cfg_print_chars(pctx, ", ", 2);
  1308. cfg_print_cstr(pctx, p->text);
  1309. first = ISC_FALSE;
  1310. }
  1311. }
  1312. }
  1313. void
  1314. cfg_doc_map(cfg_printer_t *pctx, const cfg_type_t *type) {
  1315. const cfg_clausedef_t * const *clauseset;
  1316. const cfg_clausedef_t *clause;
  1317. if (type->parse == cfg_parse_named_map) {
  1318. cfg_doc_obj(pctx, &cfg_type_astring);
  1319. cfg_print_chars(pctx, " ", 1);
  1320. } else if (type->parse == cfg_parse_addressed_map) {
  1321. cfg_doc_obj(pctx, &cfg_type_netaddr);
  1322. cfg_print_chars(pctx, " ", 1);
  1323. } else if (type->parse == cfg_parse_netprefix_map) {
  1324. cfg_doc_obj(pctx, &cfg_type_netprefix);
  1325. cfg_print_chars(pctx, " ", 1);
  1326. }
  1327. print_open(pctx);
  1328. for (clauseset = type->of; *clauseset != NULL; clauseset++) {
  1329. for (clause = *clauseset;
  1330. clause->name != NULL;
  1331. clause++) {
  1332. print_indent(pctx);
  1333. cfg_print_cstr(pctx, clause->name);
  1334. if (clause->type->print != cfg_print_void)
  1335. cfg_print_chars(pctx, " ", 1);
  1336. cfg_doc_obj(pctx, clause->type);
  1337. cfg_print_chars(pctx, ";", 1);
  1338. print_clause_flags(pctx, clause->flags);
  1339. cfg_print_chars(pctx, "\n", 1);
  1340. }
  1341. }
  1342. print_close(pctx);
  1343. }
  1344. isc_boolean_t
  1345. cfg_obj_ismap(const cfg_obj_t *obj) {
  1346. REQUIRE(obj != NULL);
  1347. return (ISC_TF(obj->type->rep == &cfg_rep_map));
  1348. }
  1349. isc_result_t
  1350. cfg_map_get(const cfg_obj_t *mapobj, const char* name, const cfg_obj_t **obj) {
  1351. isc_result_t result;
  1352. isc_symvalue_t val;
  1353. const cfg_map_t *map;
  1354. REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
  1355. REQUIRE(name != NULL);
  1356. REQUIRE(obj != NULL && *obj == NULL);
  1357. map = &mapobj->value.map;
  1358. result = isc_symtab_lookup(map->symtab, name, MAP_SYM, &val);
  1359. if (result != ISC_R_SUCCESS)
  1360. return (result);
  1361. *obj = val.as_pointer;
  1362. return (ISC_R_SUCCESS);
  1363. }
  1364. const cfg_obj_t *
  1365. cfg_map_getname(const cfg_obj_t *mapobj) {
  1366. REQUIRE(mapobj != NULL && mapobj->type->rep == &cfg_rep_map);
  1367. return (mapobj->value.map.id);
  1368. }
  1369. /* Parse an arbitrary token, storing its raw text representation. */
  1370. static isc_result_t
  1371. parse_token(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1372. cfg_obj_t *obj = NULL;
  1373. isc_result_t result;
  1374. isc_region_t r;
  1375. UNUSED(type);
  1376. CHECK(cfg_create_obj(pctx, &cfg_type_token, &obj));
  1377. CHECK(cfg_gettoken(pctx, CFG_LEXOPT_QSTRING));
  1378. if (pctx->token.type == isc_tokentype_eof) {
  1379. cfg_ungettoken(pctx);
  1380. result = ISC_R_EOF;
  1381. goto cleanup;
  1382. }
  1383. isc_lex_getlasttokentext(pctx->lexer, &pctx->token, &r);
  1384. obj->value.string.base = isc_mem_get(pctx->mctx, r.length + 1);
  1385. if (obj->value.string.base == NULL) {
  1386. result = ISC_R_NOMEMORY;
  1387. goto cleanup;
  1388. }
  1389. obj->value.string.length = r.length;
  1390. memcpy(obj->value.string.base, r.base, r.length);
  1391. obj->value.string.base[r.length] = '\0';
  1392. *ret = obj;
  1393. return (result);
  1394. cleanup:
  1395. if (obj != NULL)
  1396. isc_mem_put(pctx->mctx, obj, sizeof(*obj));
  1397. return (result);
  1398. }
  1399. cfg_type_t cfg_type_token = {
  1400. "token", parse_token, cfg_print_ustring, cfg_doc_terminal,
  1401. &cfg_rep_string, NULL
  1402. };
  1403. /*
  1404. * An unsupported option. This is just a list of tokens with balanced braces
  1405. * ending in a semicolon.
  1406. */
  1407. static isc_result_t
  1408. parse_unsupported(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1409. cfg_obj_t *listobj = NULL;
  1410. isc_result_t result;
  1411. int braces = 0;
  1412. CHECK(cfg_create_list(pctx, type, &listobj));
  1413. for (;;) {
  1414. cfg_listelt_t *elt = NULL;
  1415. CHECK(cfg_peektoken(pctx, 0));
  1416. if (pctx->token.type == isc_tokentype_special) {
  1417. if (pctx->token.value.as_char == '{')
  1418. braces++;
  1419. else if (pctx->token.value.as_char == '}')
  1420. braces--;
  1421. else if (pctx->token.value.as_char == ';')
  1422. if (braces == 0)
  1423. break;
  1424. }
  1425. if (pctx->token.type == isc_tokentype_eof || braces < 0) {
  1426. cfg_parser_error(pctx, CFG_LOG_NEAR, "unexpected token");
  1427. result = ISC_R_UNEXPECTEDTOKEN;
  1428. goto cleanup;
  1429. }
  1430. CHECK(cfg_parse_listelt(pctx, &cfg_type_token, &elt));
  1431. ISC_LIST_APPEND(listobj->value.list, elt, link);
  1432. }
  1433. INSIST(braces == 0);
  1434. *ret = listobj;
  1435. return (ISC_R_SUCCESS);
  1436. cleanup:
  1437. CLEANUP_OBJ(listobj);
  1438. return (result);
  1439. }
  1440. cfg_type_t cfg_type_unsupported = {
  1441. "unsupported", parse_unsupported, cfg_print_spacelist, cfg_doc_terminal,
  1442. &cfg_rep_list, NULL
  1443. };
  1444. /*
  1445. * Try interpreting the current token as a network address.
  1446. *
  1447. * If CFG_ADDR_WILDOK is set in flags, "*" can be used as a wildcard
  1448. * and at least one of CFG_ADDR_V4OK and CFG_ADDR_V6OK must also be set. The
  1449. * "*" is interpreted as the IPv4 wildcard address if CFG_ADDR_V4OK is
  1450. * set (including the case where CFG_ADDR_V4OK and CFG_ADDR_V6OK are both set),
  1451. * and the IPv6 wildcard address otherwise.
  1452. */
  1453. static isc_result_t
  1454. token_addr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
  1455. char *s;
  1456. struct in_addr in4a;
  1457. struct in6_addr in6a;
  1458. if (pctx->token.type != isc_tokentype_string)
  1459. return (ISC_R_UNEXPECTEDTOKEN);
  1460. s = TOKEN_STRING(pctx);
  1461. if ((flags & CFG_ADDR_WILDOK) != 0 && strcmp(s, "*") == 0) {
  1462. if ((flags & CFG_ADDR_V4OK) != 0) {
  1463. isc_netaddr_any(na);
  1464. return (ISC_R_SUCCESS);
  1465. } else if ((flags & CFG_ADDR_V6OK) != 0) {
  1466. isc_netaddr_any6(na);
  1467. return (ISC_R_SUCCESS);
  1468. } else {
  1469. INSIST(0);
  1470. }
  1471. } else {
  1472. if ((flags & (CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK)) != 0) {
  1473. if (inet_pton(AF_INET, s, &in4a) == 1) {
  1474. isc_netaddr_fromin(na, &in4a);
  1475. return (ISC_R_SUCCESS);
  1476. }
  1477. }
  1478. if ((flags & CFG_ADDR_V4PREFIXOK) != 0 &&
  1479. strlen(s) <= 15U) {
  1480. char buf[64];
  1481. int i;
  1482. strcpy(buf, s);
  1483. for (i = 0; i < 3; i++) {
  1484. strcat(buf, ".0");
  1485. if (inet_pton(AF_INET, buf, &in4a) == 1) {
  1486. isc_netaddr_fromin(na, &in4a);
  1487. return (ISC_R_SUCCESS);
  1488. }
  1489. }
  1490. }
  1491. if ((flags & CFG_ADDR_V6OK) != 0 &&
  1492. strlen(s) <= 127U) {
  1493. char buf[128]; /* see lib/bind9/getaddresses.c */
  1494. char *d; /* zone delimiter */
  1495. isc_uint32_t zone = 0; /* scope zone ID */
  1496. strcpy(buf, s);
  1497. d = strchr(buf, '%');
  1498. if (d != NULL)
  1499. *d = '\0';
  1500. if (inet_pton(AF_INET6, buf, &in6a) == 1) {
  1501. if (d != NULL) {
  1502. #ifdef ISC_PLATFORM_HAVESCOPEID
  1503. isc_result_t result;
  1504. result = isc_netscope_pton(AF_INET6,
  1505. d + 1,
  1506. &in6a,
  1507. &zone);
  1508. if (result != ISC_R_SUCCESS)
  1509. return (result);
  1510. #else
  1511. return (ISC_R_BADADDRESSFORM);
  1512. #endif
  1513. }
  1514. isc_netaddr_fromin6(na, &in6a);
  1515. isc_netaddr_setzone(na, zone);
  1516. return (ISC_R_SUCCESS);
  1517. }
  1518. }
  1519. }
  1520. return (ISC_R_UNEXPECTEDTOKEN);
  1521. }
  1522. isc_result_t
  1523. cfg_parse_rawaddr(cfg_parser_t *pctx, unsigned int flags, isc_netaddr_t *na) {
  1524. isc_result_t result;
  1525. const char *wild = "";
  1526. const char *prefix = "";
  1527. CHECK(cfg_gettoken(pctx, 0));
  1528. result = token_addr(pctx, flags, na);
  1529. if (result == ISC_R_UNEXPECTEDTOKEN) {
  1530. if ((flags & CFG_ADDR_WILDOK) != 0)
  1531. wild = " or '*'";
  1532. if ((flags & CFG_ADDR_V4PREFIXOK) != 0)
  1533. wild = " or IPv4 prefix";
  1534. if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V4OK)
  1535. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1536. "expected IPv4 address%s%s",
  1537. prefix, wild);
  1538. else if ((flags & CFG_ADDR_MASK) == CFG_ADDR_V6OK)
  1539. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1540. "expected IPv6 address%s%s",
  1541. prefix, wild);
  1542. else
  1543. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1544. "expected IP address%s%s",
  1545. prefix, wild);
  1546. }
  1547. cleanup:
  1548. return (result);
  1549. }
  1550. isc_boolean_t
  1551. cfg_lookingat_netaddr(cfg_parser_t *pctx, unsigned int flags) {
  1552. isc_result_t result;
  1553. isc_netaddr_t na_dummy;
  1554. result = token_addr(pctx, flags, &na_dummy);
  1555. return (ISC_TF(result == ISC_R_SUCCESS));
  1556. }
  1557. isc_result_t
  1558. cfg_parse_rawport(cfg_parser_t *pctx, unsigned int flags, in_port_t *port) {
  1559. isc_result_t result;
  1560. CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
  1561. if ((flags & CFG_ADDR_WILDOK) != 0 &&
  1562. pctx->token.type == isc_tokentype_string &&
  1563. strcmp(TOKEN_STRING(pctx), "*") == 0) {
  1564. *port = 0;
  1565. return (ISC_R_SUCCESS);
  1566. }
  1567. if (pctx->token.type != isc_tokentype_number) {
  1568. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1569. "expected port number or '*'");
  1570. return (ISC_R_UNEXPECTEDTOKEN);
  1571. }
  1572. if (pctx->token.value.as_ulong >= 65536U) {
  1573. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1574. "port number out of range");
  1575. return (ISC_R_UNEXPECTEDTOKEN);
  1576. }
  1577. *port = (in_port_t)(pctx->token.value.as_ulong);
  1578. return (ISC_R_SUCCESS);
  1579. cleanup:
  1580. return (result);
  1581. }
  1582. void
  1583. cfg_print_rawaddr(cfg_printer_t *pctx, const isc_netaddr_t *na) {
  1584. isc_result_t result;
  1585. char text[128];
  1586. isc_buffer_t buf;
  1587. isc_buffer_init(&buf, text, sizeof(text));
  1588. result = isc_netaddr_totext(na, &buf);
  1589. RUNTIME_CHECK(result == ISC_R_SUCCESS);
  1590. cfg_print_chars(pctx, isc_buffer_base(&buf), isc_buffer_usedlength(&buf));
  1591. }
  1592. /* netaddr */
  1593. static unsigned int netaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
  1594. static unsigned int netaddr4_flags = CFG_ADDR_V4OK;
  1595. static unsigned int netaddr4wild_flags = CFG_ADDR_V4OK | CFG_ADDR_WILDOK;
  1596. static unsigned int netaddr6_flags = CFG_ADDR_V6OK;
  1597. static unsigned int netaddr6wild_flags = CFG_ADDR_V6OK | CFG_ADDR_WILDOK;
  1598. static isc_result_t
  1599. parse_netaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1600. isc_result_t result;
  1601. cfg_obj_t *obj = NULL;
  1602. isc_netaddr_t netaddr;
  1603. unsigned int flags = *(const unsigned int *)type->of;
  1604. CHECK(cfg_create_obj(pctx, type, &obj));
  1605. CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
  1606. isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, 0);
  1607. *ret = obj;
  1608. return (ISC_R_SUCCESS);
  1609. cleanup:
  1610. CLEANUP_OBJ(obj);
  1611. return (result);
  1612. }
  1613. static void
  1614. cfg_doc_netaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
  1615. const unsigned int *flagp = type->of;
  1616. int n = 0;
  1617. if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
  1618. cfg_print_chars(pctx, "( ", 2);
  1619. if (*flagp & CFG_ADDR_V4OK) {
  1620. cfg_print_cstr(pctx, "<ipv4_address>");
  1621. n++;
  1622. }
  1623. if (*flagp & CFG_ADDR_V6OK) {
  1624. if (n != 0)
  1625. cfg_print_chars(pctx, " | ", 3);
  1626. cfg_print_cstr(pctx, "<ipv6_address>");
  1627. n++;
  1628. }
  1629. if (*flagp & CFG_ADDR_WILDOK) {
  1630. if (n != 0)
  1631. cfg_print_chars(pctx, " | ", 3);
  1632. cfg_print_chars(pctx, "*", 1);
  1633. n++;
  1634. POST(n);
  1635. }
  1636. if (*flagp != CFG_ADDR_V4OK && *flagp != CFG_ADDR_V6OK)
  1637. cfg_print_chars(pctx, " )", 2);
  1638. }
  1639. cfg_type_t cfg_type_netaddr = {
  1640. "netaddr", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
  1641. &cfg_rep_sockaddr, &netaddr_flags
  1642. };
  1643. cfg_type_t cfg_type_netaddr4 = {
  1644. "netaddr4", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
  1645. &cfg_rep_sockaddr, &netaddr4_flags
  1646. };
  1647. cfg_type_t cfg_type_netaddr4wild = {
  1648. "netaddr4wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
  1649. &cfg_rep_sockaddr, &netaddr4wild_flags
  1650. };
  1651. cfg_type_t cfg_type_netaddr6 = {
  1652. "netaddr6", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
  1653. &cfg_rep_sockaddr, &netaddr6_flags
  1654. };
  1655. cfg_type_t cfg_type_netaddr6wild = {
  1656. "netaddr6wild", parse_netaddr, cfg_print_sockaddr, cfg_doc_netaddr,
  1657. &cfg_rep_sockaddr, &netaddr6wild_flags
  1658. };
  1659. /* netprefix */
  1660. isc_result_t
  1661. cfg_parse_netprefix(cfg_parser_t *pctx, const cfg_type_t *type,
  1662. cfg_obj_t **ret)
  1663. {
  1664. cfg_obj_t *obj = NULL;
  1665. isc_result_t result;
  1666. isc_netaddr_t netaddr;
  1667. unsigned int addrlen = 0, prefixlen;
  1668. UNUSED(type);
  1669. CHECK(cfg_parse_rawaddr(pctx, CFG_ADDR_V4OK | CFG_ADDR_V4PREFIXOK |
  1670. CFG_ADDR_V6OK, &netaddr));
  1671. switch (netaddr.family) {
  1672. case AF_INET:
  1673. addrlen = 32;
  1674. break;
  1675. case AF_INET6:
  1676. addrlen = 128;
  1677. break;
  1678. default:
  1679. INSIST(0);
  1680. break;
  1681. }
  1682. CHECK(cfg_peektoken(pctx, 0));
  1683. if (pctx->token.type == isc_tokentype_special &&
  1684. pctx->token.value.as_char == '/') {
  1685. CHECK(cfg_gettoken(pctx, 0)); /* read "/" */
  1686. CHECK(cfg_gettoken(pctx, ISC_LEXOPT_NUMBER));
  1687. if (pctx->token.type != isc_tokentype_number) {
  1688. cfg_parser_error(pctx, CFG_LOG_NEAR,
  1689. "expected prefix length");
  1690. return (ISC_R_UNEXPECTEDTOKEN);
  1691. }
  1692. prefixlen = pctx->token.value.as_ulong;
  1693. if (prefixlen > addrlen) {
  1694. cfg_parser_error(pctx, CFG_LOG_NOPREP,
  1695. "invalid prefix length");
  1696. return (ISC_R_RANGE);
  1697. }
  1698. } else {
  1699. prefixlen = addrlen;
  1700. }
  1701. CHECK(cfg_create_obj(pctx, &cfg_type_netprefix, &obj));
  1702. obj->value.netprefix.address = netaddr;
  1703. obj->value.netprefix.prefixlen = prefixlen;
  1704. *ret = obj;
  1705. return (ISC_R_SUCCESS);
  1706. cleanup:
  1707. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected network prefix");
  1708. return (result);
  1709. }
  1710. static void
  1711. print_netprefix(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1712. const cfg_netprefix_t *p = &obj->value.netprefix;
  1713. cfg_print_rawaddr(pctx, &p->address);
  1714. cfg_print_chars(pctx, "/", 1);
  1715. cfg_print_rawuint(pctx, p->prefixlen);
  1716. }
  1717. isc_boolean_t
  1718. cfg_obj_isnetprefix(const cfg_obj_t *obj) {
  1719. REQUIRE(obj != NULL);
  1720. return (ISC_TF(obj->type->rep == &cfg_rep_netprefix));
  1721. }
  1722. void
  1723. cfg_obj_asnetprefix(const cfg_obj_t *obj, isc_netaddr_t *netaddr,
  1724. unsigned int *prefixlen)
  1725. {
  1726. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_netprefix);
  1727. REQUIRE(netaddr != NULL);
  1728. REQUIRE(prefixlen != NULL);
  1729. *netaddr = obj->value.netprefix.address;
  1730. *prefixlen = obj->value.netprefix.prefixlen;
  1731. }
  1732. cfg_type_t cfg_type_netprefix = {
  1733. "netprefix", cfg_parse_netprefix, print_netprefix, cfg_doc_terminal,
  1734. &cfg_rep_netprefix, NULL
  1735. };
  1736. static isc_result_t
  1737. parse_sockaddrsub(cfg_parser_t *pctx, const cfg_type_t *type,
  1738. int flags, cfg_obj_t **ret)
  1739. {
  1740. isc_result_t result;
  1741. isc_netaddr_t netaddr;
  1742. in_port_t port = 0;
  1743. cfg_obj_t *obj = NULL;
  1744. CHECK(cfg_create_obj(pctx, type, &obj));
  1745. CHECK(cfg_parse_rawaddr(pctx, flags, &netaddr));
  1746. CHECK(cfg_peektoken(pctx, 0));
  1747. if (pctx->token.type == isc_tokentype_string &&
  1748. strcasecmp(TOKEN_STRING(pctx), "port") == 0) {
  1749. CHECK(cfg_gettoken(pctx, 0)); /* read "port" */
  1750. CHECK(cfg_parse_rawport(pctx, flags, &port));
  1751. }
  1752. isc_sockaddr_fromnetaddr(&obj->value.sockaddr, &netaddr, port);
  1753. *ret = obj;
  1754. return (ISC_R_SUCCESS);
  1755. cleanup:
  1756. CLEANUP_OBJ(obj);
  1757. return (result);
  1758. }
  1759. static unsigned int sockaddr_flags = CFG_ADDR_V4OK | CFG_ADDR_V6OK;
  1760. cfg_type_t cfg_type_sockaddr = {
  1761. "sockaddr", cfg_parse_sockaddr, cfg_print_sockaddr, cfg_doc_sockaddr,
  1762. &cfg_rep_sockaddr, &sockaddr_flags
  1763. };
  1764. isc_result_t
  1765. cfg_parse_sockaddr(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  1766. const unsigned int *flagp = type->of;
  1767. return (parse_sockaddrsub(pctx, &cfg_type_sockaddr, *flagp, ret));
  1768. }
  1769. void
  1770. cfg_print_sockaddr(cfg_printer_t *pctx, const cfg_obj_t *obj) {
  1771. isc_netaddr_t netaddr;
  1772. in_port_t port;
  1773. char buf[ISC_NETADDR_FORMATSIZE];
  1774. isc_netaddr_fromsockaddr(&netaddr, &obj->value.sockaddr);
  1775. isc_netaddr_format(&netaddr, buf, sizeof(buf));
  1776. cfg_print_cstr(pctx, buf);
  1777. port = isc_sockaddr_getport(&obj->value.sockaddr);
  1778. if (port != 0) {
  1779. cfg_print_chars(pctx, " port ", 6);
  1780. cfg_print_rawuint(pctx, port);
  1781. }
  1782. }
  1783. void
  1784. cfg_doc_sockaddr(cfg_printer_t *pctx, const cfg_type_t *type) {
  1785. const unsigned int *flagp = type->of;
  1786. int n = 0;
  1787. cfg_print_chars(pctx, "( ", 2);
  1788. if (*flagp & CFG_ADDR_V4OK) {
  1789. cfg_print_cstr(pctx, "<ipv4_address>");
  1790. n++;
  1791. }
  1792. if (*flagp & CFG_ADDR_V6OK) {
  1793. if (n != 0)
  1794. cfg_print_chars(pctx, " | ", 3);
  1795. cfg_print_cstr(pctx, "<ipv6_address>");
  1796. n++;
  1797. }
  1798. if (*flagp & CFG_ADDR_WILDOK) {
  1799. if (n != 0)
  1800. cfg_print_chars(pctx, " | ", 3);
  1801. cfg_print_chars(pctx, "*", 1);
  1802. n++;
  1803. POST(n);
  1804. }
  1805. cfg_print_chars(pctx, " ) ", 3);
  1806. if (*flagp & CFG_ADDR_WILDOK) {
  1807. cfg_print_cstr(pctx, "[ port ( <integer> | * ) ]");
  1808. } else {
  1809. cfg_print_cstr(pctx, "[ port <integer> ]");
  1810. }
  1811. }
  1812. isc_boolean_t
  1813. cfg_obj_issockaddr(const cfg_obj_t *obj) {
  1814. REQUIRE(obj != NULL);
  1815. return (ISC_TF(obj->type->rep == &cfg_rep_sockaddr));
  1816. }
  1817. const isc_sockaddr_t *
  1818. cfg_obj_assockaddr(const cfg_obj_t *obj) {
  1819. REQUIRE(obj != NULL && obj->type->rep == &cfg_rep_sockaddr);
  1820. return (&obj->value.sockaddr);
  1821. }
  1822. isc_result_t
  1823. cfg_gettoken(cfg_parser_t *pctx, int options) {
  1824. isc_result_t result;
  1825. if (pctx->seen_eof)
  1826. return (ISC_R_SUCCESS);
  1827. options |= (ISC_LEXOPT_EOF | ISC_LEXOPT_NOMORE);
  1828. redo:
  1829. pctx->token.type = isc_tokentype_unknown;
  1830. result = isc_lex_gettoken(pctx->lexer, options, &pctx->token);
  1831. pctx->ungotten = ISC_FALSE;
  1832. pctx->line = isc_lex_getsourceline(pctx->lexer);
  1833. switch (result) {
  1834. case ISC_R_SUCCESS:
  1835. if (pctx->token.type == isc_tokentype_eof) {
  1836. result = isc_lex_close(pctx->lexer);
  1837. INSIST(result == ISC_R_NOMORE ||
  1838. result == ISC_R_SUCCESS);
  1839. if (isc_lex_getsourcename(pctx->lexer) != NULL) {
  1840. /*
  1841. * Closed an included file, not the main file.
  1842. */
  1843. cfg_listelt_t *elt;
  1844. elt = ISC_LIST_TAIL(pctx->open_files->
  1845. value.list);
  1846. INSIST(elt != NULL);
  1847. ISC_LIST_UNLINK(pctx->open_files->
  1848. value.list, elt, link);
  1849. ISC_LIST_APPEND(pctx->closed_files->
  1850. value.list, elt, link);
  1851. goto redo;
  1852. }
  1853. pctx->seen_eof = ISC_TRUE;
  1854. }
  1855. break;
  1856. case ISC_R_NOSPACE:
  1857. /* More understandable than "ran out of space". */
  1858. cfg_parser_error(pctx, CFG_LOG_NEAR, "token too big");
  1859. break;
  1860. case ISC_R_IOERROR:
  1861. cfg_parser_error(pctx, 0, "%s",
  1862. isc_result_totext(result));
  1863. break;
  1864. default:
  1865. cfg_parser_error(pctx, CFG_LOG_NEAR, "%s",
  1866. isc_result_totext(result));
  1867. break;
  1868. }
  1869. return (result);
  1870. }
  1871. void
  1872. cfg_ungettoken(cfg_parser_t *pctx) {
  1873. if (pctx->seen_eof)
  1874. return;
  1875. isc_lex_ungettoken(pctx->lexer, &pctx->token);
  1876. pctx->ungotten = ISC_TRUE;
  1877. }
  1878. isc_result_t
  1879. cfg_peektoken(cfg_parser_t *pctx, int options) {
  1880. isc_result_t result;
  1881. CHECK(cfg_gettoken(pctx, options));
  1882. cfg_ungettoken(pctx);
  1883. cleanup:
  1884. return (result);
  1885. }
  1886. /*
  1887. * Get a string token, accepting both the quoted and the unquoted form.
  1888. * Log an error if the next token is not a string.
  1889. */
  1890. static isc_result_t
  1891. cfg_getstringtoken(cfg_parser_t *pctx) {
  1892. isc_result_t result;
  1893. result = cfg_gettoken(pctx, CFG_LEXOPT_QSTRING);
  1894. if (result != ISC_R_SUCCESS)
  1895. return (result);
  1896. if (pctx->token.type != isc_tokentype_string &&
  1897. pctx->token.type != isc_tokentype_qstring) {
  1898. cfg_parser_error(pctx, CFG_LOG_NEAR, "expected string");
  1899. return (ISC_R_UNEXPECTEDTOKEN);
  1900. }
  1901. return (ISC_R_SUCCESS);
  1902. }
  1903. void
  1904. cfg_parser_error(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
  1905. va_list args;
  1906. va_start(args, fmt);
  1907. parser_complain(pctx, ISC_FALSE, flags, fmt, args);
  1908. va_end(args);
  1909. pctx->errors++;
  1910. }
  1911. void
  1912. cfg_parser_warning(cfg_parser_t *pctx, unsigned int flags, const char *fmt, ...) {
  1913. va_list args;
  1914. va_start(args, fmt);
  1915. parser_complain(pctx, ISC_TRUE, flags, fmt, args);
  1916. va_end(args);
  1917. pctx->warnings++;
  1918. }
  1919. #define MAX_LOG_TOKEN 30 /* How much of a token to quote in log messages. */
  1920. static isc_boolean_t
  1921. have_current_file(cfg_parser_t *pctx) {
  1922. cfg_listelt_t *elt;
  1923. if (pctx->open_files == NULL)
  1924. return (ISC_FALSE);
  1925. elt = ISC_LIST_TAIL(pctx->open_files->value.list);
  1926. if (elt == NULL)
  1927. return (ISC_FALSE);
  1928. return (ISC_TRUE);
  1929. }
  1930. static char *
  1931. current_file(cfg_parser_t *pctx) {
  1932. static char none[] = "none";
  1933. cfg_listelt_t *elt;
  1934. cfg_obj_t *fileobj;
  1935. if (!have_current_file(pctx))
  1936. return (none);
  1937. elt = ISC_LIST_TAIL(pctx->open_files->value.list);
  1938. if (elt == NULL) /* shouldn't be possible, but... */
  1939. return (none);
  1940. fileobj = elt->obj;
  1941. INSIST(fileobj->type == &cfg_type_qstring);
  1942. return (fileobj->value.string.base);
  1943. }
  1944. static void
  1945. parser_complain(cfg_parser_t *pctx, isc_boolean_t is_warning,
  1946. unsigned int flags, const char *format,
  1947. va_list args)
  1948. {
  1949. char tokenbuf[MAX_LOG_TOKEN + 10];
  1950. static char where[ISC_DIR_PATHMAX + 100];
  1951. static char message[2048];
  1952. int level = ISC_LOG_ERROR;
  1953. const char *prep = "";
  1954. size_t len;
  1955. if (is_warning)
  1956. level = ISC_LOG_WARNING;
  1957. where[0] = '\0';
  1958. if (have_current_file(pctx))
  1959. snprintf(where, sizeof(where), "%s:%u: ",
  1960. current_file(pctx), pctx->line);
  1961. len = vsnprintf(message, sizeof(message), format, args);
  1962. if (len >= sizeof(message))
  1963. FATAL_ERROR(__FILE__, __LINE__,
  1964. "error message would overflow");
  1965. if ((flags & (CFG_LOG_NEAR|CFG_LOG_BEFORE|CFG_LOG_NOPREP)) != 0) {
  1966. isc_region_t r;
  1967. if (pctx->ungotten)
  1968. (void)cfg_gettoken(pctx, 0);
  1969. if (pctx->token.type == isc_tokentype_eof) {
  1970. snprintf(tokenbuf, sizeof(tokenbuf), "end of file");
  1971. } else if (pctx->token.type == isc_tokentype_unknown) {
  1972. flags = 0;
  1973. tokenbuf[0] = '\0';
  1974. } else {
  1975. isc_lex_getlasttokentext(pctx->lexer,
  1976. &pctx->token, &r);
  1977. if (r.length > MAX_LOG_TOKEN)
  1978. snprintf(tokenbuf, sizeof(tokenbuf),
  1979. "'%.*s...'", MAX_LOG_TOKEN, r.base);
  1980. else
  1981. snprintf(tokenbuf, sizeof(tokenbuf),
  1982. "'%.*s'", (int)r.length, r.base);
  1983. }
  1984. /* Choose a preposition. */
  1985. if (flags & CFG_LOG_NEAR)
  1986. prep = " near ";
  1987. else if (flags & CFG_LOG_BEFORE)
  1988. prep = " before ";
  1989. else
  1990. prep = " ";
  1991. } else {
  1992. tokenbuf[0] = '\0';
  1993. }
  1994. isc_log_write(pctx->lctx, CAT, MOD, level,
  1995. "%s%s%s%s", where, message, prep, tokenbuf);
  1996. }
  1997. void
  1998. cfg_obj_log(const cfg_obj_t *obj, isc_log_t *lctx, int level,
  1999. const char *fmt, ...) {
  2000. va_list ap;
  2001. char msgbuf[2048];
  2002. if (! isc_log_wouldlog(lctx, level))
  2003. return;
  2004. va_start(ap, fmt);
  2005. vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
  2006. isc_log_write(lctx, CAT, MOD, level,
  2007. "%s:%u: %s",
  2008. obj->file == NULL ? "<unknown file>" : obj->file,
  2009. obj->line, msgbuf);
  2010. va_end(ap);
  2011. }
  2012. const char *
  2013. cfg_obj_file(const cfg_obj_t *obj) {
  2014. return (obj->file);
  2015. }
  2016. unsigned int
  2017. cfg_obj_line(const cfg_obj_t *obj) {
  2018. return (obj->line);
  2019. }
  2020. isc_result_t
  2021. cfg_create_obj(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  2022. isc_result_t result;
  2023. cfg_obj_t *obj;
  2024. obj = isc_mem_get(pctx->mctx, sizeof(cfg_obj_t));
  2025. if (obj == NULL)
  2026. return (ISC_R_NOMEMORY);
  2027. obj->type = type;
  2028. obj->file = current_file(pctx);
  2029. obj->line = pctx->line;
  2030. result = isc_refcount_init(&obj->references, 1);
  2031. if (result != ISC_R_SUCCESS) {
  2032. isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
  2033. return (result);
  2034. }
  2035. *ret = obj;
  2036. return (ISC_R_SUCCESS);
  2037. }
  2038. static void
  2039. map_symtabitem_destroy(char *key, unsigned int type,
  2040. isc_symvalue_t symval, void *userarg)
  2041. {
  2042. cfg_obj_t *obj = symval.as_pointer;
  2043. cfg_parser_t *pctx = (cfg_parser_t *)userarg;
  2044. UNUSED(key);
  2045. UNUSED(type);
  2046. cfg_obj_destroy(pctx, &obj);
  2047. }
  2048. static isc_result_t
  2049. create_map(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) {
  2050. isc_result_t result;
  2051. isc_symtab_t *symtab = NULL;
  2052. cfg_obj_t *obj = NULL;
  2053. CHECK(cfg_create_obj(pctx, type, &obj));
  2054. CHECK(isc_symtab_create(pctx->mctx, 5, /* XXX */
  2055. map_symtabitem_destroy,
  2056. pctx, ISC_FALSE, &symtab));
  2057. obj->value.map.symtab = symtab;
  2058. obj->value.map.id = NULL;
  2059. *ret = obj;
  2060. return (ISC_R_SUCCESS);
  2061. cleanup:
  2062. if (obj != NULL)
  2063. isc_mem_put(pctx->mctx, obj, sizeof(*obj));
  2064. return (result);
  2065. }
  2066. static void
  2067. free_map(cfg_parser_t *pctx, cfg_obj_t *obj) {
  2068. CLEANUP_OBJ(obj->value.map.id);
  2069. isc_symtab_destroy(&obj->value.map.symtab);
  2070. }
  2071. isc_boolean_t
  2072. cfg_obj_istype(const cfg_obj_t *obj, const cfg_type_t *type) {
  2073. return (ISC_TF(obj->type == type));
  2074. }
  2075. /*
  2076. * Destroy 'obj', a configuration object created in 'pctx'.
  2077. */
  2078. void
  2079. cfg_obj_destroy(cfg_parser_t *pctx, cfg_obj_t **objp) {
  2080. cfg_obj_t *obj = *objp;
  2081. unsigned int refs;
  2082. isc_refcount_decrement(&obj->references, &refs);
  2083. if (refs == 0) {
  2084. obj->type->rep->free(pctx, obj);
  2085. isc_refcount_destroy(&obj->references);
  2086. isc_mem_put(pctx->mctx, obj, sizeof(cfg_obj_t));
  2087. }
  2088. *objp = NULL;
  2089. }
  2090. void
  2091. cfg_obj_attach(cfg_obj_t *src, cfg_obj_t **dest) {
  2092. REQUIRE(src != NULL);
  2093. REQUIRE(dest != NULL && *dest == NULL);
  2094. isc_refcount_increment(&src->references, NULL);
  2095. *dest = src;
  2096. }
  2097. static void
  2098. free_noop(cfg_parser_t *pctx, cfg_obj_t *obj) {
  2099. UNUSED(pctx);
  2100. UNUSED(obj);
  2101. }
  2102. void
  2103. cfg_doc_obj(cfg_printer_t *pctx, const cfg_type_t *type) {
  2104. type->doc(pctx, type);
  2105. }
  2106. void
  2107. cfg_doc_terminal(cfg_printer_t *pctx, const cfg_type_t *type) {
  2108. cfg_print_chars(pctx, "<", 1);
  2109. cfg_print_cstr(pctx, type->name);
  2110. cfg_print_chars(pctx, ">", 1);
  2111. }
  2112. void
  2113. cfg_print_grammar(const cfg_type_t *type,
  2114. void (*f)(void *closure, const char *text, int textlen),
  2115. void *closure)
  2116. {
  2117. cfg_printer_t pctx;
  2118. pctx.f = f;
  2119. pctx.closure = closure;
  2120. pctx.indent = 0;
  2121. cfg_doc_obj(&pctx, type);
  2122. }