PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/contrib/bind9/lib/bind9/check.c

https://bitbucket.org/freebsd/freebsd-head/
C | 2810 lines | 2392 code | 269 blank | 149 comment | 823 complexity | 403e0d46707d40b5f2209939c560fcaf 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) 2001-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 <stdlib.h>
  21. #include <isc/base64.h>
  22. #include <isc/buffer.h>
  23. #include <isc/log.h>
  24. #include <isc/mem.h>
  25. #include <isc/netaddr.h>
  26. #include <isc/parseint.h>
  27. #include <isc/region.h>
  28. #include <isc/result.h>
  29. #include <isc/sockaddr.h>
  30. #include <isc/string.h>
  31. #include <isc/symtab.h>
  32. #include <isc/util.h>
  33. #include <dns/acl.h>
  34. #include <dns/fixedname.h>
  35. #include <dns/rdataclass.h>
  36. #include <dns/rdatatype.h>
  37. #include <dns/secalg.h>
  38. #include <dst/dst.h>
  39. #include <isccfg/aclconf.h>
  40. #include <isccfg/cfg.h>
  41. #include <bind9/check.h>
  42. static void
  43. freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
  44. UNUSED(type);
  45. UNUSED(value);
  46. isc_mem_free(userarg, key);
  47. }
  48. static isc_result_t
  49. check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
  50. isc_result_t result = ISC_R_SUCCESS;
  51. isc_result_t tresult;
  52. isc_textregion_t r;
  53. dns_fixedname_t fixed;
  54. const cfg_obj_t *obj;
  55. dns_rdataclass_t rdclass;
  56. dns_rdatatype_t rdtype;
  57. isc_buffer_t b;
  58. const char *str;
  59. dns_fixedname_init(&fixed);
  60. obj = cfg_tuple_get(ent, "class");
  61. if (cfg_obj_isstring(obj)) {
  62. DE_CONST(cfg_obj_asstring(obj), r.base);
  63. r.length = strlen(r.base);
  64. tresult = dns_rdataclass_fromtext(&rdclass, &r);
  65. if (tresult != ISC_R_SUCCESS) {
  66. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  67. "rrset-order: invalid class '%s'",
  68. r.base);
  69. result = ISC_R_FAILURE;
  70. }
  71. }
  72. obj = cfg_tuple_get(ent, "type");
  73. if (cfg_obj_isstring(obj)) {
  74. DE_CONST(cfg_obj_asstring(obj), r.base);
  75. r.length = strlen(r.base);
  76. tresult = dns_rdatatype_fromtext(&rdtype, &r);
  77. if (tresult != ISC_R_SUCCESS) {
  78. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  79. "rrset-order: invalid type '%s'",
  80. r.base);
  81. result = ISC_R_FAILURE;
  82. }
  83. }
  84. obj = cfg_tuple_get(ent, "name");
  85. if (cfg_obj_isstring(obj)) {
  86. str = cfg_obj_asstring(obj);
  87. isc_buffer_init(&b, str, strlen(str));
  88. isc_buffer_add(&b, strlen(str));
  89. tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
  90. dns_rootname, 0, NULL);
  91. if (tresult != ISC_R_SUCCESS) {
  92. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  93. "rrset-order: invalid name '%s'", str);
  94. result = ISC_R_FAILURE;
  95. }
  96. }
  97. obj = cfg_tuple_get(ent, "order");
  98. if (!cfg_obj_isstring(obj) ||
  99. strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
  100. cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
  101. "rrset-order: keyword 'order' missing");
  102. result = ISC_R_FAILURE;
  103. }
  104. obj = cfg_tuple_get(ent, "ordering");
  105. if (!cfg_obj_isstring(obj)) {
  106. cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
  107. "rrset-order: missing ordering");
  108. result = ISC_R_FAILURE;
  109. } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
  110. #if !DNS_RDATASET_FIXED
  111. cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
  112. "rrset-order: order 'fixed' was disabled at "
  113. "compilation time");
  114. #endif
  115. } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
  116. strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
  117. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  118. "rrset-order: invalid order '%s'",
  119. cfg_obj_asstring(obj));
  120. result = ISC_R_FAILURE;
  121. }
  122. return (result);
  123. }
  124. static isc_result_t
  125. check_order(const cfg_obj_t *options, isc_log_t *logctx) {
  126. isc_result_t result = ISC_R_SUCCESS;
  127. isc_result_t tresult;
  128. const cfg_listelt_t *element;
  129. const cfg_obj_t *obj = NULL;
  130. if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
  131. return (result);
  132. for (element = cfg_list_first(obj);
  133. element != NULL;
  134. element = cfg_list_next(element))
  135. {
  136. tresult = check_orderent(cfg_listelt_value(element), logctx);
  137. if (tresult != ISC_R_SUCCESS)
  138. result = tresult;
  139. }
  140. return (result);
  141. }
  142. static isc_result_t
  143. check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
  144. const cfg_listelt_t *element;
  145. const cfg_obj_t *alternates = NULL;
  146. const cfg_obj_t *value;
  147. const cfg_obj_t *obj;
  148. const char *str;
  149. dns_fixedname_t fixed;
  150. dns_name_t *name;
  151. isc_buffer_t buffer;
  152. isc_result_t result = ISC_R_SUCCESS;
  153. isc_result_t tresult;
  154. (void)cfg_map_get(options, "dual-stack-servers", &alternates);
  155. if (alternates == NULL)
  156. return (ISC_R_SUCCESS);
  157. obj = cfg_tuple_get(alternates, "port");
  158. if (cfg_obj_isuint32(obj)) {
  159. isc_uint32_t val = cfg_obj_asuint32(obj);
  160. if (val > ISC_UINT16_MAX) {
  161. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  162. "port '%u' out of range", val);
  163. result = ISC_R_FAILURE;
  164. }
  165. }
  166. obj = cfg_tuple_get(alternates, "addresses");
  167. for (element = cfg_list_first(obj);
  168. element != NULL;
  169. element = cfg_list_next(element)) {
  170. value = cfg_listelt_value(element);
  171. if (cfg_obj_issockaddr(value))
  172. continue;
  173. obj = cfg_tuple_get(value, "name");
  174. str = cfg_obj_asstring(obj);
  175. isc_buffer_init(&buffer, str, strlen(str));
  176. isc_buffer_add(&buffer, strlen(str));
  177. dns_fixedname_init(&fixed);
  178. name = dns_fixedname_name(&fixed);
  179. tresult = dns_name_fromtext(name, &buffer, dns_rootname,
  180. 0, NULL);
  181. if (tresult != ISC_R_SUCCESS) {
  182. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  183. "bad name '%s'", str);
  184. result = ISC_R_FAILURE;
  185. }
  186. obj = cfg_tuple_get(value, "port");
  187. if (cfg_obj_isuint32(obj)) {
  188. isc_uint32_t val = cfg_obj_asuint32(obj);
  189. if (val > ISC_UINT16_MAX) {
  190. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  191. "port '%u' out of range", val);
  192. result = ISC_R_FAILURE;
  193. }
  194. }
  195. }
  196. return (result);
  197. }
  198. static isc_result_t
  199. check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
  200. isc_log_t *logctx)
  201. {
  202. const cfg_obj_t *forward = NULL;
  203. const cfg_obj_t *forwarders = NULL;
  204. (void)cfg_map_get(options, "forward", &forward);
  205. (void)cfg_map_get(options, "forwarders", &forwarders);
  206. if (forwarders != NULL && global != NULL) {
  207. const char *file = cfg_obj_file(global);
  208. unsigned int line = cfg_obj_line(global);
  209. cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
  210. "forwarders declared in root zone and "
  211. "in general configuration: %s:%u",
  212. file, line);
  213. return (ISC_R_FAILURE);
  214. }
  215. if (forward != NULL && forwarders == NULL) {
  216. cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
  217. "no matching 'forwarders' statement");
  218. return (ISC_R_FAILURE);
  219. }
  220. return (ISC_R_SUCCESS);
  221. }
  222. static isc_result_t
  223. disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
  224. isc_result_t result = ISC_R_SUCCESS;
  225. isc_result_t tresult;
  226. const cfg_listelt_t *element;
  227. const char *str;
  228. isc_buffer_t b;
  229. dns_fixedname_t fixed;
  230. dns_name_t *name;
  231. const cfg_obj_t *obj;
  232. dns_fixedname_init(&fixed);
  233. name = dns_fixedname_name(&fixed);
  234. obj = cfg_tuple_get(disabled, "name");
  235. str = cfg_obj_asstring(obj);
  236. isc_buffer_init(&b, str, strlen(str));
  237. isc_buffer_add(&b, strlen(str));
  238. tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  239. if (tresult != ISC_R_SUCCESS) {
  240. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  241. "bad domain name '%s'", str);
  242. result = tresult;
  243. }
  244. obj = cfg_tuple_get(disabled, "algorithms");
  245. for (element = cfg_list_first(obj);
  246. element != NULL;
  247. element = cfg_list_next(element))
  248. {
  249. isc_textregion_t r;
  250. dns_secalg_t alg;
  251. isc_result_t tresult;
  252. DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
  253. r.length = strlen(r.base);
  254. tresult = dns_secalg_fromtext(&alg, &r);
  255. if (tresult != ISC_R_SUCCESS) {
  256. isc_uint8_t ui;
  257. result = isc_parse_uint8(&ui, r.base, 10);
  258. }
  259. if (tresult != ISC_R_SUCCESS) {
  260. cfg_obj_log(cfg_listelt_value(element), logctx,
  261. ISC_LOG_ERROR, "invalid algorithm '%s'",
  262. r.base);
  263. result = tresult;
  264. }
  265. }
  266. return (result);
  267. }
  268. static isc_result_t
  269. nameexist(const cfg_obj_t *obj, const char *name, int value,
  270. isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
  271. isc_mem_t *mctx)
  272. {
  273. char *key;
  274. const char *file;
  275. unsigned int line;
  276. isc_result_t result;
  277. isc_symvalue_t symvalue;
  278. key = isc_mem_strdup(mctx, name);
  279. if (key == NULL)
  280. return (ISC_R_NOMEMORY);
  281. symvalue.as_cpointer = obj;
  282. result = isc_symtab_define(symtab, key, value, symvalue,
  283. isc_symexists_reject);
  284. if (result == ISC_R_EXISTS) {
  285. RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
  286. &symvalue) == ISC_R_SUCCESS);
  287. file = cfg_obj_file(symvalue.as_cpointer);
  288. line = cfg_obj_line(symvalue.as_cpointer);
  289. if (file == NULL)
  290. file = "<unknown file>";
  291. cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
  292. isc_mem_free(mctx, key);
  293. result = ISC_R_EXISTS;
  294. } else if (result != ISC_R_SUCCESS) {
  295. isc_mem_free(mctx, key);
  296. }
  297. return (result);
  298. }
  299. static isc_result_t
  300. mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
  301. isc_mem_t *mctx)
  302. {
  303. const cfg_obj_t *obj;
  304. char namebuf[DNS_NAME_FORMATSIZE];
  305. const char *str;
  306. dns_fixedname_t fixed;
  307. dns_name_t *name;
  308. isc_buffer_t b;
  309. isc_result_t result = ISC_R_SUCCESS;
  310. dns_fixedname_init(&fixed);
  311. name = dns_fixedname_name(&fixed);
  312. obj = cfg_tuple_get(secure, "name");
  313. str = cfg_obj_asstring(obj);
  314. isc_buffer_init(&b, str, strlen(str));
  315. isc_buffer_add(&b, strlen(str));
  316. result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
  317. if (result != ISC_R_SUCCESS) {
  318. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  319. "bad domain name '%s'", str);
  320. } else {
  321. dns_name_format(name, namebuf, sizeof(namebuf));
  322. result = nameexist(secure, namebuf, 1, symtab,
  323. "dnssec-must-be-secure '%s': already "
  324. "exists previous definition: %s:%u",
  325. logctx, mctx);
  326. }
  327. return (result);
  328. }
  329. static isc_result_t
  330. checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
  331. const cfg_obj_t *voptions, const cfg_obj_t *config,
  332. isc_log_t *logctx, isc_mem_t *mctx)
  333. {
  334. isc_result_t result;
  335. const cfg_obj_t *aclobj = NULL;
  336. const cfg_obj_t *options;
  337. dns_acl_t *acl = NULL;
  338. if (zconfig != NULL) {
  339. options = cfg_tuple_get(zconfig, "options");
  340. cfg_map_get(options, aclname, &aclobj);
  341. }
  342. if (voptions != NULL && aclobj == NULL)
  343. cfg_map_get(voptions, aclname, &aclobj);
  344. if (config != NULL && aclobj == NULL) {
  345. options = NULL;
  346. cfg_map_get(config, "options", &options);
  347. if (options != NULL)
  348. cfg_map_get(options, aclname, &aclobj);
  349. }
  350. if (aclobj == NULL)
  351. return (ISC_R_SUCCESS);
  352. result = cfg_acl_fromconfig(aclobj, config, logctx,
  353. actx, mctx, 0, &acl);
  354. if (acl != NULL)
  355. dns_acl_detach(&acl);
  356. return (result);
  357. }
  358. static isc_result_t
  359. check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  360. const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
  361. {
  362. isc_result_t result = ISC_R_SUCCESS, tresult;
  363. int i = 0;
  364. static const char *acls[] = { "allow-query", "allow-query-on",
  365. "allow-query-cache", "allow-query-cache-on",
  366. "blackhole", "match-clients", "match-destinations",
  367. "sortlist", "filter-aaaa", NULL };
  368. while (acls[i] != NULL) {
  369. tresult = checkacl(acls[i++], actx, NULL, voptions, config,
  370. logctx, mctx);
  371. if (tresult != ISC_R_SUCCESS)
  372. result = tresult;
  373. }
  374. return (result);
  375. }
  376. static const unsigned char zeros[16];
  377. static isc_result_t
  378. check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  379. const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
  380. {
  381. isc_result_t result = ISC_R_SUCCESS;
  382. const cfg_obj_t *dns64 = NULL;
  383. const cfg_obj_t *options;
  384. const cfg_listelt_t *element;
  385. const cfg_obj_t *map, *obj;
  386. isc_netaddr_t na, sa;
  387. unsigned int prefixlen;
  388. int nbytes;
  389. int i;
  390. static const char *acls[] = { "clients", "exclude", "mapped", NULL};
  391. if (voptions != NULL)
  392. cfg_map_get(voptions, "dns64", &dns64);
  393. if (config != NULL && dns64 == NULL) {
  394. options = NULL;
  395. cfg_map_get(config, "options", &options);
  396. if (options != NULL)
  397. cfg_map_get(options, "dns64", &dns64);
  398. }
  399. if (dns64 == NULL)
  400. return (ISC_R_SUCCESS);
  401. for (element = cfg_list_first(dns64);
  402. element != NULL;
  403. element = cfg_list_next(element))
  404. {
  405. map = cfg_listelt_value(element);
  406. obj = cfg_map_getname(map);
  407. cfg_obj_asnetprefix(obj, &na, &prefixlen);
  408. if (na.family != AF_INET6) {
  409. cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  410. "dns64 requires a IPv6 prefix");
  411. result = ISC_R_FAILURE;
  412. continue;
  413. }
  414. if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
  415. prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
  416. cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  417. "bad prefix length %u [32/40/48/56/64/96]",
  418. prefixlen);
  419. result = ISC_R_FAILURE;
  420. continue;
  421. }
  422. for (i = 0; acls[i] != NULL; i++) {
  423. obj = NULL;
  424. (void)cfg_map_get(map, acls[i], &obj);
  425. if (obj != NULL) {
  426. dns_acl_t *acl = NULL;
  427. isc_result_t tresult;
  428. tresult = cfg_acl_fromconfig(obj, config,
  429. logctx, actx,
  430. mctx, 0, &acl);
  431. if (acl != NULL)
  432. dns_acl_detach(&acl);
  433. if (tresult != ISC_R_SUCCESS)
  434. result = tresult;
  435. }
  436. }
  437. obj = NULL;
  438. (void)cfg_map_get(map, "suffix", &obj);
  439. if (obj != NULL) {
  440. isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
  441. if (sa.family != AF_INET6) {
  442. cfg_obj_log(map, logctx, ISC_LOG_ERROR,
  443. "dns64 requires a IPv6 suffix");
  444. result = ISC_R_FAILURE;
  445. continue;
  446. }
  447. nbytes = prefixlen / 8 + 4;
  448. if (prefixlen >= 32 && prefixlen <= 64)
  449. nbytes++;
  450. if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
  451. char netaddrbuf[ISC_NETADDR_FORMATSIZE];
  452. isc_netaddr_format(&sa, netaddrbuf,
  453. sizeof(netaddrbuf));
  454. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  455. "bad suffix '%s' leading "
  456. "%u octets not zeros",
  457. netaddrbuf, nbytes);
  458. result = ISC_R_FAILURE;
  459. }
  460. }
  461. }
  462. return (result);
  463. }
  464. /*
  465. * Check allow-recursion and allow-recursion-on acls, and also log a
  466. * warning if they're inconsistent with the "recursion" option.
  467. */
  468. static isc_result_t
  469. check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  470. const char *viewname, const cfg_obj_t *config,
  471. isc_log_t *logctx, isc_mem_t *mctx)
  472. {
  473. const cfg_obj_t *options, *aclobj, *obj = NULL;
  474. dns_acl_t *acl = NULL;
  475. isc_result_t result = ISC_R_SUCCESS, tresult;
  476. isc_boolean_t recursion;
  477. const char *forview = " for view ";
  478. int i = 0;
  479. static const char *acls[] = { "allow-recursion", "allow-recursion-on",
  480. NULL };
  481. if (voptions != NULL)
  482. cfg_map_get(voptions, "recursion", &obj);
  483. if (obj == NULL && config != NULL) {
  484. options = NULL;
  485. cfg_map_get(config, "options", &options);
  486. if (options != NULL)
  487. cfg_map_get(options, "recursion", &obj);
  488. }
  489. if (obj == NULL)
  490. recursion = ISC_TRUE;
  491. else
  492. recursion = cfg_obj_asboolean(obj);
  493. if (viewname == NULL) {
  494. viewname = "";
  495. forview = "";
  496. }
  497. for (i = 0; acls[i] != NULL; i++) {
  498. aclobj = options = NULL;
  499. acl = NULL;
  500. if (voptions != NULL)
  501. cfg_map_get(voptions, acls[i], &aclobj);
  502. if (config != NULL && aclobj == NULL) {
  503. options = NULL;
  504. cfg_map_get(config, "options", &options);
  505. if (options != NULL)
  506. cfg_map_get(options, acls[i], &aclobj);
  507. }
  508. if (aclobj == NULL)
  509. continue;
  510. tresult = cfg_acl_fromconfig(aclobj, config, logctx,
  511. actx, mctx, 0, &acl);
  512. if (tresult != ISC_R_SUCCESS)
  513. result = tresult;
  514. if (acl == NULL)
  515. continue;
  516. if (recursion == ISC_FALSE && !dns_acl_isnone(acl)) {
  517. cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  518. "both \"recursion no;\" and "
  519. "\"%s\" active%s%s",
  520. acls[i], forview, viewname);
  521. }
  522. if (acl != NULL)
  523. dns_acl_detach(&acl);
  524. }
  525. return (result);
  526. }
  527. static isc_result_t
  528. check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
  529. const char *viewname, const cfg_obj_t *config,
  530. isc_log_t *logctx, isc_mem_t *mctx)
  531. {
  532. const cfg_obj_t *options, *aclobj, *obj = NULL;
  533. dns_acl_t *acl = NULL;
  534. isc_result_t result = ISC_R_SUCCESS, tresult;
  535. dns_v4_aaaa_t filter;
  536. const char *forview = " for view ";
  537. if (voptions != NULL)
  538. cfg_map_get(voptions, "filter-aaaa-on-v4", &obj);
  539. if (obj == NULL && config != NULL) {
  540. options = NULL;
  541. cfg_map_get(config, "options", &options);
  542. if (options != NULL)
  543. cfg_map_get(options, "filter-aaaa-on-v4", &obj);
  544. }
  545. if (obj == NULL)
  546. filter = dns_v4_aaaa_ok; /* default */
  547. else if (cfg_obj_isboolean(obj))
  548. filter = cfg_obj_asboolean(obj) ? dns_v4_aaaa_filter :
  549. dns_v4_aaaa_ok;
  550. else
  551. filter = dns_v4_aaaa_break_dnssec; /* break-dnssec */
  552. if (viewname == NULL) {
  553. viewname = "";
  554. forview = "";
  555. }
  556. aclobj = options = NULL;
  557. acl = NULL;
  558. if (voptions != NULL)
  559. cfg_map_get(voptions, "filter-aaaa", &aclobj);
  560. if (config != NULL && aclobj == NULL) {
  561. options = NULL;
  562. cfg_map_get(config, "options", &options);
  563. if (options != NULL)
  564. cfg_map_get(options, "filter-aaaa", &aclobj);
  565. }
  566. if (aclobj == NULL)
  567. return (result);
  568. tresult = cfg_acl_fromconfig(aclobj, config, logctx,
  569. actx, mctx, 0, &acl);
  570. if (tresult != ISC_R_SUCCESS) {
  571. result = tresult;
  572. } else if (filter != dns_v4_aaaa_ok && dns_acl_isnone(acl)) {
  573. cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  574. "both \"filter-aaaa-on-v4 %s;\" and "
  575. "\"filter-aaaa\" is 'none;'%s%s",
  576. filter == dns_v4_aaaa_break_dnssec ?
  577. "break-dnssec" : "yes", forview, viewname);
  578. result = ISC_R_FAILURE;
  579. } else if (filter == dns_v4_aaaa_ok && !dns_acl_isnone(acl)) {
  580. cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
  581. "both \"filter-aaaa-on-v4 no;\" and "
  582. "\"filter-aaaa\" is set%s%s", forview, viewname);
  583. result = ISC_R_FAILURE;
  584. }
  585. if (acl != NULL)
  586. dns_acl_detach(&acl);
  587. return (result);
  588. }
  589. typedef struct {
  590. const char *name;
  591. unsigned int scale;
  592. unsigned int max;
  593. } intervaltable;
  594. typedef enum {
  595. optlevel_config,
  596. optlevel_options,
  597. optlevel_view,
  598. optlevel_zone
  599. } optlevel_t;
  600. static isc_result_t
  601. check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
  602. optlevel_t optlevel)
  603. {
  604. isc_result_t result = ISC_R_SUCCESS;
  605. isc_result_t tresult;
  606. unsigned int i;
  607. const cfg_obj_t *obj = NULL;
  608. const cfg_obj_t *resignobj = NULL;
  609. const cfg_listelt_t *element;
  610. isc_symtab_t *symtab = NULL;
  611. dns_fixedname_t fixed;
  612. const char *str;
  613. dns_name_t *name;
  614. isc_buffer_t b;
  615. static intervaltable intervals[] = {
  616. { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
  617. { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
  618. { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
  619. { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
  620. { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
  621. { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
  622. { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
  623. { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
  624. };
  625. static const char *server_contact[] = {
  626. "empty-server", "empty-contact",
  627. "dns64-server", "dns64-contact",
  628. NULL
  629. };
  630. /*
  631. * Check that fields specified in units of time other than seconds
  632. * have reasonable values.
  633. */
  634. for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
  635. isc_uint32_t val;
  636. obj = NULL;
  637. (void)cfg_map_get(options, intervals[i].name, &obj);
  638. if (obj == NULL)
  639. continue;
  640. val = cfg_obj_asuint32(obj);
  641. if (val > intervals[i].max) {
  642. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  643. "%s '%u' is out of range (0..%u)",
  644. intervals[i].name, val,
  645. intervals[i].max);
  646. result = ISC_R_RANGE;
  647. } else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
  648. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  649. "%s '%d' is out of range",
  650. intervals[i].name, val);
  651. result = ISC_R_RANGE;
  652. }
  653. }
  654. obj = NULL;
  655. cfg_map_get(options, "sig-validity-interval", &obj);
  656. if (obj != NULL) {
  657. isc_uint32_t validity, resign = 0;
  658. validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
  659. resignobj = cfg_tuple_get(obj, "re-sign");
  660. if (!cfg_obj_isvoid(resignobj))
  661. resign = cfg_obj_asuint32(resignobj);
  662. if (validity > 3660 || validity == 0) { /* 10 years */
  663. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  664. "%s '%u' is out of range (1..3660)",
  665. "sig-validity-interval", validity);
  666. result = ISC_R_RANGE;
  667. }
  668. if (!cfg_obj_isvoid(resignobj)) {
  669. if (resign > 3660 || resign == 0) { /* 10 years */
  670. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  671. "%s '%u' is out of range (1..3660)",
  672. "sig-validity-interval (re-sign)",
  673. validity);
  674. result = ISC_R_RANGE;
  675. } else if ((validity > 7 && validity < resign) ||
  676. (validity <= 7 && validity * 24 < resign)) {
  677. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  678. "validity interval (%u days) "
  679. "less than re-signing interval "
  680. "(%u %s)", validity, resign,
  681. (validity > 7) ? "days" : "hours");
  682. result = ISC_R_RANGE;
  683. }
  684. }
  685. }
  686. obj = NULL;
  687. (void)cfg_map_get(options, "preferred-glue", &obj);
  688. if (obj != NULL) {
  689. const char *str;
  690. str = cfg_obj_asstring(obj);
  691. if (strcasecmp(str, "a") != 0 &&
  692. strcasecmp(str, "aaaa") != 0 &&
  693. strcasecmp(str, "none") != 0)
  694. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  695. "preferred-glue unexpected value '%s'",
  696. str);
  697. }
  698. obj = NULL;
  699. (void)cfg_map_get(options, "root-delegation-only", &obj);
  700. if (obj != NULL) {
  701. if (!cfg_obj_isvoid(obj)) {
  702. const cfg_listelt_t *element;
  703. const cfg_obj_t *exclude;
  704. const char *str;
  705. dns_fixedname_t fixed;
  706. dns_name_t *name;
  707. isc_buffer_t b;
  708. dns_fixedname_init(&fixed);
  709. name = dns_fixedname_name(&fixed);
  710. for (element = cfg_list_first(obj);
  711. element != NULL;
  712. element = cfg_list_next(element)) {
  713. exclude = cfg_listelt_value(element);
  714. str = cfg_obj_asstring(exclude);
  715. isc_buffer_init(&b, str, strlen(str));
  716. isc_buffer_add(&b, strlen(str));
  717. tresult = dns_name_fromtext(name, &b,
  718. dns_rootname,
  719. 0, NULL);
  720. if (tresult != ISC_R_SUCCESS) {
  721. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  722. "bad domain name '%s'",
  723. str);
  724. result = tresult;
  725. }
  726. }
  727. }
  728. }
  729. /*
  730. * Set supported DNSSEC algorithms.
  731. */
  732. obj = NULL;
  733. (void)cfg_map_get(options, "disable-algorithms", &obj);
  734. if (obj != NULL) {
  735. for (element = cfg_list_first(obj);
  736. element != NULL;
  737. element = cfg_list_next(element))
  738. {
  739. obj = cfg_listelt_value(element);
  740. tresult = disabled_algorithms(obj, logctx);
  741. if (tresult != ISC_R_SUCCESS)
  742. result = tresult;
  743. }
  744. }
  745. dns_fixedname_init(&fixed);
  746. name = dns_fixedname_name(&fixed);
  747. /*
  748. * Check the DLV zone name.
  749. */
  750. obj = NULL;
  751. (void)cfg_map_get(options, "dnssec-lookaside", &obj);
  752. if (obj != NULL) {
  753. tresult = isc_symtab_create(mctx, 100, freekey, mctx,
  754. ISC_FALSE, &symtab);
  755. if (tresult != ISC_R_SUCCESS)
  756. result = tresult;
  757. for (element = cfg_list_first(obj);
  758. element != NULL;
  759. element = cfg_list_next(element))
  760. {
  761. const char *dlv;
  762. const cfg_obj_t *dlvobj, *anchor;
  763. obj = cfg_listelt_value(element);
  764. anchor = cfg_tuple_get(obj, "trust-anchor");
  765. dlvobj = cfg_tuple_get(obj, "domain");
  766. dlv = cfg_obj_asstring(dlvobj);
  767. /*
  768. * If domain is "auto" or "no" and trust anchor
  769. * is missing, skip remaining tests
  770. */
  771. if (cfg_obj_isvoid(anchor)) {
  772. if (!strcasecmp(dlv, "no") ||
  773. !strcasecmp(dlv, "auto"))
  774. continue;
  775. }
  776. isc_buffer_init(&b, dlv, strlen(dlv));
  777. isc_buffer_add(&b, strlen(dlv));
  778. tresult = dns_name_fromtext(name, &b, dns_rootname,
  779. 0, NULL);
  780. if (tresult != ISC_R_SUCCESS) {
  781. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  782. "bad domain name '%s'", dlv);
  783. result = tresult;
  784. continue;
  785. }
  786. if (symtab != NULL) {
  787. tresult = nameexist(obj, dlv, 1, symtab,
  788. "dnssec-lookaside '%s': "
  789. "already exists previous "
  790. "definition: %s:%u",
  791. logctx, mctx);
  792. if (tresult != ISC_R_SUCCESS &&
  793. result == ISC_R_SUCCESS)
  794. result = tresult;
  795. }
  796. /*
  797. * XXXMPA to be removed when multiple lookaside
  798. * namespaces are supported.
  799. */
  800. if (!dns_name_equal(dns_rootname, name)) {
  801. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  802. "dnssec-lookaside '%s': "
  803. "non-root not yet supported", dlv);
  804. if (result == ISC_R_SUCCESS)
  805. result = ISC_R_FAILURE;
  806. }
  807. if (!cfg_obj_isvoid(anchor)) {
  808. dlv = cfg_obj_asstring(anchor);
  809. isc_buffer_init(&b, dlv, strlen(dlv));
  810. isc_buffer_add(&b, strlen(dlv));
  811. tresult = dns_name_fromtext(name, &b,
  812. dns_rootname,
  813. DNS_NAME_DOWNCASE,
  814. NULL);
  815. if (tresult != ISC_R_SUCCESS) {
  816. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  817. "bad domain name '%s'",
  818. dlv);
  819. if (result == ISC_R_SUCCESS)
  820. result = tresult;
  821. }
  822. } else {
  823. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  824. "dnssec-lookaside requires "
  825. "either 'auto' or 'no', or a "
  826. "domain and trust anchor");
  827. if (result == ISC_R_SUCCESS)
  828. result = ISC_R_FAILURE;
  829. }
  830. }
  831. if (symtab != NULL)
  832. isc_symtab_destroy(&symtab);
  833. }
  834. /*
  835. * Check auto-dnssec at the view/options level
  836. */
  837. obj = NULL;
  838. (void)cfg_map_get(options, "auto-dnssec", &obj);
  839. if (obj != NULL) {
  840. const char *arg = cfg_obj_asstring(obj);
  841. if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
  842. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  843. "auto-dnssec may only be activated at the "
  844. "zone level");
  845. result = ISC_R_FAILURE;
  846. }
  847. }
  848. /*
  849. * Check dnssec-must-be-secure.
  850. */
  851. obj = NULL;
  852. (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
  853. if (obj != NULL) {
  854. isc_symtab_t *symtab = NULL;
  855. tresult = isc_symtab_create(mctx, 100, freekey, mctx,
  856. ISC_FALSE, &symtab);
  857. if (tresult != ISC_R_SUCCESS)
  858. result = tresult;
  859. for (element = cfg_list_first(obj);
  860. element != NULL;
  861. element = cfg_list_next(element))
  862. {
  863. obj = cfg_listelt_value(element);
  864. tresult = mustbesecure(obj, symtab, logctx, mctx);
  865. if (tresult != ISC_R_SUCCESS)
  866. result = tresult;
  867. }
  868. if (symtab != NULL)
  869. isc_symtab_destroy(&symtab);
  870. }
  871. /*
  872. * Check server/contacts for syntactic validity.
  873. */
  874. for (i= 0; server_contact[i] != NULL; i++) {
  875. obj = NULL;
  876. (void)cfg_map_get(options, server_contact[i], &obj);
  877. if (obj != NULL) {
  878. str = cfg_obj_asstring(obj);
  879. isc_buffer_init(&b, str, strlen(str));
  880. isc_buffer_add(&b, strlen(str));
  881. tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
  882. &b, dns_rootname, 0, NULL);
  883. if (tresult != ISC_R_SUCCESS) {
  884. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  885. "%s: invalid name '%s'",
  886. server_contact[i], str);
  887. result = ISC_R_FAILURE;
  888. }
  889. }
  890. }
  891. /*
  892. * Check empty zone configuration.
  893. */
  894. obj = NULL;
  895. (void)cfg_map_get(options, "disable-empty-zone", &obj);
  896. for (element = cfg_list_first(obj);
  897. element != NULL;
  898. element = cfg_list_next(element))
  899. {
  900. obj = cfg_listelt_value(element);
  901. str = cfg_obj_asstring(obj);
  902. isc_buffer_init(&b, str, strlen(str));
  903. isc_buffer_add(&b, strlen(str));
  904. tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
  905. dns_rootname, 0, NULL);
  906. if (tresult != ISC_R_SUCCESS) {
  907. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  908. "disable-empty-zone: invalid name '%s'",
  909. str);
  910. result = ISC_R_FAILURE;
  911. }
  912. }
  913. /*
  914. * Check that server-id is not too long.
  915. * 1024 bytes should be big enough.
  916. */
  917. obj = NULL;
  918. (void)cfg_map_get(options, "server-id", &obj);
  919. if (obj != NULL && cfg_obj_isstring(obj) &&
  920. strlen(cfg_obj_asstring(obj)) > 1024U) {
  921. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  922. "'server-id' too big (>1024 bytes)");
  923. result = ISC_R_FAILURE;
  924. }
  925. return (result);
  926. }
  927. static isc_result_t
  928. get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
  929. isc_result_t result;
  930. const cfg_obj_t *masters = NULL;
  931. const cfg_listelt_t *elt;
  932. result = cfg_map_get(cctx, "masters", &masters);
  933. if (result != ISC_R_SUCCESS)
  934. return (result);
  935. for (elt = cfg_list_first(masters);
  936. elt != NULL;
  937. elt = cfg_list_next(elt)) {
  938. const cfg_obj_t *list;
  939. const char *listname;
  940. list = cfg_listelt_value(elt);
  941. listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
  942. if (strcasecmp(listname, name) == 0) {
  943. *ret = list;
  944. return (ISC_R_SUCCESS);
  945. }
  946. }
  947. return (ISC_R_NOTFOUND);
  948. }
  949. static isc_result_t
  950. validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
  951. isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
  952. {
  953. isc_result_t result = ISC_R_SUCCESS;
  954. isc_result_t tresult;
  955. isc_uint32_t count = 0;
  956. isc_symtab_t *symtab = NULL;
  957. isc_symvalue_t symvalue;
  958. const cfg_listelt_t *element;
  959. const cfg_listelt_t **stack = NULL;
  960. isc_uint32_t stackcount = 0, pushed = 0;
  961. const cfg_obj_t *list;
  962. REQUIRE(countp != NULL);
  963. result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
  964. if (result != ISC_R_SUCCESS) {
  965. *countp = count;
  966. return (result);
  967. }
  968. newlist:
  969. list = cfg_tuple_get(obj, "addresses");
  970. element = cfg_list_first(list);
  971. resume:
  972. for ( ;
  973. element != NULL;
  974. element = cfg_list_next(element))
  975. {
  976. const char *listname;
  977. const cfg_obj_t *addr;
  978. const cfg_obj_t *key;
  979. addr = cfg_tuple_get(cfg_listelt_value(element),
  980. "masterselement");
  981. key = cfg_tuple_get(cfg_listelt_value(element), "key");
  982. if (cfg_obj_issockaddr(addr)) {
  983. count++;
  984. continue;
  985. }
  986. if (!cfg_obj_isvoid(key)) {
  987. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  988. "unexpected token '%s'",
  989. cfg_obj_asstring(key));
  990. if (result == ISC_R_SUCCESS)
  991. result = ISC_R_FAILURE;
  992. }
  993. listname = cfg_obj_asstring(addr);
  994. symvalue.as_cpointer = addr;
  995. tresult = isc_symtab_define(symtab, listname, 1, symvalue,
  996. isc_symexists_reject);
  997. if (tresult == ISC_R_EXISTS)
  998. continue;
  999. tresult = get_masters_def(config, listname, &obj);
  1000. if (tresult != ISC_R_SUCCESS) {
  1001. if (result == ISC_R_SUCCESS)
  1002. result = tresult;
  1003. cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
  1004. "unable to find masters list '%s'",
  1005. listname);
  1006. continue;
  1007. }
  1008. /* Grow stack? */
  1009. if (stackcount == pushed) {
  1010. void * new;
  1011. isc_uint32_t newlen = stackcount + 16;
  1012. size_t newsize, oldsize;
  1013. newsize = newlen * sizeof(*stack);
  1014. oldsize = stackcount * sizeof(*stack);
  1015. new = isc_mem_get(mctx, newsize);
  1016. if (new == NULL)
  1017. goto cleanup;
  1018. if (stackcount != 0) {
  1019. void *ptr;
  1020. DE_CONST(stack, ptr);
  1021. memcpy(new, stack, oldsize);
  1022. isc_mem_put(mctx, ptr, oldsize);
  1023. }
  1024. stack = new;
  1025. stackcount = newlen;
  1026. }
  1027. stack[pushed++] = cfg_list_next(element);
  1028. goto newlist;
  1029. }
  1030. if (pushed != 0) {
  1031. element = stack[--pushed];
  1032. goto resume;
  1033. }
  1034. cleanup:
  1035. if (stack != NULL) {
  1036. void *ptr;
  1037. DE_CONST(stack, ptr);
  1038. isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
  1039. }
  1040. isc_symtab_destroy(&symtab);
  1041. *countp = count;
  1042. return (result);
  1043. }
  1044. static isc_result_t
  1045. check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
  1046. isc_result_t result = ISC_R_SUCCESS;
  1047. isc_result_t tresult;
  1048. const cfg_listelt_t *element;
  1049. const cfg_listelt_t *element2;
  1050. dns_fixedname_t fixed;
  1051. const char *str;
  1052. isc_buffer_t b;
  1053. /* Check for "update-policy local;" */
  1054. if (cfg_obj_isstring(policy) &&
  1055. strcmp("local", cfg_obj_asstring(policy)) == 0)
  1056. return (ISC_R_SUCCESS);
  1057. /* Now check the grant policy */
  1058. for (element = cfg_list_first(policy);
  1059. element != NULL;
  1060. element = cfg_list_next(element))
  1061. {
  1062. const cfg_obj_t *stmt = cfg_listelt_value(element);
  1063. const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
  1064. const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
  1065. const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
  1066. const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
  1067. dns_fixedname_init(&fixed);
  1068. str = cfg_obj_asstring(identity);
  1069. isc_buffer_init(&b, str, strlen(str));
  1070. isc_buffer_add(&b, strlen(str));
  1071. tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
  1072. dns_rootname, 0, NULL);
  1073. if (tresult != ISC_R_SUCCESS) {
  1074. cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
  1075. "'%s' is not a valid name", str);
  1076. result = tresult;
  1077. }
  1078. if (tresult == ISC_R_SUCCESS &&
  1079. strcasecmp(cfg_obj_asstring(matchtype), "zonesub") != 0) {
  1080. dns_fixedname_init(&fixed);
  1081. str = cfg_obj_asstring(dname);
  1082. isc_buffer_init(&b, str, strlen(str));
  1083. isc_buffer_add(&b, strlen(str));
  1084. tresult = dns_name_fromtext(dns_fixedname_name(&fixed),
  1085. &b, dns_rootname, 0, NULL);
  1086. if (tresult != ISC_R_SUCCESS) {
  1087. cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
  1088. "'%s' is not a valid name", str);
  1089. result = tresult;
  1090. }
  1091. }
  1092. if (tresult == ISC_R_SUCCESS &&
  1093. strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
  1094. !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
  1095. cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
  1096. "'%s' is not a wildcard", str);
  1097. result = ISC_R_FAILURE;
  1098. }
  1099. for (element2 = cfg_list_first(typelist);
  1100. element2 != NULL;
  1101. element2 = cfg_list_next(element2))
  1102. {
  1103. const cfg_obj_t *typeobj;
  1104. isc_textregion_t r;
  1105. dns_rdatatype_t type;
  1106. typeobj = cfg_listelt_value(element2);
  1107. DE_CONST(cfg_obj_asstring(typeobj), r.base);
  1108. r.length = strlen(r.base);
  1109. tresult = dns_rdatatype_fromtext(&type, &r);
  1110. if (tresult != ISC_R_SUCCESS) {
  1111. cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
  1112. "'%s' is not a valid type", r.base);
  1113. result = tresult;
  1114. }
  1115. }
  1116. }
  1117. return (result);
  1118. }
  1119. #define MASTERZONE 1
  1120. #define SLAVEZONE 2
  1121. #define STUBZONE 4
  1122. #define HINTZONE 8
  1123. #define FORWARDZONE 16
  1124. #define DELEGATIONZONE 32
  1125. #define STATICSTUBZONE 64
  1126. #define CHECKACL 128
  1127. typedef struct {
  1128. const char *name;
  1129. int allowed;
  1130. } optionstable;
  1131. static isc_result_t
  1132. check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
  1133. const cfg_obj_t *config, isc_symtab_t *symtab,
  1134. dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
  1135. isc_log_t *logctx, isc_mem_t *mctx)
  1136. {
  1137. const char *znamestr;
  1138. const char *typestr;
  1139. unsigned int ztype;
  1140. const cfg_obj_t *zoptions;
  1141. const cfg_obj_t *obj = NULL;
  1142. isc_result_t result = ISC_R_SUCCESS;
  1143. isc_result_t tresult;
  1144. unsigned int i;
  1145. dns_rdataclass_t zclass;
  1146. dns_fixedname_t fixedname;
  1147. dns_name_t *zname = NULL;
  1148. isc_buffer_t b;
  1149. isc_boolean_t root = ISC_FALSE;
  1150. const cfg_listelt_t *element;
  1151. static optionstable options[] = {
  1152. { "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL |
  1153. STATICSTUBZONE },
  1154. { "allow-notify", SLAVEZONE | CHECKACL },
  1155. { "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
  1156. { "notify", MASTERZONE | SLAVEZONE },
  1157. { "also-notify", MASTERZONE | SLAVEZONE },
  1158. { "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
  1159. { "delegation-only", HINTZONE | STUBZONE | DELEGATIONZONE },
  1160. { "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
  1161. { "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE },
  1162. { "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
  1163. { "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
  1164. { "notify-source", MASTERZONE | SLAVEZONE },
  1165. { "notify-source-v6", MASTERZONE | SLAVEZONE },
  1166. { "transfer-source", SLAVEZONE | STUBZONE },
  1167. { "transfer-source-v6", SLAVEZONE | STUBZONE },
  1168. { "max-transfer-time-in", SLAVEZONE | STUBZONE },
  1169. { "max-transfer-time-out", MASTERZONE | SLAVEZONE },
  1170. { "max-transfer-idle-in", SLAVEZONE | STUBZONE },
  1171. { "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
  1172. { "max-retry-time", SLAVEZONE | STUBZONE },
  1173. { "min-retry-time", SLAVEZONE | STUBZONE },
  1174. { "max-refresh-time", SLAVEZONE | STUBZONE },
  1175. { "min-refresh-time", SLAVEZONE | STUBZONE },
  1176. { "dnssec-secure-to-insecure", MASTERZONE },
  1177. { "sig-validity-interval", MASTERZONE },
  1178. { "sig-re-signing-interval", MASTERZONE },
  1179. { "sig-signing-nodes", MASTERZONE },
  1180. { "sig-signing-type", MASTERZONE },
  1181. { "sig-signing-signatures", MASTERZONE },
  1182. { "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
  1183. STATICSTUBZONE},
  1184. { "allow-update", MASTERZONE | CHECKACL },
  1185. { "allow-update-forwarding", SLAVEZONE | CHECKACL },
  1186. { "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
  1187. { "journal", MASTERZONE | SLAVEZONE },
  1188. { "ixfr-base", MASTERZONE | SLAVEZONE },
  1189. { "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
  1190. { "masters", SLAVEZONE | STUBZONE },
  1191. { "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
  1192. { "update-policy", MASTERZONE },
  1193. { "database", MASTERZONE | SLAVEZONE | STUBZONE },
  1194. { "key-directory", MASTERZONE },
  1195. { "check-wildcard", MASTERZONE },
  1196. { "check-mx", MASTERZONE },
  1197. { "check-dup-records", MASTERZONE },
  1198. { "integrity-check", MASTERZONE },
  1199. { "check-mx-cname", MASTERZONE },
  1200. { "check-srv-cname", MASTERZONE },
  1201. { "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
  1202. { "update-check-ksk", MASTERZONE },
  1203. { "dnssec-dnskey-kskonly", MASTERZONE },
  1204. { "auto-dnssec", MASTERZONE },
  1205. { "try-tcp-refresh", SLAVEZONE },
  1206. { "server-addresses", STATICSTUBZONE },
  1207. { "server-names", STATICSTUBZONE },
  1208. };
  1209. static optionstable dialups[] = {
  1210. { "notify", MASTERZONE | SLAVEZONE },
  1211. { "notify-passive", SLAVEZONE },
  1212. { "refresh", SLAVEZONE | STUBZONE },
  1213. { "passive", SLAVEZONE | STUBZONE },
  1214. };
  1215. znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
  1216. zoptions = cfg_tuple_get(zconfig, "options");
  1217. obj = NULL;
  1218. (void)cfg_map_get(zoptions, "type", &obj);
  1219. if (obj == NULL) {
  1220. cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
  1221. "zone '%s': type not present", znamestr);
  1222. return (ISC_R_FAILURE);
  1223. }
  1224. typestr = cfg_obj_asstring(obj);
  1225. if (strcasecmp(typestr, "master") == 0)
  1226. ztype = MASTERZONE;
  1227. else if (strcasecmp(typestr, "slave") == 0)
  1228. ztype = SLAVEZONE;
  1229. else if (strcasecmp(typestr, "stub") == 0)
  1230. ztype = STUBZONE;
  1231. else if (strcasecmp(typestr, "static-stub") == 0)
  1232. ztype = STATICSTUBZONE;
  1233. else if (strcasecmp(typestr, "forward") == 0)
  1234. ztype = FORWARDZONE;
  1235. else if (strcasecmp(typestr, "hint") == 0)
  1236. ztype = HINTZONE;
  1237. else if (strcasecmp(typestr, "delegation-only") == 0)
  1238. ztype = DELEGATIONZONE;
  1239. else {
  1240. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1241. "zone '%s': invalid type %s",
  1242. znamestr, typestr);
  1243. return (ISC_R_FAILURE);
  1244. }
  1245. obj = cfg_tuple_get(zconfig, "class");
  1246. if (cfg_obj_isstring(obj)) {
  1247. isc_textregion_t r;
  1248. DE_CONST(cfg_obj_asstring(obj), r.base);
  1249. r.length = strlen(r.base);
  1250. result = dns_rdataclass_fromtext(&zclass, &r);
  1251. if (result != ISC_R_SUCCESS) {
  1252. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1253. "zone '%s': invalid class %s",
  1254. znamestr, r.base);
  1255. return (ISC_R_FAILURE);
  1256. }
  1257. if (zclass != defclass) {
  1258. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1259. "zone '%s': class '%s' does not "
  1260. "match view/default class",
  1261. znamestr, r.base);
  1262. return (ISC_R_FAILURE);
  1263. }
  1264. }
  1265. /*
  1266. * Look for an already existing zone.
  1267. * We need to make this canonical as isc_symtab_define()
  1268. * deals with strings.
  1269. */
  1270. dns_fixedname_init(&fixedname);
  1271. isc_buffer_init(&b, znamestr, strlen(znamestr));
  1272. isc_buffer_add(&b, strlen(znamestr));
  1273. tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
  1274. dns_rootname, DNS_NAME_DOWNCASE, NULL);
  1275. if (tresult != ISC_R_SUCCESS) {
  1276. cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
  1277. "zone '%s': is not a valid name", znamestr);
  1278. result = ISC_R_FAILURE;
  1279. } else {
  1280. char namebuf[DNS_NAME_FORMATSIZE];
  1281. zname = dns_fixedname_name(&fixedname);
  1282. dns_name_format(zname, namebuf, sizeof(namebuf));
  1283. tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
  1284. symtab, "zone '%s': already exists "
  1285. "previous definition: %s:%u", logctx, mctx);
  1286. if (tresult != ISC_R_SUCCESS)
  1287. result = tresult;
  1288. if (dns_name_equal(zname, dns_rootname))
  1289. root = ISC_TRUE;
  1290. }
  1291. /*
  1292. * Look for inappropriate options for the given zone type.
  1293. * Check that ACLs expand correctly.
  1294. */
  1295. for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
  1296. obj = NULL;
  1297. if ((options[i].allowed & ztype) == 0 &&
  1298. cfg_map_get(zoptions, options[i].name, &obj) ==
  1299. ISC_R_SUCCESS)
  1300. {
  1301. if (strcmp(options[i].name, "allow-update") != 0 ||
  1302. ztype != SLAVEZONE) {
  1303. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1304. "option '%s' is not allowed "
  1305. "in '%s' zone '%s'",
  1306. options[i].name, typestr,
  1307. znamestr);
  1308. result = ISC_R_FAILURE;
  1309. } else
  1310. cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
  1311. "option '%s' is not allowed "
  1312. "in '%s' zone '%s'",
  1313. options[i].name, typestr,
  1314. znamestr);
  1315. }
  1316. obj = NULL;
  1317. if ((options[i].allowed & ztype) != 0 &&
  1318. (options[i].allowed & CHECKACL) != 0) {
  1319. tresult = checkacl(options[i].name, actx, zconfig,
  1320. voptions, config, logctx, mctx);
  1321. if (tresult != ISC_R_SUCCESS)
  1322. result = tresult;
  1323. }
  1324. }
  1325. /*
  1326. * Slave & stub zones must have a "masters" field.
  1327. */
  1328. if (ztype == SLAVEZONE || ztype == STUBZONE) {
  1329. obj = NULL;
  1330. if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
  1331. cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
  1332. "zone '%s': missing 'masters' entry",
  1333. znamestr);
  1334. result = ISC_R_FAILURE;
  1335. } else {
  1336. isc_uint32_t count;
  1337. tresult = validate_masters(obj, config, &count,
  1338. logctx, mctx);
  1339. if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
  1340. result = tresult;
  1341. if (tresult == ISC_R_SUCCESS && count == 0) {
  1342. cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
  1343. "zone '%s': empty 'masters' entry",
  1344. znamestr);
  1345. result = ISC_R_FAILURE;
  1346. }
  1347. }
  1348. }
  1349. /*
  1350. * Master zones can't have both "allow-update" and "update-policy".
  1351. */
  1352. if (ztype == MASTERZONE) {
  1353. isc_result_t res1, res2, res3;
  1354. const char *arg;
  1355. isc_boolean_t ddns;
  1356. obj = NULL;
  1357. res1 = cfg_map_get(zoptions, "allow-update", &obj);
  1358. obj = NULL;
  1359. res2 = cfg_map_get(zoptions, "update-policy", &obj);
  1360. if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
  1361. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1362. "zone '%s': 'allow-update' is ignored "
  1363. "when 'update-policy' is present",
  1364. znamestr);
  1365. result = ISC_R_FAILURE;
  1366. } else if (res2 == ISC_R_SUCCESS &&
  1367. check_update_policy(obj, logctx) != ISC_R_SUCCESS)
  1368. result = ISC_R_FAILURE;
  1369. ddns = ISC_TF(res1 == ISC_R_SUCCESS || res2 == ISC_R_SUCCESS);
  1370. obj = NULL;
  1371. arg = "off";
  1372. res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
  1373. if (res3 == ISC_R_SUCCESS)
  1374. arg = cfg_obj_asstring(obj);
  1375. if (strcasecmp(arg, "off") != 0 && !ddns) {
  1376. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1377. "'auto-dnssec %s;' requires "
  1378. "dynamic DNS to be configured in the zone",
  1379. arg);
  1380. result = ISC_R_FAILURE;
  1381. }
  1382. if (strcasecmp(arg, "create") == 0) {
  1383. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1384. "'auto-dnssec create;' is not "
  1385. "yet implemented");
  1386. result = ISC_R_FAILURE;
  1387. }
  1388. obj = NULL;
  1389. res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
  1390. if (res1 == ISC_R_SUCCESS) {
  1391. isc_uint32_t type = cfg_obj_asuint32(obj);
  1392. if (type < 0xff00U || type > 0xffffU)
  1393. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1394. "sig-signing-type: %u out of "
  1395. "range [%u..%u]", type,
  1396. 0xff00U, 0xffffU);
  1397. result = ISC_R_FAILURE;
  1398. }
  1399. }
  1400. /*
  1401. * Check the excessively complicated "dialup" option.
  1402. */
  1403. if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
  1404. const cfg_obj_t *dialup = NULL;
  1405. (void)cfg_map_get(zoptions, "dialup", &dialup);
  1406. if (dialup != NULL && cfg_obj_isstring(dialup)) {
  1407. const char *str = cfg_obj_asstring(dialup);
  1408. for (i = 0;
  1409. i < sizeof(dialups) / sizeof(dialups[0]);
  1410. i++)
  1411. {
  1412. if (strcasecmp(dialups[i].name, str) != 0)
  1413. continue;
  1414. if ((dialups[i].allowed & ztype) == 0) {
  1415. cfg_obj_log(obj, logctx,
  1416. ISC_LOG_ERROR,
  1417. "dialup type '%s' is not "
  1418. "allowed in '%s' "
  1419. "zone '%s'",
  1420. str, typestr, znamestr);
  1421. result = ISC_R_FAILURE;
  1422. }
  1423. break;
  1424. }
  1425. if (i == sizeof(dialups) / sizeof(dialups[0])) {
  1426. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1427. "invalid dialup type '%s' in zone "
  1428. "'%s'", str, znamestr);
  1429. result = ISC_R_FAILURE;
  1430. }
  1431. }
  1432. }
  1433. /*
  1434. * Check that forwarding is reasonable.
  1435. */
  1436. obj = NULL;
  1437. if (root) {
  1438. if (voptions != NULL)
  1439. (void)cfg_map_get(voptions, "forwarders", &obj);
  1440. if (obj == NULL) {
  1441. const cfg_obj_t *options = NULL;
  1442. (void)cfg_map_get(config, "options", &options);
  1443. if (options != NULL)
  1444. (void)cfg_map_get(options, "forwarders", &obj);
  1445. }
  1446. }
  1447. if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
  1448. result = ISC_R_FAILURE;
  1449. /*
  1450. * Check validity of static stub server addresses.
  1451. */
  1452. obj = NULL;
  1453. (void)cfg_map_get(zoptions, "server-addresses", &obj);
  1454. if (ztype == STATICSTUBZONE && obj != NULL) {
  1455. for (element = cfg_list_first(obj);
  1456. element != NULL;
  1457. element = cfg_list_next(element))
  1458. {
  1459. isc_sockaddr_t sa;
  1460. isc_netaddr_t na;
  1461. obj = cfg_listelt_value(element);
  1462. sa = *cfg_obj_assockaddr(obj);
  1463. if (isc_sockaddr_getport(&sa) != 0) {
  1464. result = ISC_R_FAILURE;
  1465. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1466. "port is not configurable for "
  1467. "static stub server-addresses");
  1468. }
  1469. isc_netaddr_fromsockaddr(&na, &sa);
  1470. if (isc_netaddr_getzone(&na) != 0) {
  1471. result = ISC_R_FAILURE;
  1472. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  1473. "scoped address is not allowed "
  1474. "for static stub "
  1475. "server-addresses");
  1476. }
  1477. }
  1478. }
  1479. /*
  1480. * Check validity of static stub server names.
  1481. */
  1482. obj = NULL;
  1483. (void)cfg_map_get(zoptions, "server-names", &obj);
  1484. if (zname != NULL && ztype == STATICSTUBZONE && obj != NULL) {
  1485. for (element = cfg_list_first(obj);
  1486. element != NULL;
  1487. element = cfg_list_next(element))
  1488. {
  1489. const char *snamestr;
  1490. dns_fixedname_t fixed_sname;
  1491. isc_buffer_t b2;
  1492. dns_name_t *sname;
  1493. obj = cfg_listelt_value(element);
  1494. snamestr = cfg_obj_asstring(obj);
  1495. dns_fixedname_init(&fixed_sname);
  1496. isc_buffer_init(&b2, snamestr, strlen(snamestr));
  1497. isc_buffer_add(&b2, strlen(snamestr));
  1498. sname = dns_fixedname_name(&fixed_sname);
  1499. tresult = dns_name_fromtext(sname, &b2, dns_rootname,
  1500. 0, NULL);
  1501. if (tresult != ISC_R_SUCCESS) {
  1502. cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
  1503. "server-name '%s' is not a valid "
  1504. "name", snamestr);
  1505. result = ISC_R_FAILURE;
  1506. } else if (dns_name_issubdomain(sname, zname)) {
  1507. cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
  1508. "server-name '%s' must not be a "
  1509. "subdomain of zone name '%s'",
  1510. snamestr, znamestr);
  1511. result = ISC_R_FAILURE;
  1512. }
  1513. }
  1514. }
  1515. /*
  1516. * Check various options.
  1517. */
  1518. tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
  1519. if (tresult != ISC_R_SUCCESS)
  1520. result = tresult;
  1521. /*
  1522. * If the zone type is rbt/rbt64 then master/hint zones
  1523. * require file clauses.
  1524. */
  1525. obj = NULL;
  1526. tresult = cfg_map_get(zoptions, "database", &obj);
  1527. if (tresult == ISC_R_NOTFOUND ||
  1528. (tresult == ISC_R_SUCCESS &&
  1529. (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
  1530. strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
  1531. obj = NULL;
  1532. tresult = cfg_map_get(zoptions, "file", &obj);
  1533. if (tresult != ISC_R_SUCCESS &&
  1534. (ztype == MASTERZONE || ztype == HINTZONE)) {
  1535. cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
  1536. "zone '%s': missing 'file' entry",
  1537. znamestr);
  1538. result = tresult;
  1539. }
  1540. }
  1541. return (result);
  1542. }
  1543. typedef struct keyalgorithms {
  1544. const char *name;
  1545. isc_uint16_t size;
  1546. } algorithmtable;
  1547. isc_result_t
  1548. bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
  1549. const cfg_obj_t *algobj = NULL;
  1550. const cfg_obj_t *secretobj = NULL;
  1551. const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
  1552. const char *algorithm;
  1553. int i;
  1554. size_t len = 0;
  1555. isc_result_t result;
  1556. isc_buffer_t buf;
  1557. unsigned char secretbuf[1024];
  1558. static const algorithmtable algorithms[] = {
  1559. { "hmac-md5", 128 },
  1560. { "hmac-md5.sig-alg.reg.int", 0 },
  1561. { "hmac-md5.sig-alg.reg.int.", 0 },
  1562. { "hmac-sha1", 160 },
  1563. { "hmac-sha224", 224 },
  1564. { "hmac-sha256", 256 },
  1565. { "hmac-sha384", 384 },
  1566. { "hmac-sha512", 512 },
  1567. { NULL, 0 }
  1568. };
  1569. (void)cfg_map_get(key, "algorithm", &algobj);
  1570. (void)cfg_map_get(key, "secret", &secretobj);
  1571. if (secretobj == NULL || algobj == NULL) {
  1572. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  1573. "key '%s' must have both 'secret' and "
  1574. "'algorithm' defined",
  1575. keyname);
  1576. return (ISC_R_FAILURE);
  1577. }
  1578. isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
  1579. result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
  1580. if (result != ISC_R_SUCCESS) {
  1581. cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
  1582. "bad secret '%s'", isc_result_totext(result));
  1583. return (result);
  1584. }
  1585. algorithm = cfg_obj_asstring(algobj);
  1586. for (i = 0; algorithms[i].name != NULL; i++) {
  1587. len = strlen(algorithms[i].name);
  1588. if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
  1589. (algorithm[len] == '\0' ||
  1590. (algorithms[i].size != 0 && algorithm[len] == '-')))
  1591. break;
  1592. }
  1593. if (algorithms[i].name == NULL) {
  1594. cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
  1595. "unknown algorithm '%s'", algorithm);
  1596. return (ISC_R_NOTFOUND);
  1597. }
  1598. if (algorithm[len] == '-') {
  1599. isc_uint16_t digestbits;
  1600. isc_result_t result;
  1601. result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
  1602. if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
  1603. if (result == ISC_R_RANGE ||
  1604. digestbits > algorithms[i].size) {
  1605. cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
  1606. "key '%s' digest-bits too large "
  1607. "[%u..%u]", keyname,
  1608. algorithms[i].size / 2,
  1609. algorithms[i].size);
  1610. return (ISC_R_RANGE);
  1611. }
  1612. if ((digestbits % 8) != 0) {
  1613. cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
  1614. "key '%s' digest-bits not multiple"
  1615. " of 8", keyname);
  1616. return (ISC_R_RANGE);
  1617. }
  1618. /*
  1619. * Recommended minima for hmac algorithms.
  1620. */
  1621. if ((digestbits < (algorithms[i].size / 2U) ||
  1622. (digestbits < 80U)))
  1623. cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
  1624. "key '%s' digest-bits too small "
  1625. "[<%u]", keyname,
  1626. algorithms[i].size/2);
  1627. } else {
  1628. cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
  1629. "key '%s': unable to parse digest-bits",
  1630. keyname);
  1631. return (result);
  1632. }
  1633. }
  1634. return (ISC_R_SUCCESS);
  1635. }
  1636. /*
  1637. * Check key list for duplicates key names and that the key names
  1638. * are valid domain names as these keys are used for TSIG.
  1639. *
  1640. * Check the key contents for validity.
  1641. */
  1642. static isc_result_t
  1643. check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
  1644. isc_mem_t *mctx, isc_log_t *logctx)
  1645. {
  1646. char namebuf[DNS_NAME_FORMATSIZE];
  1647. dns_fixedname_t fname;
  1648. dns_name_t *name;
  1649. isc_result_t result = ISC_R_SUCCESS;
  1650. isc_result_t tresult;
  1651. const cfg_listelt_t *element;
  1652. dns_fixedname_init(&fname);
  1653. name = dns_fixedname_name(&fname);
  1654. for (element = cfg_list_first(keys);
  1655. element != NULL;
  1656. element = cfg_list_next(element))
  1657. {
  1658. const cfg_obj_t *key = cfg_listelt_value(element);
  1659. const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
  1660. isc_symvalue_t symvalue;
  1661. isc_buffer_t b;
  1662. char *keyname;
  1663. isc_buffer_init(&b, keyid, strlen(keyid));
  1664. isc_buffer_add(&b, strlen(keyid));
  1665. tresult = dns_name_fromtext(name, &b, dns_rootname,
  1666. 0, NULL);
  1667. if (tresult != ISC_R_SUCCESS) {
  1668. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  1669. "key '%s': bad key name", keyid);
  1670. result = tresult;
  1671. continue;
  1672. }
  1673. tresult = bind9_check_key(key, logctx);
  1674. if (tresult != ISC_R_SUCCESS)
  1675. return (tresult);
  1676. dns_name_format(name, namebuf, sizeof(namebuf));
  1677. keyname = isc_mem_strdup(mctx, namebuf);
  1678. if (keyname == NULL)
  1679. return (ISC_R_NOMEMORY);
  1680. symvalue.as_cpointer = key;
  1681. tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
  1682. isc_symexists_reject);
  1683. if (tresult == ISC_R_EXISTS) {
  1684. const char *file;
  1685. unsigned int line;
  1686. RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
  1687. 1, &symvalue) == ISC_R_SUCCESS);
  1688. file = cfg_obj_file(symvalue.as_cpointer);
  1689. line = cfg_obj_line(symvalue.as_cpointer);
  1690. if (file == NULL)
  1691. file = "<unknown file>";
  1692. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  1693. "key '%s': already exists "
  1694. "previous definition: %s:%u",
  1695. keyid, file, line);
  1696. isc_mem_free(mctx, keyname);
  1697. result = tresult;
  1698. } else if (tresult != ISC_R_SUCCESS) {
  1699. isc_mem_free(mctx, keyname);
  1700. return (tresult);
  1701. }
  1702. }
  1703. return (result);
  1704. }
  1705. static struct {
  1706. const char *v4;
  1707. const char *v6;
  1708. } sources[] = {
  1709. { "transfer-source", "transfer-source-v6" },
  1710. { "notify-source", "notify-source-v6" },
  1711. { "query-source", "query-source-v6" },
  1712. { NULL, NULL }
  1713. };
  1714. /*
  1715. * RNDC keys are not normalised unlike TSIG keys.
  1716. *
  1717. * "foo." is different to "foo".
  1718. */
  1719. static isc_boolean_t
  1720. rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
  1721. const cfg_listelt_t *element;
  1722. const cfg_obj_t *obj;
  1723. const char *str;
  1724. if (keylist == NULL)
  1725. return (ISC_FALSE);
  1726. for (element = cfg_list_first(keylist);
  1727. element != NULL;
  1728. element = cfg_list_next(element))
  1729. {
  1730. obj = cfg_listelt_value(element);
  1731. str = cfg_obj_asstring(cfg_map_getname(obj));
  1732. if (!strcasecmp(str, keyname))
  1733. return (ISC_TRUE);
  1734. }
  1735. return (ISC_FALSE);
  1736. }
  1737. static isc_result_t
  1738. check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
  1739. isc_symtab_t *symtab, isc_log_t *logctx)
  1740. {
  1741. dns_fixedname_t fname;
  1742. isc_result_t result = ISC_R_SUCCESS;
  1743. isc_result_t tresult;
  1744. const cfg_listelt_t *e1, *e2;
  1745. const cfg_obj_t *v1, *v2, *keys;
  1746. const cfg_obj_t *servers;
  1747. isc_netaddr_t n1, n2;
  1748. unsigned int p1, p2;
  1749. const cfg_obj_t *obj;
  1750. char buf[ISC_NETADDR_FORMATSIZE];
  1751. char namebuf[DNS_NAME_FORMATSIZE];
  1752. const char *xfr;
  1753. const char *keyval;
  1754. isc_buffer_t b;
  1755. int source;
  1756. dns_name_t *keyname;
  1757. servers = NULL;
  1758. if (voptions != NULL)
  1759. (void)cfg_map_get(voptions, "server", &servers);
  1760. if (servers == NULL)
  1761. (void)cfg_map_get(config, "server", &servers);
  1762. if (servers == NULL)
  1763. return (ISC_R_SUCCESS);
  1764. for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
  1765. v1 = cfg_listelt_value(e1);
  1766. cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
  1767. /*
  1768. * Check that unused bits are zero.
  1769. */
  1770. tresult = isc_netaddr_prefixok(&n1, p1);
  1771. if (tresult != ISC_R_SUCCESS) {
  1772. INSIST(tresult == ISC_R_FAILURE);
  1773. isc_netaddr_format(&n1, buf, sizeof(buf));
  1774. cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
  1775. "server '%s/%u': invalid prefix "
  1776. "(extra bits specified)", buf, p1);
  1777. result = tresult;
  1778. }
  1779. source = 0;
  1780. do {
  1781. obj = NULL;
  1782. if (n1.family == AF_INET)
  1783. xfr = sources[source].v6;
  1784. else
  1785. xfr = sources[source].v4;
  1786. (void)cfg_map_get(v1, xfr, &obj);
  1787. if (obj != NULL) {
  1788. isc_netaddr_format(&n1, buf, sizeof(buf));
  1789. cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
  1790. "server '%s/%u': %s not legal",
  1791. buf, p1, xfr);
  1792. result = ISC_R_FAILURE;
  1793. }
  1794. } while (sources[++source].v4 != NULL);
  1795. e2 = e1;
  1796. while ((e2 = cfg_list_next(e2)) != NULL) {
  1797. v2 = cfg_listelt_value(e2);
  1798. cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
  1799. if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
  1800. const char *file = cfg_obj_file(v1);
  1801. unsigned int line = cfg_obj_line(v1);
  1802. if (file == NULL)
  1803. file = "<unknown file>";
  1804. isc_netaddr_format(&n2, buf, sizeof(buf));
  1805. cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
  1806. "server '%s/%u': already exists "
  1807. "previous definition: %s:%u",
  1808. buf, p2, file, line);
  1809. result = ISC_R_FAILURE;
  1810. }
  1811. }
  1812. keys = NULL;
  1813. cfg_map_get(v1, "keys", &keys);
  1814. if (keys != NULL) {
  1815. /*
  1816. * Normalize key name.
  1817. */
  1818. keyval = cfg_obj_asstring(keys);
  1819. dns_fixedname_init(&fname);
  1820. isc_buffer_init(&b, keyval, strlen(keyval));
  1821. isc_buffer_add(&b, strlen(keyval));
  1822. keyname = dns_fixedname_name(&fname);
  1823. tresult = dns_name_fromtext(keyname, &b, dns_rootname,
  1824. 0, NULL);
  1825. if (tresult != ISC_R_SUCCESS) {
  1826. cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
  1827. "bad key name '%s'", keyval);
  1828. result = ISC_R_FAILURE;
  1829. continue;
  1830. }
  1831. dns_name_format(keyname, namebuf, sizeof(namebuf));
  1832. tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
  1833. if (tresult != ISC_R_SUCCESS) {
  1834. cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
  1835. "unknown key '%s'", keyval);
  1836. result = ISC_R_FAILURE;
  1837. }
  1838. }
  1839. }
  1840. return (result);
  1841. }
  1842. static isc_result_t
  1843. check_trusted_key(const cfg_obj_t *key, isc_boolean_t managed,
  1844. isc_log_t *logctx)
  1845. {
  1846. const char *keystr, *keynamestr;
  1847. dns_fixedname_t fkeyname;
  1848. dns_name_t *keyname;
  1849. isc_buffer_t b;
  1850. isc_region_t r;
  1851. isc_result_t result = ISC_R_SUCCESS;
  1852. isc_result_t tresult;
  1853. isc_uint32_t flags, proto, alg;
  1854. unsigned char keydata[4096];
  1855. flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
  1856. proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
  1857. alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
  1858. dns_fixedname_init(&fkeyname);
  1859. keyname = dns_fixedname_name(&fkeyname);
  1860. keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
  1861. isc_buffer_init(&b, keynamestr, strlen(keynamestr));
  1862. isc_buffer_add(&b, strlen(keynamestr));
  1863. result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
  1864. if (result != ISC_R_SUCCESS) {
  1865. cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
  1866. isc_result_totext(result));
  1867. result = ISC_R_FAILURE;
  1868. }
  1869. if (flags > 0xffff) {
  1870. cfg_obj_log(key, logctx, ISC_LOG_WARNING,
  1871. "flags too big: %u\n", flags);
  1872. result = ISC_R_FAILURE;
  1873. }
  1874. if (proto > 0xff) {
  1875. cfg_obj_log(key, logctx, ISC_LOG_WARNING,
  1876. "protocol too big: %u\n", proto);
  1877. result = ISC_R_FAILURE;
  1878. }
  1879. if (alg > 0xff) {
  1880. cfg_obj_log(key, logctx, ISC_LOG_WARNING,
  1881. "algorithm too big: %u\n", alg);
  1882. result = ISC_R_FAILURE;
  1883. }
  1884. if (managed) {
  1885. const char *initmethod;
  1886. initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
  1887. if (strcasecmp(initmethod, "initial-key") != 0) {
  1888. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  1889. "managed key '%s': "
  1890. "invalid initialization method '%s'",
  1891. keynamestr, initmethod);
  1892. result = ISC_R_FAILURE;
  1893. }
  1894. }
  1895. isc_buffer_init(&b, keydata, sizeof(keydata));
  1896. keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
  1897. tresult = isc_base64_decodestring(keystr, &b);
  1898. if (tresult != ISC_R_SUCCESS) {
  1899. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  1900. "%s", isc_result_totext(tresult));
  1901. result = ISC_R_FAILURE;
  1902. } else {
  1903. isc_buffer_usedregion(&b, &r);
  1904. if ((alg == DST_ALG_RSASHA1 || alg == DST_ALG_RSAMD5) &&
  1905. r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
  1906. cfg_obj_log(key, logctx, ISC_LOG_WARNING,
  1907. "%s key '%s' has a weak exponent",
  1908. managed ? "managed" : "trusted",
  1909. keynamestr);
  1910. }
  1911. return (result);
  1912. }
  1913. static isc_result_t
  1914. check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
  1915. const char *viewname, dns_rdataclass_t vclass,
  1916. isc_log_t *logctx, isc_mem_t *mctx)
  1917. {
  1918. const cfg_obj_t *zones = NULL;
  1919. const cfg_obj_t *keys = NULL;
  1920. const cfg_listelt_t *element, *element2;
  1921. isc_symtab_t *symtab = NULL;
  1922. isc_result_t result = ISC_R_SUCCESS;
  1923. isc_result_t tresult = ISC_R_SUCCESS;
  1924. cfg_aclconfctx_t *actx = NULL;
  1925. const cfg_obj_t *obj;
  1926. const cfg_obj_t *options = NULL;
  1927. isc_boolean_t enablednssec, enablevalidation;
  1928. const char *valstr = "no";
  1929. /*
  1930. * Get global options block
  1931. */
  1932. (void)cfg_map_get(config, "options", &options);
  1933. /*
  1934. * Check that all zone statements are syntactically correct and
  1935. * there are no duplicate zones.
  1936. */
  1937. tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
  1938. ISC_FALSE, &symtab);
  1939. if (tresult != ISC_R_SUCCESS)
  1940. return (ISC_R_NOMEMORY);
  1941. cfg_aclconfctx_create(mctx, &actx);
  1942. if (voptions != NULL)
  1943. (void)cfg_map_get(voptions, "zone", &zones);
  1944. else
  1945. (void)cfg_map_get(config, "zone", &zones);
  1946. for (element = cfg_list_first(zones);
  1947. element != NULL;
  1948. element = cfg_list_next(element))
  1949. {
  1950. isc_result_t tresult;
  1951. const cfg_obj_t *zone = cfg_listelt_value(element);
  1952. tresult = check_zoneconf(zone, voptions, config, symtab,
  1953. vclass, actx, logctx, mctx);
  1954. if (tresult != ISC_R_SUCCESS)
  1955. result = ISC_R_FAILURE;
  1956. }
  1957. isc_symtab_destroy(&symtab);
  1958. /*
  1959. * Check that forwarding is reasonable.
  1960. */
  1961. if (voptions == NULL) {
  1962. if (options != NULL)
  1963. if (check_forward(options, NULL,
  1964. logctx) != ISC_R_SUCCESS)
  1965. result = ISC_R_FAILURE;
  1966. } else {
  1967. if (check_forward(voptions, NULL, logctx) != ISC_R_SUCCESS)
  1968. result = ISC_R_FAILURE;
  1969. }
  1970. /*
  1971. * Check that dual-stack-servers is reasonable.
  1972. */
  1973. if (voptions == NULL) {
  1974. if (options != NULL)
  1975. if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
  1976. result = ISC_R_FAILURE;
  1977. } else {
  1978. if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
  1979. result = ISC_R_FAILURE;
  1980. }
  1981. /*
  1982. * Check that rrset-order is reasonable.
  1983. */
  1984. if (voptions != NULL) {
  1985. if (check_order(voptions, logctx) != ISC_R_SUCCESS)
  1986. result = ISC_R_FAILURE;
  1987. }
  1988. /*
  1989. * Check that all key statements are syntactically correct and
  1990. * there are no duplicate keys.
  1991. */
  1992. tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
  1993. ISC_FALSE, &symtab);
  1994. if (tresult != ISC_R_SUCCESS)
  1995. return (ISC_R_NOMEMORY);
  1996. (void)cfg_map_get(config, "key", &keys);
  1997. tresult = check_keylist(keys, symtab, mctx, logctx);
  1998. if (tresult == ISC_R_EXISTS)
  1999. result = ISC_R_FAILURE;
  2000. else if (tresult != ISC_R_SUCCESS) {
  2001. isc_symtab_destroy(&symtab);
  2002. return (tresult);
  2003. }
  2004. if (voptions != NULL) {
  2005. keys = NULL;
  2006. (void)cfg_map_get(voptions, "key", &keys);
  2007. tresult = check_keylist(keys, symtab, mctx, logctx);
  2008. if (tresult == ISC_R_EXISTS)
  2009. result = ISC_R_FAILURE;
  2010. else if (tresult != ISC_R_SUCCESS) {
  2011. isc_symtab_destroy(&symtab);
  2012. return (tresult);
  2013. }
  2014. }
  2015. /*
  2016. * Global servers can refer to keys in views.
  2017. */
  2018. if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
  2019. result = ISC_R_FAILURE;
  2020. isc_symtab_destroy(&symtab);
  2021. /*
  2022. * Check that dnssec-enable/dnssec-validation are sensible.
  2023. */
  2024. obj = NULL;
  2025. if (voptions != NULL)
  2026. (void)cfg_map_get(voptions, "dnssec-enable", &obj);
  2027. if (obj == NULL && options != NULL)
  2028. (void)cfg_map_get(options, "dnssec-enable", &obj);
  2029. if (obj == NULL)
  2030. enablednssec = ISC_TRUE;
  2031. else
  2032. enablednssec = cfg_obj_asboolean(obj);
  2033. obj = NULL;
  2034. if (voptions != NULL)
  2035. (void)cfg_map_get(voptions, "dnssec-validation", &obj);
  2036. if (obj == NULL && options != NULL)
  2037. (void)cfg_map_get(options, "dnssec-validation", &obj);
  2038. if (obj == NULL) {
  2039. enablevalidation = enablednssec;
  2040. valstr = "yes";
  2041. } else if (cfg_obj_isboolean(obj)) {
  2042. enablevalidation = cfg_obj_asboolean(obj);
  2043. valstr = enablevalidation ? "yes" : "no";
  2044. } else {
  2045. enablevalidation = ISC_TRUE;
  2046. valstr = "auto";
  2047. }
  2048. if (enablevalidation && !enablednssec)
  2049. cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
  2050. "'dnssec-validation %s;' and 'dnssec-enable no;'",
  2051. valstr);
  2052. /*
  2053. * Check trusted-keys and managed-keys.
  2054. */
  2055. keys = NULL;
  2056. if (voptions != NULL)
  2057. (void)cfg_map_get(voptions, "trusted-keys", &keys);
  2058. if (keys == NULL)
  2059. (void)cfg_map_get(config, "trusted-keys", &keys);
  2060. for (element = cfg_list_first(keys);
  2061. element != NULL;
  2062. element = cfg_list_next(element))
  2063. {
  2064. const cfg_obj_t *keylist = cfg_listelt_value(element);
  2065. for (element2 = cfg_list_first(keylist);
  2066. element2 != NULL;
  2067. element2 = cfg_list_next(element2)) {
  2068. obj = cfg_listelt_value(element2);
  2069. tresult = check_trusted_key(obj, ISC_FALSE, logctx);
  2070. if (tresult != ISC_R_SUCCESS)
  2071. result = tresult;
  2072. }
  2073. }
  2074. keys = NULL;
  2075. if (voptions != NULL)
  2076. (void)cfg_map_get(voptions, "managed-keys", &keys);
  2077. if (keys == NULL)
  2078. (void)cfg_map_get(config, "managed-keys", &keys);
  2079. for (element = cfg_list_first(keys);
  2080. element != NULL;
  2081. element = cfg_list_next(element))
  2082. {
  2083. const cfg_obj_t *keylist = cfg_listelt_value(element);
  2084. for (element2 = cfg_list_first(keylist);
  2085. element2 != NULL;
  2086. element2 = cfg_list_next(element2)) {
  2087. obj = cfg_listelt_value(element2);
  2088. tresult = check_trusted_key(obj, ISC_TRUE, logctx);
  2089. if (tresult != ISC_R_SUCCESS)
  2090. result = tresult;
  2091. }
  2092. }
  2093. /*
  2094. * Check options.
  2095. */
  2096. if (voptions != NULL)
  2097. tresult = check_options(voptions, logctx, mctx,
  2098. optlevel_view);
  2099. else
  2100. tresult = check_options(config, logctx, mctx,
  2101. optlevel_config);
  2102. if (tresult != ISC_R_SUCCESS)
  2103. result = tresult;
  2104. tresult = check_viewacls(actx, voptions, config, logctx, mctx);
  2105. if (tresult != ISC_R_SUCCESS)
  2106. result = tresult;
  2107. tresult = check_recursionacls(actx, voptions, viewname,
  2108. config, logctx, mctx);
  2109. if (tresult != ISC_R_SUCCESS)
  2110. result = tresult;
  2111. tresult = check_filteraaaa(actx, voptions, viewname, config,
  2112. logctx, mctx);
  2113. if (tresult != ISC_R_SUCCESS)
  2114. result = tresult;
  2115. tresult = check_dns64(actx, voptions, config, logctx, mctx);
  2116. if (tresult != ISC_R_SUCCESS)
  2117. result = tresult;
  2118. cfg_aclconfctx_detach(&actx);
  2119. return (result);
  2120. }
  2121. static const char *
  2122. default_channels[] = {
  2123. "default_syslog",
  2124. "default_stderr",
  2125. "default_debug",
  2126. "null",
  2127. NULL
  2128. };
  2129. static isc_result_t
  2130. bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
  2131. isc_mem_t *mctx)
  2132. {
  2133. const cfg_obj_t *categories = NULL;
  2134. const cfg_obj_t *category;
  2135. const cfg_obj_t *channels = NULL;
  2136. const cfg_obj_t *channel;
  2137. const cfg_listelt_t *element;
  2138. const cfg_listelt_t *delement;
  2139. const char *channelname;
  2140. const char *catname;
  2141. const cfg_obj_t *fileobj = NULL;
  2142. const cfg_obj_t *syslogobj = NULL;
  2143. const cfg_obj_t *nullobj = NULL;
  2144. const cfg_obj_t *stderrobj = NULL;
  2145. const cfg_obj_t *logobj = NULL;
  2146. isc_result_t result = ISC_R_SUCCESS;
  2147. isc_result_t tresult;
  2148. isc_symtab_t *symtab = NULL;
  2149. isc_symvalue_t symvalue;
  2150. int i;
  2151. (void)cfg_map_get(config, "logging", &logobj);
  2152. if (logobj == NULL)
  2153. return (ISC_R_SUCCESS);
  2154. result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
  2155. if (result != ISC_R_SUCCESS)
  2156. return (result);
  2157. symvalue.as_cpointer = NULL;
  2158. for (i = 0; default_channels[i] != NULL; i++) {
  2159. tresult = isc_symtab_define(symtab, default_channels[i], 1,
  2160. symvalue, isc_symexists_replace);
  2161. if (tresult != ISC_R_SUCCESS)
  2162. result = tresult;
  2163. }
  2164. cfg_map_get(logobj, "channel", &channels);
  2165. for (element = cfg_list_first(channels);
  2166. element != NULL;
  2167. element = cfg_list_next(element))
  2168. {
  2169. channel = cfg_listelt_value(element);
  2170. channelname = cfg_obj_asstring(cfg_map_getname(channel));
  2171. fileobj = syslogobj = nullobj = stderrobj = NULL;
  2172. (void)cfg_map_get(channel, "file", &fileobj);
  2173. (void)cfg_map_get(channel, "syslog", &syslogobj);
  2174. (void)cfg_map_get(channel, "null", &nullobj);
  2175. (void)cfg_map_get(channel, "stderr", &stderrobj);
  2176. i = 0;
  2177. if (fileobj != NULL)
  2178. i++;
  2179. if (syslogobj != NULL)
  2180. i++;
  2181. if (nullobj != NULL)
  2182. i++;
  2183. if (stderrobj != NULL)
  2184. i++;
  2185. if (i != 1) {
  2186. cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
  2187. "channel '%s': exactly one of file, syslog, "
  2188. "null, and stderr must be present",
  2189. channelname);
  2190. result = ISC_R_FAILURE;
  2191. }
  2192. tresult = isc_symtab_define(symtab, channelname, 1,
  2193. symvalue, isc_symexists_replace);
  2194. if (tresult != ISC_R_SUCCESS)
  2195. result = tresult;
  2196. }
  2197. cfg_map_get(logobj, "category", &categories);
  2198. for (element = cfg_list_first(categories);
  2199. element != NULL;
  2200. element = cfg_list_next(element))
  2201. {
  2202. category = cfg_listelt_value(element);
  2203. catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
  2204. if (isc_log_categorybyname(logctx, catname) == NULL) {
  2205. cfg_obj_log(category, logctx, ISC_LOG_ERROR,
  2206. "undefined category: '%s'", catname);
  2207. result = ISC_R_FAILURE;
  2208. }
  2209. channels = cfg_tuple_get(category, "destinations");
  2210. for (delement = cfg_list_first(channels);
  2211. delement != NULL;
  2212. delement = cfg_list_next(delement))
  2213. {
  2214. channel = cfg_listelt_value(delement);
  2215. channelname = cfg_obj_asstring(channel);
  2216. tresult = isc_symtab_lookup(symtab, channelname, 1,
  2217. &symvalue);
  2218. if (tresult != ISC_R_SUCCESS) {
  2219. cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
  2220. "undefined channel: '%s'",
  2221. channelname);
  2222. result = tresult;
  2223. }
  2224. }
  2225. }
  2226. isc_symtab_destroy(&symtab);
  2227. return (result);
  2228. }
  2229. static isc_result_t
  2230. bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
  2231. isc_log_t *logctx)
  2232. {
  2233. isc_result_t result = ISC_R_SUCCESS;
  2234. const cfg_obj_t *control_keylist;
  2235. const cfg_listelt_t *element;
  2236. const cfg_obj_t *key;
  2237. const char *keyval;
  2238. control_keylist = cfg_tuple_get(control, "keys");
  2239. if (cfg_obj_isvoid(control_keylist))
  2240. return (ISC_R_SUCCESS);
  2241. for (element = cfg_list_first(control_keylist);
  2242. element != NULL;
  2243. element = cfg_list_next(element))
  2244. {
  2245. key = cfg_listelt_value(element);
  2246. keyval = cfg_obj_asstring(key);
  2247. if (!rndckey_exists(keylist, keyval)) {
  2248. cfg_obj_log(key, logctx, ISC_LOG_ERROR,
  2249. "unknown key '%s'", keyval);
  2250. result = ISC_R_NOTFOUND;
  2251. }
  2252. }
  2253. return (result);
  2254. }
  2255. static isc_result_t
  2256. bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
  2257. isc_mem_t *mctx)
  2258. {
  2259. isc_result_t result = ISC_R_SUCCESS, tresult;
  2260. cfg_aclconfctx_t *actx = NULL;
  2261. const cfg_listelt_t *element, *element2;
  2262. const cfg_obj_t *allow;
  2263. const cfg_obj_t *control;
  2264. const cfg_obj_t *controls;
  2265. const cfg_obj_t *controlslist = NULL;
  2266. const cfg_obj_t *inetcontrols;
  2267. const cfg_obj_t *unixcontrols;
  2268. const cfg_obj_t *keylist = NULL;
  2269. const char *path;
  2270. isc_uint32_t perm, mask;
  2271. dns_acl_t *acl = NULL;
  2272. isc_sockaddr_t addr;
  2273. int i;
  2274. (void)cfg_map_get(config, "controls", &controlslist);
  2275. if (controlslist == NULL)
  2276. return (ISC_R_SUCCESS);
  2277. (void)cfg_map_get(config, "key", &keylist);
  2278. cfg_aclconfctx_create(mctx, &actx);
  2279. /*
  2280. * INET: Check allow clause.
  2281. * UNIX: Check "perm" for sanity, check path length.
  2282. */
  2283. for (element = cfg_list_first(controlslist);
  2284. element != NULL;
  2285. element = cfg_list_next(element)) {
  2286. controls = cfg_listelt_value(element);
  2287. unixcontrols = NULL;
  2288. inetcontrols = NULL;
  2289. (void)cfg_map_get(controls, "unix", &unixcontrols);
  2290. (void)cfg_map_get(controls, "inet", &inetcontrols);
  2291. for (element2 = cfg_list_first(inetcontrols);
  2292. element2 != NULL;
  2293. element2 = cfg_list_next(element2)) {
  2294. control = cfg_listelt_value(element2);
  2295. allow = cfg_tuple_get(control, "allow");
  2296. tresult = cfg_acl_fromconfig(allow, config, logctx,
  2297. actx, mctx, 0, &acl);
  2298. if (acl != NULL)
  2299. dns_acl_detach(&acl);
  2300. if (tresult != ISC_R_SUCCESS)
  2301. result = tresult;
  2302. tresult = bind9_check_controlskeys(control, keylist,
  2303. logctx);
  2304. if (tresult != ISC_R_SUCCESS)
  2305. result = tresult;
  2306. }
  2307. for (element2 = cfg_list_first(unixcontrols);
  2308. element2 != NULL;
  2309. element2 = cfg_list_next(element2)) {
  2310. control = cfg_listelt_value(element2);
  2311. path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
  2312. tresult = isc_sockaddr_frompath(&addr, path);
  2313. if (tresult == ISC_R_NOSPACE) {
  2314. cfg_obj_log(control, logctx, ISC_LOG_ERROR,
  2315. "unix control '%s': path too long",
  2316. path);
  2317. result = ISC_R_NOSPACE;
  2318. }
  2319. perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
  2320. for (i = 0; i < 3; i++) {
  2321. #ifdef NEED_SECURE_DIRECTORY
  2322. mask = (0x1 << (i*3)); /* SEARCH */
  2323. #else
  2324. mask = (0x6 << (i*3)); /* READ + WRITE */
  2325. #endif
  2326. if ((perm & mask) == mask)
  2327. break;
  2328. }
  2329. if (i == 0) {
  2330. cfg_obj_log(control, logctx, ISC_LOG_WARNING,
  2331. "unix control '%s' allows access "
  2332. "to everyone", path);
  2333. } else if (i == 3) {
  2334. cfg_obj_log(control, logctx, ISC_LOG_WARNING,
  2335. "unix control '%s' allows access "
  2336. "to nobody", path);
  2337. }
  2338. tresult = bind9_check_controlskeys(control, keylist,
  2339. logctx);
  2340. if (tresult != ISC_R_SUCCESS)
  2341. result = tresult;
  2342. }
  2343. }
  2344. cfg_aclconfctx_detach(&actx);
  2345. return (result);
  2346. }
  2347. isc_result_t
  2348. bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
  2349. isc_mem_t *mctx)
  2350. {
  2351. const cfg_obj_t *options = NULL;
  2352. const cfg_obj_t *views = NULL;
  2353. const cfg_obj_t *acls = NULL;
  2354. const cfg_obj_t *kals = NULL;
  2355. const cfg_obj_t *obj;
  2356. const cfg_listelt_t *velement;
  2357. isc_result_t result = ISC_R_SUCCESS;
  2358. isc_result_t tresult;
  2359. isc_symtab_t *symtab = NULL;
  2360. static const char *builtin[] = { "localhost", "localnets",
  2361. "any", "none"};
  2362. (void)cfg_map_get(config, "options", &options);
  2363. if (options != NULL &&
  2364. check_options(options, logctx, mctx,
  2365. optlevel_options) != ISC_R_SUCCESS)
  2366. result = ISC_R_FAILURE;
  2367. if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
  2368. result = ISC_R_FAILURE;
  2369. if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
  2370. result = ISC_R_FAILURE;
  2371. if (options != NULL &&
  2372. check_order(options, logctx) != ISC_R_SUCCESS)
  2373. result = ISC_R_FAILURE;
  2374. (void)cfg_map_get(config, "view", &views);
  2375. if (views != NULL && options != NULL)
  2376. if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
  2377. result = ISC_R_FAILURE;
  2378. if (views == NULL) {
  2379. if (check_viewconf(config, NULL, NULL, dns_rdataclass_in,
  2380. logctx, mctx) != ISC_R_SUCCESS)
  2381. result = ISC_R_FAILURE;
  2382. } else {
  2383. const cfg_obj_t *zones = NULL;
  2384. (void)cfg_map_get(config, "zone", &zones);
  2385. if (zones != NULL) {
  2386. cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
  2387. "when using 'view' statements, "
  2388. "all zones must be in views");
  2389. result = ISC_R_FAILURE;
  2390. }
  2391. }
  2392. tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
  2393. if (tresult != ISC_R_SUCCESS)
  2394. result = tresult;
  2395. for (velement = cfg_list_first(views);
  2396. velement != NULL;
  2397. velement = cfg_list_next(velement))
  2398. {
  2399. const cfg_obj_t *view = cfg_listelt_value(velement);
  2400. const cfg_obj_t *vname = cfg_tuple_get(view, "name");
  2401. const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
  2402. const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
  2403. dns_rdataclass_t vclass = dns_rdataclass_in;
  2404. isc_result_t tresult = ISC_R_SUCCESS;
  2405. const char *key = cfg_obj_asstring(vname);
  2406. isc_symvalue_t symvalue;
  2407. if (cfg_obj_isstring(vclassobj)) {
  2408. isc_textregion_t r;
  2409. DE_CONST(cfg_obj_asstring(vclassobj), r.base);
  2410. r.length = strlen(r.base);
  2411. tresult = dns_rdataclass_fromtext(&vclass, &r);
  2412. if (tresult != ISC_R_SUCCESS)
  2413. cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
  2414. "view '%s': invalid class %s",
  2415. cfg_obj_asstring(vname), r.base);
  2416. }
  2417. if (tresult == ISC_R_SUCCESS && symtab != NULL) {
  2418. symvalue.as_cpointer = view;
  2419. tresult = isc_symtab_define(symtab, key, vclass,
  2420. symvalue,
  2421. isc_symexists_reject);
  2422. if (tresult == ISC_R_EXISTS) {
  2423. const char *file;
  2424. unsigned int line;
  2425. RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
  2426. vclass, &symvalue) == ISC_R_SUCCESS);
  2427. file = cfg_obj_file(symvalue.as_cpointer);
  2428. line = cfg_obj_line(symvalue.as_cpointer);
  2429. cfg_obj_log(view, logctx, ISC_LOG_ERROR,
  2430. "view '%s': already exists "
  2431. "previous definition: %s:%u",
  2432. key, file, line);
  2433. result = tresult;
  2434. } else if (tresult != ISC_R_SUCCESS) {
  2435. result = tresult;
  2436. } else if ((strcasecmp(key, "_bind") == 0 &&
  2437. vclass == dns_rdataclass_ch) ||
  2438. (strcasecmp(key, "_default") == 0 &&
  2439. vclass == dns_rdataclass_in)) {
  2440. cfg_obj_log(view, logctx, ISC_LOG_ERROR,
  2441. "attempt to redefine builtin view "
  2442. "'%s'", key);
  2443. result = ISC_R_EXISTS;
  2444. }
  2445. }
  2446. if (tresult == ISC_R_SUCCESS)
  2447. tresult = check_viewconf(config, voptions, key,
  2448. vclass, logctx, mctx);
  2449. if (tresult != ISC_R_SUCCESS)
  2450. result = ISC_R_FAILURE;
  2451. }
  2452. if (symtab != NULL)
  2453. isc_symtab_destroy(&symtab);
  2454. if (views != NULL && options != NULL) {
  2455. obj = NULL;
  2456. tresult = cfg_map_get(options, "cache-file", &obj);
  2457. if (tresult == ISC_R_SUCCESS) {
  2458. cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
  2459. "'cache-file' cannot be a global "
  2460. "option if views are present");
  2461. result = ISC_R_FAILURE;
  2462. }
  2463. }
  2464. cfg_map_get(config, "acl", &acls);
  2465. if (acls != NULL) {
  2466. const cfg_listelt_t *elt;
  2467. const cfg_listelt_t *elt2;
  2468. const char *aclname;
  2469. for (elt = cfg_list_first(acls);
  2470. elt != NULL;
  2471. elt = cfg_list_next(elt)) {
  2472. const cfg_obj_t *acl = cfg_listelt_value(elt);
  2473. unsigned int line = cfg_obj_line(acl);
  2474. unsigned int i;
  2475. aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
  2476. for (i = 0;
  2477. i < sizeof(builtin) / sizeof(builtin[0]);
  2478. i++)
  2479. if (strcasecmp(aclname, builtin[i]) == 0) {
  2480. cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
  2481. "attempt to redefine "
  2482. "builtin acl '%s'",
  2483. aclname);
  2484. result = ISC_R_FAILURE;
  2485. break;
  2486. }
  2487. for (elt2 = cfg_list_next(elt);
  2488. elt2 != NULL;
  2489. elt2 = cfg_list_next(elt2)) {
  2490. const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
  2491. const char *name;
  2492. name = cfg_obj_asstring(cfg_tuple_get(acl2,
  2493. "name"));
  2494. if (strcasecmp(aclname, name) == 0) {
  2495. const char *file = cfg_obj_file(acl);
  2496. if (file == NULL)
  2497. file = "<unknown file>";
  2498. cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
  2499. "attempt to redefine "
  2500. "acl '%s' previous "
  2501. "definition: %s:%u",
  2502. name, file, line);
  2503. result = ISC_R_FAILURE;
  2504. }
  2505. }
  2506. }
  2507. }
  2508. tresult = cfg_map_get(config, "kal", &kals);
  2509. if (tresult == ISC_R_SUCCESS) {
  2510. const cfg_listelt_t *elt;
  2511. const cfg_listelt_t *elt2;
  2512. const char *aclname;
  2513. for (elt = cfg_list_first(kals);
  2514. elt != NULL;
  2515. elt = cfg_list_next(elt)) {
  2516. const cfg_obj_t *acl = cfg_listelt_value(elt);
  2517. aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
  2518. for (elt2 = cfg_list_next(elt);
  2519. elt2 != NULL;
  2520. elt2 = cfg_list_next(elt2)) {
  2521. const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
  2522. const char *name;
  2523. name = cfg_obj_asstring(cfg_tuple_get(acl2,
  2524. "name"));
  2525. if (strcasecmp(aclname, name) == 0) {
  2526. const char *file = cfg_obj_file(acl);
  2527. unsigned int line = cfg_obj_line(acl);
  2528. if (file == NULL)
  2529. file = "<unknown file>";
  2530. cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
  2531. "attempt to redefine "
  2532. "kal '%s' previous "
  2533. "definition: %s:%u",
  2534. name, file, line);
  2535. result = ISC_R_FAILURE;
  2536. }
  2537. }
  2538. }
  2539. }
  2540. return (result);
  2541. }