Annotation of src/external/mpl/bind/dist/lib/bind9/check.c, Revision 1.6
1.5 christos 1: /* $NetBSD: check.c,v 1.1.1.4 2019/04/27 23:47:30 christos Exp $ */
1.1 christos 2:
3: /*
4: * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5: *
6: * This Source Code Form is subject to the terms of the Mozilla Public
7: * License, v. 2.0. If a copy of the MPL was not distributed with this
8: * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9: *
10: * See the COPYRIGHT file distributed with this work for additional
11: * information regarding copyright ownership.
12: */
13:
14: /*! \file */
15:
16: #include <config.h>
17:
1.3 christos 18: #include <inttypes.h>
19: #include <stdbool.h>
1.1 christos 20: #include <stdlib.h>
21:
22: #include <isc/aes.h>
23: #include <isc/base64.h>
24: #include <isc/buffer.h>
25: #include <isc/file.h>
26: #include <isc/hex.h>
27: #include <isc/log.h>
1.3 christos 28: #include <isc/md.h>
1.1 christos 29: #include <isc/mem.h>
30: #include <isc/netaddr.h>
31: #include <isc/parseint.h>
32: #include <isc/platform.h>
33: #include <isc/print.h>
34: #include <isc/region.h>
35: #include <isc/result.h>
1.6 ! christos 36: #include <isc/siphash.h>
1.1 christos 37: #include <isc/sockaddr.h>
38: #include <isc/string.h>
39: #include <isc/symtab.h>
40: #include <isc/util.h>
41:
42: #include <pk11/site.h>
43:
44: #include <dns/acl.h>
45: #include <dns/dnstap.h>
46: #include <dns/fixedname.h>
1.6 ! christos 47: #include <dns/rbt.h>
1.1 christos 48: #include <dns/rdataclass.h>
49: #include <dns/rdatatype.h>
50: #include <dns/rrl.h>
51: #include <dns/secalg.h>
52: #include <dns/ssu.h>
53:
54: #include <dst/dst.h>
55:
56: #include <isccfg/aclconf.h>
57: #include <isccfg/cfg.h>
58: #include <isccfg/grammar.h>
59: #include <isccfg/namedconf.h>
60:
1.3 christos 61: #include <ns/hooks.h>
62:
1.1 christos 63: #include <bind9/check.h>
64:
65: static unsigned char dlviscorg_ndata[] = "\003dlv\003isc\003org";
66: static unsigned char dlviscorg_offsets[] = { 0, 4, 8, 12 };
67: static dns_name_t const dlviscorg =
68: DNS_NAME_INITABSOLUTE(dlviscorg_ndata, dlviscorg_offsets);
69:
70: static isc_result_t
1.3 christos 71: fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
1.1 christos 72: isc_log_t *logctxlogc);
73:
74: static void
75: freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
76: UNUSED(type);
77: UNUSED(value);
78: isc_mem_free(userarg, key);
79: }
80:
81: static isc_result_t
82: check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
83: isc_result_t result = ISC_R_SUCCESS;
84: isc_result_t tresult;
85: isc_textregion_t r;
86: dns_fixedname_t fixed;
87: const cfg_obj_t *obj;
88: dns_rdataclass_t rdclass;
89: dns_rdatatype_t rdtype;
90: isc_buffer_t b;
91: const char *str;
92:
93: dns_fixedname_init(&fixed);
94: obj = cfg_tuple_get(ent, "class");
95: if (cfg_obj_isstring(obj)) {
96:
97: DE_CONST(cfg_obj_asstring(obj), r.base);
98: r.length = strlen(r.base);
99: tresult = dns_rdataclass_fromtext(&rdclass, &r);
100: if (tresult != ISC_R_SUCCESS) {
101: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
102: "rrset-order: invalid class '%s'",
103: r.base);
104: if (result == ISC_R_SUCCESS)
105: result = ISC_R_FAILURE;
106: }
107: }
108:
109: obj = cfg_tuple_get(ent, "type");
110: if (cfg_obj_isstring(obj)) {
111: DE_CONST(cfg_obj_asstring(obj), r.base);
112: r.length = strlen(r.base);
113: tresult = dns_rdatatype_fromtext(&rdtype, &r);
114: if (tresult != ISC_R_SUCCESS) {
115: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
116: "rrset-order: invalid type '%s'",
117: r.base);
118: if (result == ISC_R_SUCCESS)
119: result = ISC_R_FAILURE;
120: }
121: }
122:
123: obj = cfg_tuple_get(ent, "name");
124: if (cfg_obj_isstring(obj)) {
125: str = cfg_obj_asstring(obj);
126: isc_buffer_constinit(&b, str, strlen(str));
127: isc_buffer_add(&b, strlen(str));
128: tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
129: dns_rootname, 0, NULL);
130: if (tresult != ISC_R_SUCCESS) {
131: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
132: "rrset-order: invalid name '%s'", str);
133: if (result == ISC_R_SUCCESS)
134: result = ISC_R_FAILURE;
135: }
136: }
137:
138: obj = cfg_tuple_get(ent, "order");
139: if (!cfg_obj_isstring(obj) ||
140: strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
141: cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
142: "rrset-order: keyword 'order' missing");
143: if (result == ISC_R_SUCCESS)
144: result = ISC_R_FAILURE;
145: }
146:
147: obj = cfg_tuple_get(ent, "ordering");
148: if (!cfg_obj_isstring(obj)) {
149: cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
150: "rrset-order: missing ordering");
151: if (result == ISC_R_SUCCESS)
152: result = ISC_R_FAILURE;
153: } else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
154: #if !DNS_RDATASET_FIXED
155: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
156: "rrset-order: order 'fixed' was disabled at "
157: "compilation time");
158: #endif
159: } else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
160: strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0 &&
161: strcasecmp(cfg_obj_asstring(obj), "none") != 0) {
162: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
163: "rrset-order: invalid order '%s'",
164: cfg_obj_asstring(obj));
165: if (result == ISC_R_SUCCESS)
166: result = ISC_R_FAILURE;
167: }
168: return (result);
169: }
170:
171: static isc_result_t
172: check_order(const cfg_obj_t *options, isc_log_t *logctx) {
173: isc_result_t result = ISC_R_SUCCESS;
174: isc_result_t tresult;
175: const cfg_listelt_t *element;
176: const cfg_obj_t *obj = NULL;
177:
178: if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
179: return (result);
180:
181: for (element = cfg_list_first(obj);
182: element != NULL;
183: element = cfg_list_next(element))
184: {
185: tresult = check_orderent(cfg_listelt_value(element), logctx);
186: if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
187: result = tresult;
188: }
189: return (result);
190: }
191:
192: static isc_result_t
193: check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
194: const cfg_listelt_t *element;
195: const cfg_obj_t *alternates = NULL;
196: const cfg_obj_t *value;
197: const cfg_obj_t *obj;
198: const char *str;
199: dns_fixedname_t fixed;
200: dns_name_t *name;
201: isc_buffer_t buffer;
202: isc_result_t result = ISC_R_SUCCESS;
203: isc_result_t tresult;
204:
205: (void)cfg_map_get(options, "dual-stack-servers", &alternates);
206:
207: if (alternates == NULL)
208: return (ISC_R_SUCCESS);
209:
210: obj = cfg_tuple_get(alternates, "port");
211: if (cfg_obj_isuint32(obj)) {
1.3 christos 212: uint32_t val = cfg_obj_asuint32(obj);
213: if (val > UINT16_MAX) {
1.1 christos 214: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
215: "port '%u' out of range", val);
216: if (result == ISC_R_SUCCESS)
217: result = ISC_R_RANGE;
218: }
219: }
220: obj = cfg_tuple_get(alternates, "addresses");
221: for (element = cfg_list_first(obj);
222: element != NULL;
223: element = cfg_list_next(element)) {
224: value = cfg_listelt_value(element);
225: if (cfg_obj_issockaddr(value))
226: continue;
227: obj = cfg_tuple_get(value, "name");
228: str = cfg_obj_asstring(obj);
229: isc_buffer_constinit(&buffer, str, strlen(str));
230: isc_buffer_add(&buffer, strlen(str));
231: name = dns_fixedname_initname(&fixed);
232: tresult = dns_name_fromtext(name, &buffer, dns_rootname,
233: 0, NULL);
234: if (tresult != ISC_R_SUCCESS) {
235: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
236: "bad name '%s'", str);
237: if (result == ISC_R_SUCCESS)
238: result = tresult;
239: }
240: obj = cfg_tuple_get(value, "port");
241: if (cfg_obj_isuint32(obj)) {
1.3 christos 242: uint32_t val = cfg_obj_asuint32(obj);
243: if (val > UINT16_MAX) {
1.1 christos 244: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
245: "port '%u' out of range", val);
246: if (result == ISC_R_SUCCESS)
247: result = ISC_R_RANGE;
248: }
249: }
250: }
251: return (result);
252: }
253:
254: static isc_result_t
255: check_forward(const cfg_obj_t *options, const cfg_obj_t *global,
256: isc_log_t *logctx)
257: {
258: const cfg_obj_t *forward = NULL;
259: const cfg_obj_t *forwarders = NULL;
260:
261: (void)cfg_map_get(options, "forward", &forward);
262: (void)cfg_map_get(options, "forwarders", &forwarders);
263:
264: if (forwarders != NULL && global != NULL) {
265: const char *file = cfg_obj_file(global);
266: unsigned int line = cfg_obj_line(global);
267: cfg_obj_log(forwarders, logctx, ISC_LOG_ERROR,
268: "forwarders declared in root zone and "
269: "in general configuration: %s:%u",
270: file, line);
271: return (ISC_R_FAILURE);
272: }
273: if (forward != NULL && forwarders == NULL) {
274: cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
275: "no matching 'forwarders' statement");
276: return (ISC_R_FAILURE);
277: }
278: return (ISC_R_SUCCESS);
279: }
280:
281: static isc_result_t
282: disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
283: isc_result_t result = ISC_R_SUCCESS;
284: isc_result_t tresult;
285: const cfg_listelt_t *element;
286: const char *str;
287: isc_buffer_t b;
288: dns_fixedname_t fixed;
289: dns_name_t *name;
290: const cfg_obj_t *obj;
291:
292: name = dns_fixedname_initname(&fixed);
293: obj = cfg_tuple_get(disabled, "name");
294: str = cfg_obj_asstring(obj);
295: isc_buffer_constinit(&b, str, strlen(str));
296: isc_buffer_add(&b, strlen(str));
297: tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
298: if (tresult != ISC_R_SUCCESS) {
299: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
300: "bad domain name '%s'", str);
301: result = tresult;
302: }
303:
304: obj = cfg_tuple_get(disabled, "algorithms");
305:
306: for (element = cfg_list_first(obj);
307: element != NULL;
308: element = cfg_list_next(element))
309: {
310: isc_textregion_t r;
311: dns_secalg_t alg;
312:
313: DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
314: r.length = strlen(r.base);
315:
316: tresult = dns_secalg_fromtext(&alg, &r);
317: if (tresult != ISC_R_SUCCESS) {
318: cfg_obj_log(cfg_listelt_value(element), logctx,
319: ISC_LOG_ERROR, "invalid algorithm '%s'",
320: r.base);
321: result = tresult;
322: }
323: }
324: return (result);
325: }
326:
327: static isc_result_t
328: disabled_ds_digests(const cfg_obj_t *disabled, isc_log_t *logctx) {
329: isc_result_t result = ISC_R_SUCCESS;
330: isc_result_t tresult;
331: const cfg_listelt_t *element;
332: const char *str;
333: isc_buffer_t b;
334: dns_fixedname_t fixed;
335: dns_name_t *name;
336: const cfg_obj_t *obj;
337:
338: name = dns_fixedname_initname(&fixed);
339: obj = cfg_tuple_get(disabled, "name");
340: str = cfg_obj_asstring(obj);
341: isc_buffer_constinit(&b, str, strlen(str));
342: isc_buffer_add(&b, strlen(str));
343: tresult = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
344: if (tresult != ISC_R_SUCCESS) {
345: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
346: "bad domain name '%s'", str);
347: result = tresult;
348: }
349:
350: obj = cfg_tuple_get(disabled, "digests");
351:
352: for (element = cfg_list_first(obj);
353: element != NULL;
354: element = cfg_list_next(element))
355: {
356: isc_textregion_t r;
357: dns_dsdigest_t digest;
358:
359: DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
360: r.length = strlen(r.base);
361:
362: /* works with a numeric argument too */
363: tresult = dns_dsdigest_fromtext(&digest, &r);
364: if (tresult != ISC_R_SUCCESS) {
365: cfg_obj_log(cfg_listelt_value(element), logctx,
366: ISC_LOG_ERROR, "invalid digest type '%s'",
367: r.base);
368: result = tresult;
369: }
370: }
371: return (result);
372: }
373:
374: static isc_result_t
375: nameexist(const cfg_obj_t *obj, const char *name, int value,
376: isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
377: isc_mem_t *mctx)
378: {
379: char *key;
380: const char *file;
381: unsigned int line;
382: isc_result_t result;
383: isc_symvalue_t symvalue;
384:
385: key = isc_mem_strdup(mctx, name);
386: if (key == NULL)
387: return (ISC_R_NOMEMORY);
388: symvalue.as_cpointer = obj;
389: result = isc_symtab_define(symtab, key, value, symvalue,
390: isc_symexists_reject);
391: if (result == ISC_R_EXISTS) {
392: RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
393: &symvalue) == ISC_R_SUCCESS);
394: file = cfg_obj_file(symvalue.as_cpointer);
395: line = cfg_obj_line(symvalue.as_cpointer);
396:
397: if (file == NULL)
398: file = "<unknown file>";
399: cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
400: isc_mem_free(mctx, key);
401: result = ISC_R_EXISTS;
402: } else if (result != ISC_R_SUCCESS) {
403: isc_mem_free(mctx, key);
404: }
405: return (result);
406: }
407:
408: static isc_result_t
409: mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
410: isc_mem_t *mctx)
411: {
412: const cfg_obj_t *obj;
413: char namebuf[DNS_NAME_FORMATSIZE];
414: const char *str;
415: dns_fixedname_t fixed;
416: dns_name_t *name;
417: isc_buffer_t b;
418: isc_result_t result = ISC_R_SUCCESS;
419:
420: name = dns_fixedname_initname(&fixed);
421: obj = cfg_tuple_get(secure, "name");
422: str = cfg_obj_asstring(obj);
423: isc_buffer_constinit(&b, str, strlen(str));
424: isc_buffer_add(&b, strlen(str));
425: result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
426: if (result != ISC_R_SUCCESS) {
427: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
428: "bad domain name '%s'", str);
429: } else {
430: dns_name_format(name, namebuf, sizeof(namebuf));
431: result = nameexist(secure, namebuf, 1, symtab,
432: "dnssec-must-be-secure '%s': already "
433: "exists previous definition: %s:%u",
434: logctx, mctx);
435: }
436: return (result);
437: }
438:
439: static isc_result_t
440: checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
441: const cfg_obj_t *voptions, const cfg_obj_t *config,
442: isc_log_t *logctx, isc_mem_t *mctx)
443: {
444: isc_result_t result;
445: const cfg_obj_t *aclobj = NULL;
446: const cfg_obj_t *options;
447: dns_acl_t *acl = NULL;
448:
449: if (zconfig != NULL) {
450: options = cfg_tuple_get(zconfig, "options");
451: cfg_map_get(options, aclname, &aclobj);
452: }
453: if (voptions != NULL && aclobj == NULL)
454: cfg_map_get(voptions, aclname, &aclobj);
455: if (config != NULL && aclobj == NULL) {
456: options = NULL;
457: cfg_map_get(config, "options", &options);
458: if (options != NULL)
459: cfg_map_get(options, aclname, &aclobj);
460: }
461: if (aclobj == NULL)
462: return (ISC_R_SUCCESS);
463: result = cfg_acl_fromconfig(aclobj, config, logctx,
464: actx, mctx, 0, &acl);
465: if (acl != NULL)
466: dns_acl_detach(&acl);
467: return (result);
468: }
469:
470: static isc_result_t
471: check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
472: const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
473: {
474: isc_result_t result = ISC_R_SUCCESS, tresult;
475: int i = 0;
476:
477: static const char *acls[] = { "allow-query", "allow-query-on",
478: "allow-query-cache", "allow-query-cache-on",
479: "blackhole", "keep-response-order", "match-clients",
1.3 christos 480: "match-destinations", "sortlist", NULL };
1.1 christos 481:
482: while (acls[i] != NULL) {
483: tresult = checkacl(acls[i++], actx, NULL, voptions, config,
484: logctx, mctx);
485: if (tresult != ISC_R_SUCCESS)
486: result = tresult;
487: }
488: return (result);
489: }
490:
491: static const unsigned char zeros[16];
492:
493: static isc_result_t
494: check_dns64(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
495: const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
496: {
497: isc_result_t result = ISC_R_SUCCESS;
498: const cfg_obj_t *dns64 = NULL;
499: const cfg_obj_t *options;
500: const cfg_listelt_t *element;
501: const cfg_obj_t *map, *obj;
502: isc_netaddr_t na, sa;
503: unsigned int prefixlen;
504: int nbytes;
505: int i;
506:
507: static const char *acls[] = { "clients", "exclude", "mapped", NULL};
508:
509: if (voptions != NULL)
510: cfg_map_get(voptions, "dns64", &dns64);
511: if (config != NULL && dns64 == NULL) {
512: options = NULL;
513: cfg_map_get(config, "options", &options);
514: if (options != NULL)
515: cfg_map_get(options, "dns64", &dns64);
516: }
517: if (dns64 == NULL)
518: return (ISC_R_SUCCESS);
519:
520: for (element = cfg_list_first(dns64);
521: element != NULL;
522: element = cfg_list_next(element))
523: {
524: map = cfg_listelt_value(element);
525: obj = cfg_map_getname(map);
526:
527: cfg_obj_asnetprefix(obj, &na, &prefixlen);
528: if (na.family != AF_INET6) {
529: cfg_obj_log(map, logctx, ISC_LOG_ERROR,
530: "dns64 requires a IPv6 prefix");
531: result = ISC_R_FAILURE;
532: continue;
533: }
534:
1.6 ! christos 535: if (na.type.in6.s6_addr[8] != 0) {
! 536: cfg_obj_log(map, logctx, ISC_LOG_WARNING,
! 537: "warning: invalid prefix, bits [64..71] "
! 538: "must be zero");
! 539: }
! 540:
1.1 christos 541: if (prefixlen != 32 && prefixlen != 40 && prefixlen != 48 &&
542: prefixlen != 56 && prefixlen != 64 && prefixlen != 96) {
543: cfg_obj_log(map, logctx, ISC_LOG_ERROR,
544: "bad prefix length %u [32/40/48/56/64/96]",
545: prefixlen);
546: result = ISC_R_FAILURE;
547: continue;
548: }
549:
550: for (i = 0; acls[i] != NULL; i++) {
551: obj = NULL;
552: (void)cfg_map_get(map, acls[i], &obj);
553: if (obj != NULL) {
554: dns_acl_t *acl = NULL;
555: isc_result_t tresult;
556:
557: tresult = cfg_acl_fromconfig(obj, config,
558: logctx, actx,
559: mctx, 0, &acl);
560: if (acl != NULL)
561: dns_acl_detach(&acl);
562: if (tresult != ISC_R_SUCCESS)
563: result = tresult;
564: }
565: }
566:
567: obj = NULL;
568: (void)cfg_map_get(map, "suffix", &obj);
569: if (obj != NULL) {
570: isc_netaddr_fromsockaddr(&sa, cfg_obj_assockaddr(obj));
571: if (sa.family != AF_INET6) {
572: cfg_obj_log(map, logctx, ISC_LOG_ERROR,
573: "dns64 requires a IPv6 suffix");
574: result = ISC_R_FAILURE;
575: continue;
576: }
577: nbytes = prefixlen / 8 + 4;
1.3 christos 578: if (prefixlen <= 64)
1.1 christos 579: nbytes++;
580: if (memcmp(sa.type.in6.s6_addr, zeros, nbytes) != 0) {
581: char netaddrbuf[ISC_NETADDR_FORMATSIZE];
582: isc_netaddr_format(&sa, netaddrbuf,
583: sizeof(netaddrbuf));
584: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
585: "bad suffix '%s' leading "
586: "%u octets not zeros",
587: netaddrbuf, nbytes);
588: result = ISC_R_FAILURE;
589: }
590: }
591: }
592:
593: return (result);
594: }
595:
596: #define CHECK_RRL(cond, pat, val1, val2) \
597: do { \
598: if (!(cond)) { \
599: cfg_obj_log(obj, logctx, ISC_LOG_ERROR, \
600: pat, val1, val2); \
601: if (result == ISC_R_SUCCESS) \
602: result = ISC_R_RANGE; \
603: } \
604: } while (0)
605:
606: #define CHECK_RRL_RATE(rate, def, max_rate, name) \
607: do { \
608: obj = NULL; \
609: mresult = cfg_map_get(map, name, &obj); \
610: if (mresult == ISC_R_SUCCESS) { \
611: rate = cfg_obj_asuint32(obj); \
612: CHECK_RRL(rate <= max_rate, name" %d > %d", \
613: rate, max_rate); \
614: } \
615: } while (0)
616:
617: static isc_result_t
618: check_ratelimit(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
619: const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
620: {
621: isc_result_t result = ISC_R_SUCCESS;
622: isc_result_t mresult;
623: const cfg_obj_t *map = NULL;
624: const cfg_obj_t *options;
625: const cfg_obj_t *obj;
626: int min_entries, i;
627: int all_per_second;
628: int errors_per_second;
629: int nodata_per_second;
630: int nxdomains_per_second;
631: int referrals_per_second;
632: int responses_per_second;
633: int slip;
634:
635: if (voptions != NULL)
636: cfg_map_get(voptions, "rate-limit", &map);
637: if (config != NULL && map == NULL) {
638: options = NULL;
639: cfg_map_get(config, "options", &options);
640: if (options != NULL)
641: cfg_map_get(options, "rate-limit", &map);
642: }
643: if (map == NULL)
644: return (ISC_R_SUCCESS);
645:
646: min_entries = 500;
647: obj = NULL;
648: mresult = cfg_map_get(map, "min-table-size", &obj);
649: if (mresult == ISC_R_SUCCESS) {
650: min_entries = cfg_obj_asuint32(obj);
651: if (min_entries < 1)
652: min_entries = 1;
653: }
654:
655: obj = NULL;
656: mresult = cfg_map_get(map, "max-table-size", &obj);
657: if (mresult == ISC_R_SUCCESS) {
658: i = cfg_obj_asuint32(obj);
659: CHECK_RRL(i >= min_entries,
660: "max-table-size %d < min-table-size %d",
661: i, min_entries);
662: }
663:
664: CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
665: "responses-per-second");
666:
667: CHECK_RRL_RATE(referrals_per_second, responses_per_second,
668: DNS_RRL_MAX_RATE, "referrals-per-second");
669: CHECK_RRL_RATE(nodata_per_second, responses_per_second,
670: DNS_RRL_MAX_RATE, "nodata-per-second");
671: CHECK_RRL_RATE(nxdomains_per_second, responses_per_second,
672: DNS_RRL_MAX_RATE, "nxdomains-per-second");
673: CHECK_RRL_RATE(errors_per_second, responses_per_second,
674: DNS_RRL_MAX_RATE, "errors-per-second");
675:
676: CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE, "all-per-second");
677:
678: CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP, "slip");
679:
680: obj = NULL;
681: mresult = cfg_map_get(map, "window", &obj);
682: if (mresult == ISC_R_SUCCESS) {
683: i = cfg_obj_asuint32(obj);
684: CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
685: "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
686: }
687:
688: obj = NULL;
689: mresult = cfg_map_get(map, "qps-scale", &obj);
690: if (mresult == ISC_R_SUCCESS) {
691: i = cfg_obj_asuint32(obj);
692: CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
693: }
694:
695: obj = NULL;
696: mresult = cfg_map_get(map, "ipv4-prefix-length", &obj);
697: if (mresult == ISC_R_SUCCESS) {
698: i = cfg_obj_asuint32(obj);
699: CHECK_RRL(i >= 8 && i <= 32,
700: "invalid 'ipv4-prefix-length %d'%s", i, "");
701: }
702:
703: obj = NULL;
704: mresult = cfg_map_get(map, "ipv6-prefix-length", &obj);
705: if (mresult == ISC_R_SUCCESS) {
706: i = cfg_obj_asuint32(obj);
707: CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
708: "ipv6-prefix-length %d < 16 or > %d",
709: i, DNS_RRL_MAX_PREFIX);
710: }
711:
712: obj = NULL;
713: (void)cfg_map_get(map, "exempt-clients", &obj);
714: if (obj != NULL) {
715: dns_acl_t *acl = NULL;
716: isc_result_t tresult;
717:
718: tresult = cfg_acl_fromconfig(obj, config, logctx, actx,
719: mctx, 0, &acl);
720: if (acl != NULL)
721: dns_acl_detach(&acl);
722: if (result == ISC_R_SUCCESS)
723: result = tresult;
724: }
725:
726: return (result);
727: }
728:
729: /*
730: * Check allow-recursion and allow-recursion-on acls, and also log a
731: * warning if they're inconsistent with the "recursion" option.
732: */
733: static isc_result_t
734: check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
735: const char *viewname, const cfg_obj_t *config,
736: isc_log_t *logctx, isc_mem_t *mctx)
737: {
738: const cfg_obj_t *options, *aclobj, *obj = NULL;
739: dns_acl_t *acl = NULL;
740: isc_result_t result = ISC_R_SUCCESS, tresult;
1.3 christos 741: bool recursion;
1.1 christos 742: const char *forview = " for view ";
743: int i = 0;
744:
745: static const char *acls[] = { "allow-recursion", "allow-recursion-on",
746: NULL };
747:
748: if (voptions != NULL)
749: cfg_map_get(voptions, "recursion", &obj);
750: if (obj == NULL && config != NULL) {
751: options = NULL;
752: cfg_map_get(config, "options", &options);
753: if (options != NULL)
754: cfg_map_get(options, "recursion", &obj);
755: }
756: if (obj == NULL)
1.3 christos 757: recursion = true;
1.1 christos 758: else
759: recursion = cfg_obj_asboolean(obj);
760:
761: if (viewname == NULL) {
762: viewname = "";
763: forview = "";
764: }
765:
766: for (i = 0; acls[i] != NULL; i++) {
767: aclobj = options = NULL;
768: acl = NULL;
769:
770: if (voptions != NULL)
771: cfg_map_get(voptions, acls[i], &aclobj);
772: if (config != NULL && aclobj == NULL) {
773: options = NULL;
774: cfg_map_get(config, "options", &options);
775: if (options != NULL)
776: cfg_map_get(options, acls[i], &aclobj);
777: }
778: if (aclobj == NULL)
779: continue;
780:
781: tresult = cfg_acl_fromconfig(aclobj, config, logctx,
782: actx, mctx, 0, &acl);
783:
784: if (tresult != ISC_R_SUCCESS)
785: result = tresult;
786:
787: if (acl == NULL)
788: continue;
789:
1.3 christos 790: if (recursion == false && !dns_acl_isnone(acl)) {
1.1 christos 791: cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING,
792: "both \"recursion no;\" and "
793: "\"%s\" active%s%s",
794: acls[i], forview, viewname);
795: }
796:
797: if (acl != NULL)
798: dns_acl_detach(&acl);
799: }
800:
801: return (result);
802: }
803:
804: typedef struct {
805: const char *name;
806: unsigned int scale;
807: unsigned int max;
808: } intervaltable;
809:
810: #ifdef HAVE_DNSTAP
811: typedef struct {
812: const char *name;
813: unsigned int min;
814: unsigned int max;
815: } fstrmtable;
816: #endif
817:
818: typedef enum {
819: optlevel_config,
820: optlevel_options,
821: optlevel_view,
822: optlevel_zone
823: } optlevel_t;
824:
825: static isc_result_t
826: check_dscp(const cfg_obj_t *options, isc_log_t *logctx) {
827: isc_result_t result = ISC_R_SUCCESS;
828: const cfg_obj_t *obj = NULL;
829:
830: /*
831: * Check that DSCP setting is within range
832: */
833: obj = NULL;
834: (void)cfg_map_get(options, "dscp", &obj);
835: if (obj != NULL) {
1.3 christos 836: uint32_t dscp = cfg_obj_asuint32(obj);
1.1 christos 837: if (dscp >= 64) {
838: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
839: "'dscp' out of range (0-63)");
840: result = ISC_R_FAILURE;
841: }
842: }
843:
844: return (result);
845: }
846:
847: static isc_result_t
848: check_name(const char *str) {
849: dns_fixedname_t fixed;
850:
851: dns_fixedname_init(&fixed);
852: return (dns_name_fromstring(dns_fixedname_name(&fixed), str, 0, NULL));
853: }
854:
855: static isc_result_t
856: check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
857: optlevel_t optlevel)
858: {
859: isc_result_t result = ISC_R_SUCCESS;
860: isc_result_t tresult;
861: unsigned int i;
862: const cfg_obj_t *obj = NULL;
863: const cfg_obj_t *resignobj = NULL;
864: const cfg_listelt_t *element;
865: isc_symtab_t *symtab = NULL;
866: dns_fixedname_t fixed;
867: const char *str;
868: dns_name_t *name;
869: isc_buffer_t b;
1.3 christos 870: uint32_t lifetime = 3600;
1.6 ! christos 871: const char *ccalg = "siphash24";
1.1 christos 872:
1.3 christos 873: /*
874: * { "name", scale, value }
875: * (scale * value) <= UINT32_MAX
876: */
1.1 christos 877: static intervaltable intervals[] = {
1.3 christos 878: { "cleaning-interval", 60, 28 * 24 * 60 }, /* 28 days */
879: { "heartbeat-interval", 60, 28 * 24 * 60 }, /* 28 days */
880: { "interface-interval", 60, 28 * 24 * 60 }, /* 28 days */
881: { "max-transfer-idle-in", 60, 28 * 24 * 60 }, /* 28 days */
882: { "max-transfer-idle-out", 60, 28 * 24 * 60 }, /* 28 days */
883: { "max-transfer-time-in", 60, 28 * 24 * 60 }, /* 28 days */
884: { "max-transfer-time-out", 60, 28 * 24 * 60 }, /* 28 days */
885: { "statistics-interval", 60, 28 * 24 * 60 }, /* 28 days */
886:
887: /* minimum and maximum cache and negative cache TTLs */
888: { "min-cache-ttl", 1, MAX_MIN_CACHE_TTL }, /* 90 secs */
889: { "max-cache-ttl", 1, UINT32_MAX }, /* no limit */
890: { "min-ncache-ttl", 1, MAX_MIN_NCACHE_TTL}, /* 90 secs */
891: { "max-ncache-ttl", 1, MAX_MAX_NCACHE_TTL }, /* 7 days */
1.1 christos 892: };
893:
894: static const char *server_contact[] = {
895: "empty-server", "empty-contact",
896: "dns64-server", "dns64-contact",
897: NULL
898: };
899:
900: #ifdef HAVE_DNSTAP
901: static fstrmtable fstrm[] = {
902: {
903: "fstrm-set-buffer-hint",
904: FSTRM_IOTHR_BUFFER_HINT_MIN,
905: FSTRM_IOTHR_BUFFER_HINT_MAX
906: },
907: {
908: "fstrm-set-flush-timeout",
909: FSTRM_IOTHR_FLUSH_TIMEOUT_MIN,
910: FSTRM_IOTHR_FLUSH_TIMEOUT_MAX
911: },
912: {
913: "fstrm-set-input-queue-size",
914: FSTRM_IOTHR_INPUT_QUEUE_SIZE_MIN,
915: FSTRM_IOTHR_INPUT_QUEUE_SIZE_MAX
916: },
917: {
918: "fstrm-set-output-notify-threshold",
919: FSTRM_IOTHR_QUEUE_NOTIFY_THRESHOLD_MIN,
920: 0
921: },
922: {
923: "fstrm-set-output-queue-size",
924: FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MIN,
925: FSTRM_IOTHR_OUTPUT_QUEUE_SIZE_MAX
926: },
927: {
928: "fstrm-set-reopen-interval",
929: FSTRM_IOTHR_REOPEN_INTERVAL_MIN,
930: FSTRM_IOTHR_REOPEN_INTERVAL_MAX
931: }
932: };
933: #endif
934:
935: /*
936: * Check that fields specified in units of time other than seconds
937: * have reasonable values.
938: */
939: for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
1.3 christos 940: uint32_t val;
1.1 christos 941: obj = NULL;
942: (void)cfg_map_get(options, intervals[i].name, &obj);
943: if (obj == NULL)
944: continue;
945: val = cfg_obj_asuint32(obj);
946: if (val > intervals[i].max) {
947: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
948: "%s '%u' is out of range (0..%u)",
949: intervals[i].name, val,
950: intervals[i].max);
951: result = ISC_R_RANGE;
1.3 christos 952: } else if (val > (UINT32_MAX / intervals[i].scale)) {
1.1 christos 953: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
954: "%s '%d' is out of range",
955: intervals[i].name, val);
956: result = ISC_R_RANGE;
957: }
958: }
959:
960: obj = NULL;
961: cfg_map_get(options, "max-rsa-exponent-size", &obj);
962: if (obj != NULL) {
1.3 christos 963: uint32_t val;
1.1 christos 964:
965: val = cfg_obj_asuint32(obj);
966: if (val != 0 && (val < 35 || val > 4096)) {
967: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
968: "max-rsa-exponent-size '%u' is out of "
969: "range (35..4096)", val);
970: result = ISC_R_RANGE;
971: }
972: }
973:
974: obj = NULL;
975: cfg_map_get(options, "sig-validity-interval", &obj);
976: if (obj != NULL) {
1.3 christos 977: uint32_t validity, resign = 0;
1.1 christos 978:
979: validity = cfg_obj_asuint32(cfg_tuple_get(obj, "validity"));
980: resignobj = cfg_tuple_get(obj, "re-sign");
981: if (!cfg_obj_isvoid(resignobj))
982: resign = cfg_obj_asuint32(resignobj);
983:
984: if (validity > 3660 || validity == 0) { /* 10 years */
985: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
986: "%s '%u' is out of range (1..3660)",
987: "sig-validity-interval", validity);
988: result = ISC_R_RANGE;
989: }
990:
991: if (!cfg_obj_isvoid(resignobj)) {
992: if (resign > 3660 || resign == 0) { /* 10 years */
993: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
994: "%s '%u' is out of range (1..3660)",
995: "sig-validity-interval (re-sign)",
996: validity);
997: result = ISC_R_RANGE;
998: } else if ((validity > 7 && validity < resign) ||
999: (validity <= 7 && validity * 24 < resign)) {
1000: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1001: "validity interval (%u days) "
1002: "less than re-signing interval "
1003: "(%u %s)", validity, resign,
1004: (validity > 7) ? "days" : "hours");
1005: result = ISC_R_RANGE;
1006: }
1007: }
1008: }
1009:
1010: obj = NULL;
1.3 christos 1011: cfg_map_get(options, "dnskey-sig-validity", &obj);
1012: if (obj != NULL) {
1013: uint32_t keyvalidity;
1014:
1015: keyvalidity = cfg_obj_asuint32(obj);
1016: if (keyvalidity > 3660 || keyvalidity == 0) { /* 10 years */
1017: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1018: "%s '%u' is out of range (1..3660)",
1019: "dnskey-sig-validity",
1020: keyvalidity);
1021: result = ISC_R_RANGE;
1022: }
1023:
1024: }
1025:
1026: obj = NULL;
1.1 christos 1027: (void)cfg_map_get(options, "preferred-glue", &obj);
1028: if (obj != NULL) {
1029: str = cfg_obj_asstring(obj);
1030: if (strcasecmp(str, "a") != 0 &&
1031: strcasecmp(str, "aaaa") != 0 &&
1032: strcasecmp(str, "none") != 0)
1033: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1034: "preferred-glue unexpected value '%s'",
1035: str);
1036: }
1037:
1038: obj = NULL;
1039: (void)cfg_map_get(options, "root-delegation-only", &obj);
1040: if (obj != NULL) {
1041: if (!cfg_obj_isvoid(obj)) {
1042: for (element = cfg_list_first(obj);
1043: element != NULL;
1044: element = cfg_list_next(element)) {
1045: const cfg_obj_t *exclude;
1046:
1047: exclude = cfg_listelt_value(element);
1048: str = cfg_obj_asstring(exclude);
1049: tresult = check_name(str);
1050: if (tresult != ISC_R_SUCCESS) {
1051: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1052: "bad domain name '%s'",
1053: str);
1054: result = tresult;
1055: }
1056: }
1057: }
1058: }
1059:
1060: /*
1061: * Set supported DNSSEC algorithms.
1062: */
1063: obj = NULL;
1064: (void)cfg_map_get(options, "disable-algorithms", &obj);
1065: if (obj != NULL) {
1066: for (element = cfg_list_first(obj);
1067: element != NULL;
1068: element = cfg_list_next(element))
1069: {
1070: obj = cfg_listelt_value(element);
1071: tresult = disabled_algorithms(obj, logctx);
1072: if (tresult != ISC_R_SUCCESS)
1073: result = tresult;
1074: }
1075: }
1076:
1077: /*
1078: * Set supported DS/DLV digest types.
1079: */
1080: obj = NULL;
1081: (void)cfg_map_get(options, "disable-ds-digests", &obj);
1082: if (obj != NULL) {
1083: for (element = cfg_list_first(obj);
1084: element != NULL;
1085: element = cfg_list_next(element))
1086: {
1087: obj = cfg_listelt_value(element);
1088: tresult = disabled_ds_digests(obj, logctx);
1089: if (tresult != ISC_R_SUCCESS)
1090: result = tresult;
1091: }
1092: }
1093:
1094: name = dns_fixedname_initname(&fixed);
1095:
1096: /*
1097: * Check the DLV zone name.
1098: */
1099: obj = NULL;
1100: (void)cfg_map_get(options, "dnssec-lookaside", &obj);
1101: if (obj != NULL) {
1102: tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1.3 christos 1103: false, &symtab);
1.1 christos 1104: if (tresult != ISC_R_SUCCESS)
1105: result = tresult;
1106: for (element = cfg_list_first(obj);
1107: element != NULL;
1108: element = cfg_list_next(element))
1109: {
1110: const char *dlv;
1111: const cfg_obj_t *dlvobj, *anchor;
1112:
1113: obj = cfg_listelt_value(element);
1114:
1115: anchor = cfg_tuple_get(obj, "trust-anchor");
1116: dlvobj = cfg_tuple_get(obj, "domain");
1117: dlv = cfg_obj_asstring(dlvobj);
1118:
1119: /*
1120: * If domain is "auto" or "no" and trust anchor
1121: * is missing, skip remaining tests
1122: */
1123: if (cfg_obj_isvoid(anchor)) {
1124: if (!strcasecmp(dlv, "no")) {
1125: continue;
1126: }
1127: if (!strcasecmp(dlv, "auto")) {
1128: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1129: "dnssec-lookaside 'auto' "
1130: "is no longer supported");
1131: continue;
1132: }
1133: }
1134:
1135: tresult = dns_name_fromstring(name, dlv, 0, NULL);
1136: if (tresult != ISC_R_SUCCESS) {
1137: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1138: "bad domain name '%s'", dlv);
1139: result = tresult;
1140: continue;
1141: }
1142: if (symtab != NULL) {
1143: tresult = nameexist(obj, dlv, 1, symtab,
1144: "dnssec-lookaside '%s': "
1145: "already exists; previous "
1146: "definition: %s:%u",
1147: logctx, mctx);
1148: if (tresult != ISC_R_SUCCESS &&
1149: result == ISC_R_SUCCESS)
1150: result = tresult;
1151: }
1152:
1153: /*
1154: * XXXMPA to be removed when multiple lookaside
1155: * namespaces are supported.
1156: */
1157: if (!dns_name_equal(dns_rootname, name)) {
1158: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1159: "dnssec-lookaside '%s': "
1160: "non-root not yet supported", dlv);
1161: if (result == ISC_R_SUCCESS)
1162: result = ISC_R_FAILURE;
1163: }
1164:
1165: if (cfg_obj_isvoid(anchor)) {
1166: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1167: "dnssec-lookaside requires "
1168: "either or 'no' or a "
1169: "domain and trust anchor");
1170: if (result == ISC_R_SUCCESS)
1171: result = ISC_R_FAILURE;
1172: continue;
1173: }
1174:
1175: dlv = cfg_obj_asstring(anchor);
1176: tresult = dns_name_fromstring(name, dlv, 0, NULL);
1177: if (tresult != ISC_R_SUCCESS) {
1178: cfg_obj_log(anchor, logctx, ISC_LOG_ERROR,
1179: "bad domain name '%s'", dlv);
1180: if (result == ISC_R_SUCCESS)
1181: result = tresult;
1182: continue;
1183: }
1184: if (dns_name_equal(&dlviscorg, name)) {
1185: cfg_obj_log(anchor, logctx, ISC_LOG_WARNING,
1186: "dlv.isc.org has been shut down");
1187: continue;
1188: }
1189: }
1190:
1191: if (symtab != NULL)
1192: isc_symtab_destroy(&symtab);
1193: }
1194:
1195: /*
1196: * Check auto-dnssec at the view/options level
1197: */
1198: obj = NULL;
1199: (void)cfg_map_get(options, "auto-dnssec", &obj);
1200: if (obj != NULL) {
1201: const char *arg = cfg_obj_asstring(obj);
1202: if (optlevel != optlevel_zone && strcasecmp(arg, "off") != 0) {
1203: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1204: "auto-dnssec may only be activated at the "
1205: "zone level");
1206: if (result == ISC_R_SUCCESS)
1207: result = ISC_R_FAILURE;
1208: }
1209: }
1210:
1211: /*
1212: * Check dnssec-must-be-secure.
1213: */
1214: obj = NULL;
1215: (void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
1216: if (obj != NULL) {
1217: tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1.3 christos 1218: false, &symtab);
1.1 christos 1219: if (tresult != ISC_R_SUCCESS)
1220: result = tresult;
1221: for (element = cfg_list_first(obj);
1222: element != NULL;
1223: element = cfg_list_next(element))
1224: {
1225: obj = cfg_listelt_value(element);
1226: tresult = mustbesecure(obj, symtab, logctx, mctx);
1227: if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
1228: result = tresult;
1229: }
1230: if (symtab != NULL)
1231: isc_symtab_destroy(&symtab);
1232: }
1233:
1234: /*
1235: * Check server/contacts for syntactic validity.
1236: */
1237: for (i= 0; server_contact[i] != NULL; i++) {
1238: obj = NULL;
1239: (void)cfg_map_get(options, server_contact[i], &obj);
1240: if (obj != NULL) {
1241: str = cfg_obj_asstring(obj);
1242: if (check_name(str) != ISC_R_SUCCESS) {
1243: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1244: "%s: invalid name '%s'",
1245: server_contact[i], str);
1246: if (result == ISC_R_SUCCESS)
1247: result = ISC_R_FAILURE;
1248: }
1249: }
1250: }
1251:
1252: /*
1253: * Check empty zone configuration.
1254: */
1255: obj = NULL;
1256: (void)cfg_map_get(options, "disable-empty-zone", &obj);
1257: for (element = cfg_list_first(obj);
1258: element != NULL;
1259: element = cfg_list_next(element))
1260: {
1261: obj = cfg_listelt_value(element);
1262: str = cfg_obj_asstring(obj);
1263: if (check_name(str) != ISC_R_SUCCESS) {
1264: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1265: "disable-empty-zone: invalid name '%s'",
1266: str);
1267: if (result == ISC_R_SUCCESS)
1268: result = ISC_R_FAILURE;
1269: }
1270: }
1271:
1272: /*
1273: * Check that server-id is not too long.
1274: * 1024 bytes should be big enough.
1275: */
1276: obj = NULL;
1277: (void)cfg_map_get(options, "server-id", &obj);
1278: if (obj != NULL && cfg_obj_isstring(obj) &&
1279: strlen(cfg_obj_asstring(obj)) > 1024U) {
1280: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1281: "'server-id' too big (>1024 bytes)");
1282: if (result == ISC_R_SUCCESS)
1283: result = ISC_R_FAILURE;
1284: }
1285:
1286: tresult = check_dscp(options, logctx);
1287: if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
1288: result = tresult;
1289:
1290: obj = NULL;
1291: (void)cfg_map_get(options, "nta-lifetime", &obj);
1292: if (obj != NULL) {
1293: lifetime = cfg_obj_asuint32(obj);
1294: if (lifetime > 604800) { /* 7 days */
1295: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1296: "'nta-lifetime' cannot exceed one week");
1297: if (result == ISC_R_SUCCESS)
1298: result = ISC_R_RANGE;
1299: } else if (lifetime == 0) {
1300: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1301: "'nta-lifetime' may not be zero");
1302: if (result == ISC_R_SUCCESS)
1303: result = ISC_R_RANGE;
1304: }
1305: }
1306:
1307: obj = NULL;
1308: (void)cfg_map_get(options, "nta-recheck", &obj);
1309: if (obj != NULL) {
1.3 christos 1310: uint32_t recheck = cfg_obj_asuint32(obj);
1.1 christos 1311: if (recheck > 604800) { /* 7 days */
1312: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1313: "'nta-recheck' cannot exceed one week");
1314: if (result == ISC_R_SUCCESS)
1315: result = ISC_R_RANGE;
1316: }
1317:
1318: if (recheck > lifetime)
1319: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1320: "'nta-recheck' (%d seconds) is "
1321: "greater than 'nta-lifetime' "
1322: "(%d seconds)", recheck, lifetime);
1323: }
1324:
1325: obj = NULL;
1326: (void) cfg_map_get(options, "cookie-algorithm", &obj);
1.3 christos 1327: if (obj != NULL) {
1.1 christos 1328: ccalg = cfg_obj_asstring(obj);
1329: }
1330:
1331: obj = NULL;
1332: (void) cfg_map_get(options, "cookie-secret", &obj);
1333: if (obj != NULL) {
1334: unsigned char secret[32];
1335:
1336: for (element = cfg_list_first(obj);
1337: element != NULL;
1338: element = cfg_list_next(element)) {
1339: unsigned int usedlength;
1340:
1341: obj = cfg_listelt_value(element);
1342: str = cfg_obj_asstring(obj);
1343:
1344: memset(secret, 0, sizeof(secret));
1345: isc_buffer_init(&b, secret, sizeof(secret));
1346: tresult = isc_hex_decodestring(str, &b);
1347: if (tresult == ISC_R_NOSPACE) {
1348: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1349: "cookie-secret: too long");
1350: } else if (tresult != ISC_R_SUCCESS) {
1351: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1352: "cookie-secret: invalid hex "
1353: "string");
1354: }
1355: if (tresult != ISC_R_SUCCESS) {
1356: if (result == ISC_R_SUCCESS)
1357: result = tresult;
1358: continue;
1359: }
1360:
1361: usedlength = isc_buffer_usedlength(&b);
1362: if (strcasecmp(ccalg, "aes") == 0 &&
1363: usedlength != ISC_AES128_KEYLENGTH) {
1364: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1.6 ! christos 1365: "AES cookie-secret must be 128 bits");
! 1366: if (result == ISC_R_SUCCESS)
! 1367: result = ISC_R_RANGE;
! 1368: }
! 1369: if (strcasecmp(ccalg, "siphash24") == 0 &&
! 1370: usedlength != ISC_SIPHASH24_KEY_LENGTH) {
! 1371: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
! 1372: "SipHash-2-4 cookie-secret must be 128 bits");
1.1 christos 1373: if (result == ISC_R_SUCCESS)
1374: result = ISC_R_RANGE;
1375: }
1376: if (strcasecmp(ccalg, "sha1") == 0 &&
1377: usedlength != ISC_SHA1_DIGESTLENGTH) {
1378: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1379: "SHA1 cookie-secret must be "
1380: "160 bits");
1381: if (result == ISC_R_SUCCESS)
1382: result = ISC_R_RANGE;
1383: }
1384: if (strcasecmp(ccalg, "sha256") == 0 &&
1385: usedlength != ISC_SHA256_DIGESTLENGTH) {
1386: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1387: "SHA256 cookie-secret must be "
1388: "256 bits");
1389: if (result == ISC_R_SUCCESS)
1390: result = ISC_R_RANGE;
1391: }
1392: }
1393: }
1394:
1395: #ifdef HAVE_DNSTAP
1396: for (i = 0; i < sizeof(fstrm) / sizeof(fstrm[0]); i++) {
1.3 christos 1397: uint32_t value;
1.1 christos 1398:
1399: obj = NULL;
1400: (void) cfg_map_get(options, fstrm[i].name, &obj);
1401: if (obj == NULL)
1402: continue;
1403:
1404: value = cfg_obj_asuint32(obj);
1405: if (value < fstrm[i].min ||
1406: (fstrm[i].max != 0U && value > fstrm[i].max)) {
1407: if (fstrm[i].max != 0U)
1408: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1409: "%s '%u' out of range (%u..%u)",
1410: fstrm[i].name, value,
1411: fstrm[i].min, fstrm[i].max);
1412: else
1413: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1414: "%s out of range (%u < %u)",
1415: fstrm[i].name, value, fstrm[i].min);
1416: if (result == ISC_R_SUCCESS)
1417: result = ISC_R_RANGE;
1418: }
1419:
1420: if (strcmp(fstrm[i].name, "fstrm-set-input-queue-size") == 0) {
1421: int bits = 0;
1422: do {
1423: bits += value & 0x1;
1424: value >>= 1;
1425: } while (value != 0U);
1426: if (bits != 1) {
1427: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1428: "%s '%u' not a power-of-2",
1429: fstrm[i].name,
1430: cfg_obj_asuint32(obj));
1431: if (result == ISC_R_SUCCESS)
1432: result = ISC_R_RANGE;
1433: }
1434: }
1435: }
1436:
1437: /* Check that dnstap-ouput values are consistent */
1438: obj = NULL;
1439: (void) cfg_map_get(options, "dnstap-output", &obj);
1440: if (obj != NULL) {
1441: const cfg_obj_t *obj2;
1442: dns_dtmode_t dmode;
1443:
1444: obj2 = cfg_tuple_get(obj, "mode");
1445: if (obj2 == NULL) {
1446: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1447: "dnstap-output mode not found");
1448: if (result == ISC_R_SUCCESS)
1449: result = ISC_R_FAILURE;
1450: } else {
1451: if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0)
1452: dmode = dns_dtmode_file;
1453: else
1454: dmode = dns_dtmode_unix;
1455:
1456: obj2 = cfg_tuple_get(obj, "size");
1457: if (obj2 != NULL && !cfg_obj_isvoid(obj2) &&
1458: dmode == dns_dtmode_unix)
1459: {
1460: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1461: "dnstap-output size "
1462: "cannot be set with mode unix");
1463: if (result == ISC_R_SUCCESS)
1464: result = ISC_R_FAILURE;
1465: }
1466:
1467: obj2 = cfg_tuple_get(obj, "versions");
1468: if (obj2 != NULL && !cfg_obj_isvoid(obj2) &&
1469: dmode == dns_dtmode_unix)
1470: {
1471: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1472: "dnstap-output versions "
1473: "cannot be set with mode unix");
1474: if (result == ISC_R_SUCCESS)
1475: result = ISC_R_FAILURE;
1476: }
1477:
1478: obj2 = cfg_tuple_get(obj, "suffix");
1479: if (obj2 != NULL && !cfg_obj_isvoid(obj2) &&
1480: dmode == dns_dtmode_unix)
1481: {
1482: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1483: "dnstap-output suffix "
1484: "cannot be set with mode unix");
1485: if (result == ISC_R_SUCCESS)
1486: result = ISC_R_FAILURE;
1487: }
1488: }
1.6 ! christos 1489: } else {
! 1490: (void) cfg_map_get(options, "dnstap", &obj);
! 1491: if (obj != NULL) {
! 1492: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
! 1493: "'dnstap-output' must be set if 'dnstap' "
! 1494: "is set");
! 1495: if (result == ISC_R_SUCCESS) {
! 1496: result = ISC_R_FAILURE;
! 1497: }
! 1498: }
1.1 christos 1499: }
1500: #endif
1501:
1502: obj = NULL;
1503: (void)cfg_map_get(options, "lmdb-mapsize", &obj);
1504: if (obj != NULL) {
1.3 christos 1505: uint64_t mapsize = cfg_obj_asuint64(obj);
1.1 christos 1506:
1507: if (mapsize < (1ULL << 20)) { /* 1 megabyte */
1508: cfg_obj_log(obj, logctx,
1509: ISC_LOG_ERROR,
1510: "'lmdb-mapsize "
1.3 christos 1511: "%" PRId64 "' "
1.1 christos 1512: "is too small",
1513: mapsize);
1514: if (result == ISC_R_SUCCESS)
1515: result = ISC_R_RANGE;
1516: } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
1517: cfg_obj_log(obj, logctx,
1518: ISC_LOG_ERROR,
1519: "'lmdb-mapsize "
1.3 christos 1520: "%" PRId64 "' "
1.1 christos 1521: "is too large",
1522: mapsize);
1523: if (result == ISC_R_SUCCESS)
1524: result = ISC_R_RANGE;
1525: }
1526: }
1527:
1528: obj = NULL;
1529: (void)cfg_map_get(options, "resolver-nonbackoff-tries", &obj);
1530: if (obj != NULL && cfg_obj_asuint32(obj) == 0U) {
1531: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1532: "'resolver-nonbackoff-tries' must be >= 1");
1533: if (result == ISC_R_SUCCESS)
1534: result = ISC_R_RANGE;
1535: }
1536:
1.3 christos 1537: obj = NULL;
1538: (void)cfg_map_get(options, "geoip-use-ecs", &obj);
1539: if (obj != NULL && cfg_obj_asboolean(obj)) {
1540: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1541: "'geoip-use-ecs yes': "
1542: "ECS can no longer be used in geoip ACLs");
1543: if (result == ISC_R_SUCCESS) {
1544: result = ISC_R_FAILURE;
1545: }
1546: }
1547:
1.1 christos 1548: return (result);
1549: }
1550:
1551: static isc_result_t
1552: get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
1553: isc_result_t result;
1554: const cfg_obj_t *masters = NULL;
1555: const cfg_listelt_t *elt;
1556:
1557: result = cfg_map_get(cctx, "masters", &masters);
1558: if (result != ISC_R_SUCCESS)
1559: return (result);
1560: for (elt = cfg_list_first(masters);
1561: elt != NULL;
1562: elt = cfg_list_next(elt)) {
1563: const cfg_obj_t *list;
1564: const char *listname;
1565:
1566: list = cfg_listelt_value(elt);
1567: listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
1568:
1569: if (strcasecmp(listname, name) == 0) {
1570: *ret = list;
1571: return (ISC_R_SUCCESS);
1572: }
1573: }
1574: return (ISC_R_NOTFOUND);
1575: }
1576:
1577: static isc_result_t
1578: validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
1.3 christos 1579: uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
1.1 christos 1580: {
1581: isc_result_t result = ISC_R_SUCCESS;
1582: isc_result_t tresult;
1.3 christos 1583: uint32_t count = 0;
1.1 christos 1584: isc_symtab_t *symtab = NULL;
1585: isc_symvalue_t symvalue;
1586: const cfg_listelt_t *element;
1587: const cfg_listelt_t **stack = NULL;
1.3 christos 1588: uint32_t stackcount = 0, pushed = 0;
1.1 christos 1589: const cfg_obj_t *list;
1590:
1591: REQUIRE(countp != NULL);
1.3 christos 1592: result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
1.1 christos 1593: if (result != ISC_R_SUCCESS) {
1594: *countp = count;
1595: return (result);
1596: }
1597:
1598: newlist:
1599: list = cfg_tuple_get(obj, "addresses");
1600: element = cfg_list_first(list);
1601: resume:
1602: for ( ;
1603: element != NULL;
1604: element = cfg_list_next(element))
1605: {
1606: const char *listname;
1607: const cfg_obj_t *addr;
1608: const cfg_obj_t *key;
1609:
1610: addr = cfg_tuple_get(cfg_listelt_value(element),
1611: "masterselement");
1612: key = cfg_tuple_get(cfg_listelt_value(element), "key");
1613:
1614: if (cfg_obj_issockaddr(addr)) {
1615: count++;
1616: continue;
1617: }
1618: if (!cfg_obj_isvoid(key)) {
1619: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1620: "unexpected token '%s'",
1621: cfg_obj_asstring(key));
1622: if (result == ISC_R_SUCCESS)
1623: result = ISC_R_FAILURE;
1624: }
1625: listname = cfg_obj_asstring(addr);
1626: symvalue.as_cpointer = addr;
1627: tresult = isc_symtab_define(symtab, listname, 1, symvalue,
1628: isc_symexists_reject);
1629: if (tresult == ISC_R_EXISTS)
1630: continue;
1631: tresult = get_masters_def(config, listname, &obj);
1632: if (tresult != ISC_R_SUCCESS) {
1633: if (result == ISC_R_SUCCESS)
1634: result = tresult;
1635: cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
1636: "unable to find masters list '%s'",
1637: listname);
1638: continue;
1639: }
1640: /* Grow stack? */
1641: if (stackcount == pushed) {
1642: void * newstack;
1.3 christos 1643: uint32_t newlen = stackcount + 16;
1.1 christos 1644: size_t newsize, oldsize;
1645:
1646: newsize = newlen * sizeof(*stack);
1647: oldsize = stackcount * sizeof(*stack);
1648: newstack = isc_mem_get(mctx, newsize);
1649: if (newstack == NULL)
1650: goto cleanup;
1651: if (stackcount != 0) {
1652: void *ptr;
1653:
1654: DE_CONST(stack, ptr);
1655: memmove(newstack, stack, oldsize);
1656: isc_mem_put(mctx, ptr, oldsize);
1657: }
1658: stack = newstack;
1659: stackcount = newlen;
1660: }
1661: stack[pushed++] = cfg_list_next(element);
1662: goto newlist;
1663: }
1664: if (pushed != 0) {
1665: element = stack[--pushed];
1666: goto resume;
1667: }
1668: cleanup:
1669: if (stack != NULL) {
1670: void *ptr;
1671:
1672: DE_CONST(stack, ptr);
1673: isc_mem_put(mctx, ptr, stackcount * sizeof(*stack));
1674: }
1675: isc_symtab_destroy(&symtab);
1676: *countp = count;
1677: return (result);
1678: }
1679:
1680: static isc_result_t
1681: check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
1682: isc_result_t result = ISC_R_SUCCESS;
1683: isc_result_t tresult;
1684: const cfg_listelt_t *element;
1685: const cfg_listelt_t *element2;
1686: dns_fixedname_t fixed_id, fixed_name;
1687: dns_name_t *id, *name;
1688: const char *str;
1.3 christos 1689: isc_textregion_t r;
1690: dns_rdatatype_t type;
1.1 christos 1691:
1692: /* Check for "update-policy local;" */
1693: if (cfg_obj_isstring(policy) &&
1694: strcmp("local", cfg_obj_asstring(policy)) == 0)
1695: return (ISC_R_SUCCESS);
1696:
1697: /* Now check the grant policy */
1698: for (element = cfg_list_first(policy);
1699: element != NULL;
1700: element = cfg_list_next(element))
1701: {
1702: const cfg_obj_t *stmt = cfg_listelt_value(element);
1703: const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
1704: const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
1705: const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
1706: const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
1707: dns_ssumatchtype_t mtype;
1708:
1709: id = dns_fixedname_initname(&fixed_id);
1710: name = dns_fixedname_initname(&fixed_name);
1711:
1712: tresult = dns_ssu_mtypefromstring(cfg_obj_asstring(matchtype),
1713: &mtype);
1714: if (tresult != ISC_R_SUCCESS) {
1715: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1716: "has a bad match-type");
1717: }
1718:
1719: str = cfg_obj_asstring(identity);
1720: tresult = dns_name_fromstring(id, str, 1, NULL);
1721: if (tresult != ISC_R_SUCCESS) {
1722: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1723: "'%s' is not a valid name", str);
1724: result = tresult;
1725: }
1726:
1727: /*
1.3 christos 1728: * There is no name field for subzone and dname is void
1.1 christos 1729: */
1.3 christos 1730: if (mtype == dns_ssumatchtype_subdomain &&
1731: cfg_obj_isvoid(dname))
1.1 christos 1732: {
1.3 christos 1733: str = "."; /* Use "." as a replacement. */
1734: } else {
1.1 christos 1735: str = cfg_obj_asstring(dname);
1.3 christos 1736: }
1737: if (tresult == ISC_R_SUCCESS) {
1.1 christos 1738: tresult = dns_name_fromstring(name, str, 0, NULL);
1739: if (tresult != ISC_R_SUCCESS) {
1740: cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
1741: "'%s' is not a valid name", str);
1742: result = tresult;
1743: }
1744: }
1745:
1746: if (tresult == ISC_R_SUCCESS &&
1747: mtype == dns_ssumatchtype_wildcard &&
1748: !dns_name_iswildcard(name))
1749: {
1750: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1751: "'%s' is not a wildcard", str);
1752: result = ISC_R_FAILURE;
1753: }
1754:
1755: /*
1756: * For some match types, the name should be a placeholder
1757: * value, either "." or the same as identity.
1758: */
1759: switch (mtype) {
1760: case dns_ssumatchtype_self:
1761: case dns_ssumatchtype_selfsub:
1762: case dns_ssumatchtype_selfwild:
1763: if (tresult == ISC_R_SUCCESS &&
1764: (!dns_name_equal(id, name) &&
1765: !dns_name_equal(dns_rootname, name))) {
1766: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1767: "identity and name fields are not "
1768: "the same");
1769: result = ISC_R_FAILURE;
1770: }
1771: break;
1772: case dns_ssumatchtype_selfkrb5:
1773: case dns_ssumatchtype_selfms:
1.3 christos 1774: case dns_ssumatchtype_selfsubkrb5:
1775: case dns_ssumatchtype_selfsubms:
1.1 christos 1776: case dns_ssumatchtype_tcpself:
1777: case dns_ssumatchtype_6to4self:
1778: if (tresult == ISC_R_SUCCESS &&
1779: !dns_name_equal(dns_rootname, name)) {
1780: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1781: "name field not set to "
1782: "placeholder value '.'");
1783: result = ISC_R_FAILURE;
1784: }
1785: break;
1786: case dns_ssumatchtype_name:
1.3 christos 1787: case dns_ssumatchtype_subdomain: /* also zonesub */
1788: case dns_ssumatchtype_subdomainms:
1789: case dns_ssumatchtype_subdomainkrb5:
1.1 christos 1790: case dns_ssumatchtype_wildcard:
1791: case dns_ssumatchtype_external:
1792: case dns_ssumatchtype_local:
1.3 christos 1793: if (tresult == ISC_R_SUCCESS) {
1794: DE_CONST(str, r.base);
1795: r.length = strlen(str);
1796: tresult = dns_rdatatype_fromtext(&type, &r);
1797: }
1798: if (tresult == ISC_R_SUCCESS) {
1799: cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
1800: "missing name field type '%s' "
1801: "found", str);
1802: result = ISC_R_FAILURE;
1803: break;
1804: }
1.1 christos 1805: break;
1806: default:
1807: INSIST(0);
1.3 christos 1808: ISC_UNREACHABLE();
1.1 christos 1809: }
1810:
1811: for (element2 = cfg_list_first(typelist);
1812: element2 != NULL;
1813: element2 = cfg_list_next(element2))
1814: {
1815: const cfg_obj_t *typeobj;
1816:
1817: typeobj = cfg_listelt_value(element2);
1818: DE_CONST(cfg_obj_asstring(typeobj), r.base);
1819: r.length = strlen(r.base);
1820:
1821: tresult = dns_rdatatype_fromtext(&type, &r);
1822: if (tresult != ISC_R_SUCCESS) {
1823: cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
1824: "'%s' is not a valid type", r.base);
1825: result = tresult;
1826: }
1827: }
1828: }
1829: return (result);
1830: }
1831:
1832: typedef struct {
1833: const char *name;
1.3 christos 1834: unsigned int allowed;
1.1 christos 1835: } optionstable;
1836:
1837: static isc_result_t
1838: check_nonzero(const cfg_obj_t *options, isc_log_t *logctx) {
1839: isc_result_t result = ISC_R_SUCCESS;
1840: const cfg_obj_t *obj = NULL;
1841: unsigned int i;
1842:
1843: static const char *nonzero[] = { "max-retry-time", "min-retry-time",
1844: "max-refresh-time", "min-refresh-time" };
1845: /*
1846: * Check if value is zero.
1847: */
1848: for (i = 0; i < sizeof(nonzero) / sizeof(nonzero[0]); i++) {
1849: obj = NULL;
1850: if (cfg_map_get(options, nonzero[i], &obj) == ISC_R_SUCCESS &&
1851: cfg_obj_asuint32(obj) == 0) {
1852: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1853: "'%s' must not be zero", nonzero[i]);
1854: result = ISC_R_FAILURE;
1855: }
1856: }
1857: return (result);
1858: }
1859:
1.3 christos 1860: /*%
1861: * Check whether NOTIFY configuration at the zone level is acceptable for a
1862: * mirror zone. Return true if it is; return false otherwise.
1863: */
1864: static bool
1865: check_mirror_zone_notify(const cfg_obj_t *zoptions, const char *znamestr,
1866: isc_log_t *logctx)
1867: {
1868: bool notify_configuration_ok = true;
1869: const cfg_obj_t *obj = NULL;
1870:
1871: (void)cfg_map_get(zoptions, "notify", &obj);
1872: if (obj == NULL) {
1873: /*
1874: * "notify" not set at zone level. This is fine.
1875: */
1876: return (true);
1877: }
1878:
1879: if (cfg_obj_isboolean(obj)) {
1880: if (cfg_obj_asboolean(obj)) {
1881: /*
1882: * "notify yes;" set at zone level. This is an error.
1883: */
1884: notify_configuration_ok = false;
1885: }
1886: } else {
1887: const char *notifystr = cfg_obj_asstring(obj);
1888: if (strcasecmp(notifystr, "explicit") != 0) {
1889: /*
1890: * Something else than "notify explicit;" set at zone
1891: * level. This is an error.
1892: */
1893: notify_configuration_ok = false;
1894: }
1895: }
1896:
1897: if (!notify_configuration_ok) {
1898: cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1899: "zone '%s': mirror zones can only be used with "
1900: "'notify no;' or 'notify explicit;'", znamestr);
1901: }
1902:
1903: return (notify_configuration_ok);
1904: }
1905:
1906: /*%
1907: * Try to determine whether recursion is available in a view without resorting
1908: * to extraordinary measures: just check the "recursion" and "allow-recursion"
1909: * settings. The point is to prevent accidental mirror zone misuse rather than
1910: * to enforce some sort of policy. Recursion is assumed to be allowed by
1911: * default if it is not explicitly disabled.
1912: */
1913: static bool
1914: check_recursion(const cfg_obj_t *config, const cfg_obj_t *voptions,
1915: const cfg_obj_t *goptions, isc_log_t *logctx,
1916: cfg_aclconfctx_t *actx, isc_mem_t *mctx)
1917: {
1918: dns_acl_t *acl = NULL;
1919: const cfg_obj_t *obj;
1920: isc_result_t result;
1921: bool retval = true;
1922:
1923: /*
1924: * Check the "recursion" option first.
1925: */
1926: obj = NULL;
1927: result = ISC_R_NOTFOUND;
1928: if (voptions != NULL) {
1929: result = cfg_map_get(voptions, "recursion", &obj);
1930: }
1931: if (result != ISC_R_SUCCESS && goptions != NULL) {
1932: result = cfg_map_get(goptions, "recursion", &obj);
1933: }
1934: if (result == ISC_R_SUCCESS && !cfg_obj_asboolean(obj)) {
1935: retval = false;
1936: goto cleanup;
1937: }
1938:
1939: /*
1940: * If recursion is not disabled by the "recursion" option, check
1941: * whether it is disabled by the "allow-recursion" ACL.
1942: */
1943: obj = NULL;
1944: result = ISC_R_NOTFOUND;
1945: if (voptions != NULL) {
1946: result = cfg_map_get(voptions, "allow-recursion", &obj);
1947: }
1948: if (result != ISC_R_SUCCESS && goptions != NULL) {
1949: result = cfg_map_get(goptions, "allow-recursion", &obj);
1950: }
1951: if (result == ISC_R_SUCCESS) {
1952: result = cfg_acl_fromconfig(obj, config, logctx, actx, mctx, 0,
1953: &acl);
1954: if (result != ISC_R_SUCCESS) {
1955: goto cleanup;
1956: }
1957: retval = !dns_acl_isnone(acl);
1958: }
1959:
1960: cleanup:
1961: if (acl != NULL) {
1962: dns_acl_detach(&acl);
1963: }
1964:
1965: return (retval);
1966: }
1967:
1.1 christos 1968: static isc_result_t
1969: check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
1970: const cfg_obj_t *config, isc_symtab_t *symtab,
1971: isc_symtab_t *files, isc_symtab_t *inview,
1972: const char *viewname, dns_rdataclass_t defclass,
1973: cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx)
1974: {
1975: const char *znamestr;
1976: const char *typestr = NULL;
1977: const char *target = NULL;
1978: unsigned int ztype;
1979: const cfg_obj_t *zoptions, *goptions = NULL;
1980: const cfg_obj_t *obj = NULL;
1981: const cfg_obj_t *inviewobj = NULL;
1982: isc_result_t result = ISC_R_SUCCESS;
1983: isc_result_t tresult;
1984: unsigned int i;
1985: dns_rdataclass_t zclass;
1986: dns_fixedname_t fixedname;
1.4 christos 1987: dns_name_t *zname = NULL; /* NULL if parsing of zone name fails. */
1.1 christos 1988: isc_buffer_t b;
1.3 christos 1989: bool root = false;
1990: bool rfc1918 = false;
1991: bool ula = false;
1.1 christos 1992: const cfg_listelt_t *element;
1.3 christos 1993: bool dlz;
1.1 christos 1994: dns_masterformat_t masterformat;
1.3 christos 1995: bool ddns = false;
1.1 christos 1996: const void *clauses = NULL;
1997: const char *option = NULL;
1998: static const char *acls[] = {
1999: "allow-notify",
2000: "allow-transfer",
2001: "allow-update",
2002: "allow-update-forwarding",
2003: };
2004:
2005: static optionstable dialups[] = {
1.4 christos 2006: { "notify", CFG_ZONE_MASTER | CFG_ZONE_SLAVE },
2007: { "notify-passive", CFG_ZONE_SLAVE },
2008: { "passive", CFG_ZONE_SLAVE | CFG_ZONE_STUB },
2009: { "refresh", CFG_ZONE_SLAVE | CFG_ZONE_STUB },
1.1 christos 2010: };
2011:
2012: znamestr = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
2013:
2014: zoptions = cfg_tuple_get(zconfig, "options");
2015:
2016: if (config != NULL)
2017: cfg_map_get(config, "options", &goptions);
2018:
2019: inviewobj = NULL;
2020: (void)cfg_map_get(zoptions, "in-view", &inviewobj);
2021: if (inviewobj != NULL) {
2022: target = cfg_obj_asstring(inviewobj);
2023: ztype = CFG_ZONE_INVIEW;
2024: } else {
2025: obj = NULL;
2026: (void)cfg_map_get(zoptions, "type", &obj);
2027: if (obj == NULL) {
2028: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2029: "zone '%s': type not present", znamestr);
2030: return (ISC_R_FAILURE);
2031: }
2032:
2033: typestr = cfg_obj_asstring(obj);
1.3 christos 2034: if (strcasecmp(typestr, "master") == 0 ||
2035: strcasecmp(typestr, "primary") == 0)
2036: {
1.1 christos 2037: ztype = CFG_ZONE_MASTER;
1.3 christos 2038: } else if (strcasecmp(typestr, "slave") == 0 ||
2039: strcasecmp(typestr, "secondary") == 0)
2040: {
1.1 christos 2041: ztype = CFG_ZONE_SLAVE;
1.3 christos 2042: } else if (strcasecmp(typestr, "mirror") == 0) {
2043: ztype = CFG_ZONE_MIRROR;
1.1 christos 2044: } else if (strcasecmp(typestr, "stub") == 0) {
2045: ztype = CFG_ZONE_STUB;
2046: } else if (strcasecmp(typestr, "static-stub") == 0) {
2047: ztype = CFG_ZONE_STATICSTUB;
2048: } else if (strcasecmp(typestr, "forward") == 0) {
2049: ztype = CFG_ZONE_FORWARD;
2050: } else if (strcasecmp(typestr, "hint") == 0) {
2051: ztype = CFG_ZONE_HINT;
2052: } else if (strcasecmp(typestr, "delegation-only") == 0) {
2053: ztype = CFG_ZONE_DELEGATION;
2054: } else if (strcasecmp(typestr, "redirect") == 0) {
2055: ztype = CFG_ZONE_REDIRECT;
2056: } else {
2057: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2058: "zone '%s': invalid type %s",
2059: znamestr, typestr);
2060: return (ISC_R_FAILURE);
2061: }
2062:
2063: if (ztype == CFG_ZONE_REDIRECT && strcmp(znamestr, ".") != 0) {
2064: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2065: "redirect zones must be called \".\"");
2066: return (ISC_R_FAILURE);
2067: }
2068: }
2069:
2070: obj = cfg_tuple_get(zconfig, "class");
2071: if (cfg_obj_isstring(obj)) {
2072: isc_textregion_t r;
2073:
2074: DE_CONST(cfg_obj_asstring(obj), r.base);
2075: r.length = strlen(r.base);
2076: result = dns_rdataclass_fromtext(&zclass, &r);
2077: if (result != ISC_R_SUCCESS) {
2078: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2079: "zone '%s': invalid class %s",
2080: znamestr, r.base);
2081: return (ISC_R_FAILURE);
2082: }
2083: if (zclass != defclass) {
2084: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2085: "zone '%s': class '%s' does not "
2086: "match view/default class",
2087: znamestr, r.base);
2088: return (ISC_R_FAILURE);
2089: }
2090: } else {
2091: zclass = defclass;
2092: }
2093:
2094: /*
2095: * Look for an already existing zone.
2096: * We need to make this canonical as isc_symtab_define()
2097: * deals with strings.
2098: */
2099: dns_fixedname_init(&fixedname);
2100: isc_buffer_constinit(&b, znamestr, strlen(znamestr));
2101: isc_buffer_add(&b, strlen(znamestr));
2102: tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
2103: dns_rootname, DNS_NAME_DOWNCASE, NULL);
2104: if (tresult != ISC_R_SUCCESS) {
2105: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2106: "zone '%s': is not a valid name", znamestr);
2107: result = ISC_R_FAILURE;
2108: } else {
2109: char namebuf[DNS_NAME_FORMATSIZE + 128];
2110: char *tmp = namebuf;
2111: size_t len = sizeof(namebuf);
2112:
2113: zname = dns_fixedname_name(&fixedname);
2114: dns_name_format(zname, namebuf, sizeof(namebuf));
2115: tresult = nameexist(zconfig, namebuf,
2116: ztype == CFG_ZONE_HINT ? 1 :
2117: ztype == CFG_ZONE_REDIRECT ? 2 : 3,
2118: symtab, "zone '%s': already exists "
2119: "previous definition: %s:%u", logctx, mctx);
2120: if (tresult != ISC_R_SUCCESS)
2121: result = tresult;
2122: if (dns_name_equal(zname, dns_rootname))
1.3 christos 2123: root = true;
1.1 christos 2124: else if (dns_name_isrfc1918(zname))
1.3 christos 2125: rfc1918 = true;
1.1 christos 2126: else if (dns_name_isula(zname))
1.3 christos 2127: ula = true;
1.1 christos 2128: tmp += strlen(tmp);
2129: len -= strlen(tmp);
2130: (void)snprintf(tmp, len, "%u/%s", zclass,
2131: (ztype == CFG_ZONE_INVIEW) ? target :
2132: (viewname != NULL) ? viewname : "_default");
2133: switch (ztype) {
2134: case CFG_ZONE_INVIEW:
2135: tresult = isc_symtab_lookup(inview, namebuf, 0, NULL);
2136: if (tresult != ISC_R_SUCCESS) {
2137: cfg_obj_log(inviewobj, logctx, ISC_LOG_ERROR,
2138: "'in-view' zone '%s' "
2139: "does not exist in view '%s', "
2140: "or view '%s' is not yet defined",
2141: znamestr, target, target);
2142: if (result == ISC_R_SUCCESS) {
2143: result = tresult;
2144: }
2145: }
2146: break;
2147:
2148: case CFG_ZONE_FORWARD:
2149: case CFG_ZONE_REDIRECT:
2150: case CFG_ZONE_DELEGATION:
2151: break;
2152:
2153: case CFG_ZONE_MASTER:
2154: case CFG_ZONE_SLAVE:
1.3 christos 2155: case CFG_ZONE_MIRROR:
1.1 christos 2156: case CFG_ZONE_HINT:
2157: case CFG_ZONE_STUB:
2158: case CFG_ZONE_STATICSTUB:
2159: tmp = isc_mem_strdup(mctx, namebuf);
2160: if (tmp != NULL) {
2161: isc_symvalue_t symvalue;
2162:
2163: symvalue.as_cpointer = NULL;
2164: tresult = isc_symtab_define(inview, tmp, 1,
2165: symvalue, isc_symexists_replace);
2166: if (tresult == ISC_R_NOMEMORY) {
2167: isc_mem_free(mctx, tmp);
2168: }
2169: if (result == ISC_R_SUCCESS &&
2170: tresult != ISC_R_SUCCESS)
2171: result = tresult;
2172: } else if (result != ISC_R_SUCCESS) {
2173: result = ISC_R_NOMEMORY;
2174: }
2175: break;
2176:
2177: default:
2178: INSIST(0);
1.3 christos 2179: ISC_UNREACHABLE();
1.1 christos 2180: }
2181: }
2182:
2183: if (ztype == CFG_ZONE_INVIEW) {
2184: const cfg_obj_t *fwd = NULL;
2185: unsigned int maxopts = 1;
2186:
2187: (void)cfg_map_get(zoptions, "forward", &fwd);
2188: if (fwd != NULL)
2189: maxopts++;
2190: fwd = NULL;
2191: (void)cfg_map_get(zoptions, "forwarders", &fwd);
2192: if (fwd != NULL)
2193: maxopts++;
2194: if (cfg_map_count(zoptions) > maxopts) {
2195: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2196: "zone '%s': 'in-view' used "
2197: "with incompatible zone options",
2198: znamestr);
2199: if (result == ISC_R_SUCCESS)
2200: result = ISC_R_FAILURE;
2201: }
2202: return (result);
2203: }
2204:
2205: /*
2206: * Check if value is zero.
2207: */
2208: if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
2209: result = ISC_R_FAILURE;
2210:
2211: /*
2212: * Check validity of the zone options.
2213: */
2214: option = cfg_map_firstclause(&cfg_type_zoneopts, &clauses, &i);
2215: while (option != NULL) {
2216: obj = NULL;
2217: if (cfg_map_get(zoptions, option, &obj) == ISC_R_SUCCESS &&
2218: obj != NULL && !cfg_clause_validforzone(option, ztype))
2219: {
2220: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2221: "option '%s' is not allowed "
2222: "in '%s' zone '%s'",
2223: option, typestr, znamestr);
2224: result = ISC_R_FAILURE;
2225: }
2226: option = cfg_map_nextclause(&cfg_type_zoneopts, &clauses, &i);
2227: }
2228:
2229: /*
2230: * Check that ACLs expand correctly.
2231: */
2232: for (i = 0; i < (sizeof(acls) / sizeof(acls[0])); i++) {
2233: tresult = checkacl(acls[i], actx, zconfig,
2234: voptions, config, logctx, mctx);
2235: if (tresult != ISC_R_SUCCESS) {
2236: result = tresult;
2237: }
2238: }
2239:
2240: /*
1.3 christos 2241: * Only a limited subset of all possible "notify" settings can be used
2242: * at the zone level for mirror zones.
2243: */
2244: if (ztype == CFG_ZONE_MIRROR &&
2245: !check_mirror_zone_notify(zoptions, znamestr, logctx))
2246: {
2247: result = ISC_R_FAILURE;
2248: }
2249:
2250: /*
2251: * Master, slave, and mirror zones may have an "also-notify" field, but
1.1 christos 2252: * shouldn't if notify is disabled.
2253: */
1.3 christos 2254: if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE ||
2255: ztype == CFG_ZONE_MIRROR)
2256: {
2257: bool donotify = true;
1.1 christos 2258:
2259: obj = NULL;
2260: tresult = cfg_map_get(zoptions, "notify", &obj);
2261: if (tresult != ISC_R_SUCCESS && voptions != NULL)
2262: tresult = cfg_map_get(voptions, "notify", &obj);
2263: if (tresult != ISC_R_SUCCESS && goptions != NULL)
2264: tresult = cfg_map_get(goptions, "notify", &obj);
2265: if (tresult == ISC_R_SUCCESS) {
2266: if (cfg_obj_isboolean(obj))
2267: donotify = cfg_obj_asboolean(obj);
2268: else {
2269: const char *notifystr = cfg_obj_asstring(obj);
2270: if (ztype != CFG_ZONE_MASTER &&
2271: strcasecmp(notifystr, "master-only") == 0)
1.3 christos 2272: donotify = false;
1.1 christos 2273: }
2274: }
2275:
2276: obj = NULL;
2277: tresult = cfg_map_get(zoptions, "also-notify", &obj);
2278: if (tresult == ISC_R_SUCCESS && !donotify) {
2279: cfg_obj_log(zoptions, logctx, ISC_LOG_WARNING,
2280: "zone '%s': 'also-notify' set but "
2281: "'notify' is disabled", znamestr);
2282: }
2283: if (tresult != ISC_R_SUCCESS && voptions != NULL)
2284: tresult = cfg_map_get(voptions, "also-notify", &obj);
2285: if (tresult != ISC_R_SUCCESS && goptions != NULL)
2286: tresult = cfg_map_get(goptions, "also-notify", &obj);
2287: if (tresult == ISC_R_SUCCESS && donotify) {
1.3 christos 2288: uint32_t count;
1.1 christos 2289: tresult = validate_masters(obj, config, &count,
2290: logctx, mctx);
2291: if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
2292: result = tresult;
2293: }
2294: }
2295:
2296: /*
1.3 christos 2297: * Slave, mirror, and stub zones must have a "masters" field, with one
2298: * exception: when mirroring the root zone, a default, built-in master
2299: * server list is used in the absence of one explicitly specified.
1.1 christos 2300: */
1.3 christos 2301: if (ztype == CFG_ZONE_SLAVE || ztype == CFG_ZONE_STUB ||
1.4 christos 2302: (ztype == CFG_ZONE_MIRROR && zname != NULL &&
2303: !dns_name_equal(zname, dns_rootname)))
1.3 christos 2304: {
1.1 christos 2305: obj = NULL;
2306: if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
2307: cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
2308: "zone '%s': missing 'masters' entry",
2309: znamestr);
2310: result = ISC_R_FAILURE;
2311: } else {
1.3 christos 2312: uint32_t count;
1.1 christos 2313: tresult = validate_masters(obj, config, &count,
2314: logctx, mctx);
2315: if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
2316: result = tresult;
2317: if (tresult == ISC_R_SUCCESS && count == 0) {
2318: cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
2319: "zone '%s': empty 'masters' entry",
2320: znamestr);
2321: result = ISC_R_FAILURE;
2322: }
2323: }
2324: }
2325:
2326: /*
1.3 christos 2327: * Configuring a mirror zone and disabling recursion at the same time
2328: * contradicts the purpose of the former.
2329: */
2330: if (ztype == CFG_ZONE_MIRROR &&
2331: !check_recursion(config, voptions, goptions, logctx, actx, mctx))
2332: {
2333: cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
2334: "zone '%s': mirror zones cannot be used if "
2335: "recursion is disabled", znamestr);
2336: result = ISC_R_FAILURE;
2337: }
2338:
2339: /*
1.1 christos 2340: * Master zones can't have both "allow-update" and "update-policy".
2341: */
2342: if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE) {
1.3 christos 2343: bool signing = false;
1.1 christos 2344: isc_result_t res1, res2, res3;
2345: const cfg_obj_t *au = NULL;
2346: const char *arg;
2347:
2348: obj = NULL;
2349: res1 = cfg_map_get(zoptions, "allow-update", &au);
2350: obj = NULL;
2351: res2 = cfg_map_get(zoptions, "update-policy", &obj);
2352: if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
2353: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2354: "zone '%s': 'allow-update' is ignored "
2355: "when 'update-policy' is present",
2356: znamestr);
2357: result = ISC_R_FAILURE;
2358: } else if (res2 == ISC_R_SUCCESS) {
2359: res3 = check_update_policy(obj, logctx);
2360: if (res3 != ISC_R_SUCCESS)
2361: result = ISC_R_FAILURE;
2362: }
2363:
2364: /*
2365: * To determine whether auto-dnssec is allowed,
2366: * we should also check for allow-update at the
2367: * view and options levels.
2368: */
2369: if (res1 != ISC_R_SUCCESS && voptions != NULL)
2370: res1 = cfg_map_get(voptions, "allow-update", &au);
2371: if (res1 != ISC_R_SUCCESS && goptions != NULL)
2372: res1 = cfg_map_get(goptions, "allow-update", &au);
2373:
2374: if (res2 == ISC_R_SUCCESS)
1.3 christos 2375: ddns = true;
1.1 christos 2376: else if (res1 == ISC_R_SUCCESS) {
2377: dns_acl_t *acl = NULL;
2378: res1 = cfg_acl_fromconfig(au, config, logctx,
2379: actx, mctx, 0, &acl);
2380: if (res1 != ISC_R_SUCCESS) {
2381: cfg_obj_log(au, logctx, ISC_LOG_ERROR,
2382: "acl expansion failed: %s",
2383: isc_result_totext(result));
2384: result = ISC_R_FAILURE;
2385: } else if (acl != NULL) {
2386: if (!dns_acl_isnone(acl))
1.3 christos 2387: ddns = true;
1.1 christos 2388: dns_acl_detach(&acl);
2389: }
2390: }
2391:
2392: obj = NULL;
2393: res1 = cfg_map_get(zoptions, "inline-signing", &obj);
2394: if (res1 == ISC_R_SUCCESS)
2395: signing = cfg_obj_asboolean(obj);
2396:
2397: obj = NULL;
2398: arg = "off";
2399: res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
2400: if (res3 == ISC_R_SUCCESS)
2401: arg = cfg_obj_asstring(obj);
2402: if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
2403: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2404: "'auto-dnssec %s;' requires%s "
2405: "inline-signing to be configured for "
2406: "the zone", arg,
2407: (ztype == CFG_ZONE_MASTER) ?
2408: " dynamic DNS or" : "");
2409: result = ISC_R_FAILURE;
2410: }
2411:
2412: obj = NULL;
2413: res1 = cfg_map_get(zoptions, "sig-signing-type", &obj);
2414: if (res1 == ISC_R_SUCCESS) {
1.3 christos 2415: uint32_t type = cfg_obj_asuint32(obj);
1.1 christos 2416: if (type < 0xff00U || type > 0xffffU)
2417: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2418: "sig-signing-type: %u out of "
2419: "range [%u..%u]", type,
2420: 0xff00U, 0xffffU);
2421: result = ISC_R_FAILURE;
2422: }
2423:
2424: obj = NULL;
2425: res1 = cfg_map_get(zoptions, "dnssec-dnskey-kskonly", &obj);
2426: if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
2427: !signing)
2428: {
2429: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2430: "dnssec-dnskey-kskonly: requires "
2431: "inline-signing when used in slave zone");
2432: result = ISC_R_FAILURE;
2433: }
2434:
2435: obj = NULL;
2436: res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
2437: if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
2438: !signing)
2439: {
2440: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2441: "dnssec-loadkeys-interval: requires "
2442: "inline-signing when used in slave zone");
2443: result = ISC_R_FAILURE;
2444: }
2445:
2446: obj = NULL;
2447: res1 = cfg_map_get(zoptions, "update-check-ksk", &obj);
2448: if (res1 == ISC_R_SUCCESS && ztype == CFG_ZONE_SLAVE &&
2449: !signing)
2450: {
2451: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2452: "update-check-ksk: requires "
2453: "inline-signing when used in slave zone");
2454: result = ISC_R_FAILURE;
2455: }
2456: }
2457:
2458: /*
2459: * Check the excessively complicated "dialup" option.
2460: */
2461: if (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_SLAVE ||
2462: ztype == CFG_ZONE_STUB)
2463: {
1.4 christos 2464: obj = NULL;
2465: (void)cfg_map_get(zoptions, "dialup", &obj);
2466: if (obj != NULL && cfg_obj_isstring(obj)) {
2467: const char *str = cfg_obj_asstring(obj);
1.1 christos 2468: for (i = 0;
2469: i < sizeof(dialups) / sizeof(dialups[0]);
2470: i++)
2471: {
2472: if (strcasecmp(dialups[i].name, str) != 0)
2473: continue;
2474: if ((dialups[i].allowed & ztype) == 0) {
2475: cfg_obj_log(obj, logctx,
2476: ISC_LOG_ERROR,
2477: "dialup type '%s' is not "
2478: "allowed in '%s' "
2479: "zone '%s'",
2480: str, typestr, znamestr);
2481: result = ISC_R_FAILURE;
2482: }
2483: break;
2484: }
2485: if (i == sizeof(dialups) / sizeof(dialups[0])) {
2486: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2487: "invalid dialup type '%s' in zone "
2488: "'%s'", str, znamestr);
2489: result = ISC_R_FAILURE;
2490: }
2491: }
2492: }
2493:
2494: /*
2495: * Check that forwarding is reasonable.
2496: */
2497: obj = NULL;
2498: if (root) {
2499: if (voptions != NULL)
2500: (void)cfg_map_get(voptions, "forwarders", &obj);
2501: if (obj == NULL && goptions != NULL)
2502: (void)cfg_map_get(goptions, "forwarders", &obj);
2503: }
2504: if (check_forward(zoptions, obj, logctx) != ISC_R_SUCCESS)
2505: result = ISC_R_FAILURE;
2506:
2507: /*
2508: * Check that a RFC 1918 / ULA reverse zone is not forward first
2509: * unless explictly configured to be so.
2510: */
2511: if (ztype == CFG_ZONE_FORWARD && (rfc1918 || ula)) {
2512: obj = NULL;
2513: (void)cfg_map_get(zoptions, "forward", &obj);
2514: if (obj == NULL) {
2515: /*
2516: * Forward mode not explicity configured.
2517: */
2518: if (voptions != NULL)
2519: cfg_map_get(voptions, "forward", &obj);
2520: if (obj == NULL && goptions != NULL)
2521: cfg_map_get(goptions, "forward", &obj);
2522: if (obj == NULL ||
2523: strcasecmp(cfg_obj_asstring(obj), "first") == 0)
2524: cfg_obj_log(zconfig, logctx, ISC_LOG_WARNING,
2525: "inherited 'forward first;' for "
2526: "%s zone '%s' - did you want "
2527: "'forward only;'?",
2528: rfc1918 ? "rfc1918" : "ula",
2529: znamestr);
2530: }
2531: }
2532:
2533: /*
2534: * Check validity of static stub server addresses.
2535: */
2536: obj = NULL;
2537: (void)cfg_map_get(zoptions, "server-addresses", &obj);
2538: if (ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
2539: for (element = cfg_list_first(obj);
2540: element != NULL;
2541: element = cfg_list_next(element))
2542: {
2543: isc_sockaddr_t sa;
2544: isc_netaddr_t na;
2545: obj = cfg_listelt_value(element);
2546: sa = *cfg_obj_assockaddr(obj);
2547:
2548: isc_netaddr_fromsockaddr(&na, &sa);
2549: if (isc_netaddr_getzone(&na) != 0) {
2550: result = ISC_R_FAILURE;
2551: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2552: "scoped address is not allowed "
2553: "for static stub "
2554: "server-addresses");
2555: }
2556: }
2557: }
2558:
2559: /*
2560: * Check validity of static stub server names.
2561: */
2562: obj = NULL;
2563: (void)cfg_map_get(zoptions, "server-names", &obj);
2564: if (zname != NULL && ztype == CFG_ZONE_STATICSTUB && obj != NULL) {
2565: for (element = cfg_list_first(obj);
2566: element != NULL;
2567: element = cfg_list_next(element))
2568: {
2569: const char *snamestr;
2570: dns_fixedname_t fixed_sname;
2571: isc_buffer_t b2;
2572: dns_name_t *sname;
2573:
2574: obj = cfg_listelt_value(element);
2575: snamestr = cfg_obj_asstring(obj);
2576:
2577: isc_buffer_constinit(&b2, snamestr, strlen(snamestr));
2578: isc_buffer_add(&b2, strlen(snamestr));
2579: sname = dns_fixedname_initname(&fixed_sname);
2580: tresult = dns_name_fromtext(sname, &b2, dns_rootname,
2581: 0, NULL);
2582: if (tresult != ISC_R_SUCCESS) {
2583: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2584: "server-name '%s' is not a valid "
2585: "name", snamestr);
2586: result = ISC_R_FAILURE;
2587: } else if (dns_name_issubdomain(sname, zname)) {
2588: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2589: "server-name '%s' must not be a "
2590: "subdomain of zone name '%s'",
2591: snamestr, znamestr);
2592: result = ISC_R_FAILURE;
2593: }
2594: }
2595: }
2596:
2597: /*
2598: * Check that max-zone-ttl isn't used with masterfile-format map
2599: */
2600: masterformat = dns_masterformat_text;
2601: obj = NULL;
2602: (void)cfg_map_get(zoptions, "masterfile-format", &obj);
2603: if (obj != NULL) {
2604: const char *masterformatstr = cfg_obj_asstring(obj);
1.3 christos 2605: if (strcasecmp(masterformatstr, "text") == 0) {
1.1 christos 2606: masterformat = dns_masterformat_text;
1.3 christos 2607: } else if (strcasecmp(masterformatstr, "raw") == 0) {
1.1 christos 2608: masterformat = dns_masterformat_raw;
1.3 christos 2609: } else if (strcasecmp(masterformatstr, "map") == 0) {
1.1 christos 2610: masterformat = dns_masterformat_map;
1.3 christos 2611: } else {
1.1 christos 2612: INSIST(0);
1.3 christos 2613: ISC_UNREACHABLE();
2614: }
1.1 christos 2615: }
2616:
2617: if (masterformat == dns_masterformat_map) {
2618: obj = NULL;
2619: (void)cfg_map_get(zoptions, "max-zone-ttl", &obj);
2620: if (obj == NULL && voptions != NULL)
2621: (void)cfg_map_get(voptions, "max-zone-ttl", &obj);
2622: if (obj == NULL && goptions !=NULL)
2623: (void)cfg_map_get(goptions, "max-zone-ttl", &obj);
2624: if (obj != NULL) {
2625: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2626: "zone '%s': 'max-zone-ttl' is not "
2627: "compatible with 'masterfile-format map'",
2628: znamestr);
2629: result = ISC_R_FAILURE;
2630: }
2631: }
2632:
2633: /*
2634: * Warn if key-directory doesn't exist
2635: */
2636: obj = NULL;
2637: tresult = cfg_map_get(zoptions, "key-directory", &obj);
2638: if (tresult == ISC_R_SUCCESS) {
2639: const char *dir = cfg_obj_asstring(obj);
2640: tresult = isc_file_isdirectory(dir);
2641: switch (tresult) {
2642: case ISC_R_SUCCESS:
2643: break;
2644: case ISC_R_FILENOTFOUND:
2645: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2646: "key-directory: '%s' does not exist",
2647: dir);
2648: break;
2649: case ISC_R_INVALIDFILE:
2650: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2651: "key-directory: '%s' is not a directory",
2652: dir);
2653: break;
2654: default:
2655: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
2656: "key-directory: '%s' %s",
2657: dir, isc_result_totext(tresult));
2658: result = tresult;
2659: }
2660: }
2661:
2662: /*
2663: * Check various options.
2664: */
2665: tresult = check_options(zoptions, logctx, mctx, optlevel_zone);
2666: if (tresult != ISC_R_SUCCESS)
2667: result = tresult;
2668:
2669: /*
2670: * If the zone type is rbt/rbt64 then master/hint zones
2671: * require file clauses.
2672: * If inline signing is used, then slave zones require a
2673: * file clause as well
2674: */
2675: obj = NULL;
1.3 christos 2676: dlz = false;
1.1 christos 2677: tresult = cfg_map_get(zoptions, "dlz", &obj);
2678: if (tresult == ISC_R_SUCCESS)
1.3 christos 2679: dlz = true;
1.1 christos 2680:
2681: obj = NULL;
2682: tresult = cfg_map_get(zoptions, "database", &obj);
2683: if (dlz && tresult == ISC_R_SUCCESS) {
2684: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2685: "zone '%s': cannot specify both 'dlz' "
2686: "and 'database'", znamestr);
2687: result = ISC_R_FAILURE;
2688: } else if (!dlz &&
2689: (tresult == ISC_R_NOTFOUND ||
2690: (tresult == ISC_R_SUCCESS &&
2691: (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
2692: strcmp("rbt64", cfg_obj_asstring(obj)) == 0))))
2693: {
2694: isc_result_t res1;
2695: const cfg_obj_t *fileobj = NULL;
2696: tresult = cfg_map_get(zoptions, "file", &fileobj);
2697: obj = NULL;
2698: res1 = cfg_map_get(zoptions, "inline-signing", &obj);
2699: if ((tresult != ISC_R_SUCCESS &&
2700: (ztype == CFG_ZONE_MASTER || ztype == CFG_ZONE_HINT ||
2701: (ztype == CFG_ZONE_SLAVE && res1 == ISC_R_SUCCESS &&
2702: cfg_obj_asboolean(obj)))))
2703: {
2704: cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
2705: "zone '%s': missing 'file' entry",
2706: znamestr);
2707: result = tresult;
2708: } else if (tresult == ISC_R_SUCCESS &&
1.3 christos 2709: (ztype == CFG_ZONE_SLAVE ||
2710: ztype == CFG_ZONE_MIRROR || ddns))
2711: {
2712: tresult = fileexist(fileobj, files, true, logctx);
1.1 christos 2713: if (tresult != ISC_R_SUCCESS)
2714: result = tresult;
2715: } else if (tresult == ISC_R_SUCCESS &&
2716: (ztype == CFG_ZONE_MASTER ||
2717: ztype == CFG_ZONE_HINT))
2718: {
1.3 christos 2719: tresult = fileexist(fileobj, files, false, logctx);
1.1 christos 2720: if (tresult != ISC_R_SUCCESS)
2721: result = tresult;
2722: }
2723: }
2724:
2725: return (result);
2726: }
2727:
2728:
2729: typedef struct keyalgorithms {
2730: const char *name;
1.3 christos 2731: uint16_t size;
1.1 christos 2732: } algorithmtable;
2733:
2734: isc_result_t
2735: bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
2736: const cfg_obj_t *algobj = NULL;
2737: const cfg_obj_t *secretobj = NULL;
2738: const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
2739: const char *algorithm;
2740: int i;
2741: size_t len = 0;
2742: isc_result_t result;
2743: isc_buffer_t buf;
2744: unsigned char secretbuf[1024];
2745: static const algorithmtable algorithms[] = {
2746: { "hmac-md5", 128 },
2747: { "hmac-md5.sig-alg.reg.int", 0 },
2748: { "hmac-md5.sig-alg.reg.int.", 0 },
2749: { "hmac-sha1", 160 },
2750: { "hmac-sha224", 224 },
2751: { "hmac-sha256", 256 },
2752: { "hmac-sha384", 384 },
2753: { "hmac-sha512", 512 },
2754: { NULL, 0 }
2755: };
2756:
2757: (void)cfg_map_get(key, "algorithm", &algobj);
2758: (void)cfg_map_get(key, "secret", &secretobj);
2759: if (secretobj == NULL || algobj == NULL) {
2760: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2761: "key '%s' must have both 'secret' and "
2762: "'algorithm' defined",
2763: keyname);
2764: return (ISC_R_FAILURE);
2765: }
2766:
2767: isc_buffer_init(&buf, secretbuf, sizeof(secretbuf));
2768: result = isc_base64_decodestring(cfg_obj_asstring(secretobj), &buf);
2769: if (result != ISC_R_SUCCESS) {
2770: cfg_obj_log(secretobj, logctx, ISC_LOG_ERROR,
2771: "bad secret '%s'", isc_result_totext(result));
2772: return (result);
2773: }
2774:
2775: algorithm = cfg_obj_asstring(algobj);
2776: for (i = 0; algorithms[i].name != NULL; i++) {
2777: len = strlen(algorithms[i].name);
2778: if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
2779: (algorithm[len] == '\0' ||
2780: (algorithms[i].size != 0 && algorithm[len] == '-')))
2781: break;
2782: }
2783: if (algorithms[i].name == NULL) {
2784: cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2785: "unknown algorithm '%s'", algorithm);
2786: return (ISC_R_NOTFOUND);
2787: }
2788: if (algorithm[len] == '-') {
1.3 christos 2789: uint16_t digestbits;
1.1 christos 2790: result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
2791: if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
2792: if (result == ISC_R_RANGE ||
2793: digestbits > algorithms[i].size) {
2794: cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2795: "key '%s' digest-bits too large "
2796: "[%u..%u]", keyname,
2797: algorithms[i].size / 2,
2798: algorithms[i].size);
2799: return (ISC_R_RANGE);
2800: }
2801: if ((digestbits % 8) != 0) {
2802: cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2803: "key '%s' digest-bits not multiple"
2804: " of 8", keyname);
2805: return (ISC_R_RANGE);
2806: }
2807: /*
2808: * Recommended minima for hmac algorithms.
2809: */
2810: if ((digestbits < (algorithms[i].size / 2U) ||
2811: (digestbits < 80U)))
2812: cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
2813: "key '%s' digest-bits too small "
2814: "[<%u]", keyname,
2815: algorithms[i].size/2);
2816: } else {
2817: cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
2818: "key '%s': unable to parse digest-bits",
2819: keyname);
2820: return (result);
2821: }
2822: }
2823: return (ISC_R_SUCCESS);
2824: }
2825:
2826: static isc_result_t
1.3 christos 2827: fileexist(const cfg_obj_t *obj, isc_symtab_t *symtab, bool writeable,
1.1 christos 2828: isc_log_t *logctx)
2829: {
2830: isc_result_t result;
2831: isc_symvalue_t symvalue;
2832: unsigned int line;
2833: const char *file;
2834:
2835: result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 0, &symvalue);
2836: if (result == ISC_R_SUCCESS) {
2837: if (writeable) {
2838: file = cfg_obj_file(symvalue.as_cpointer);
2839: line = cfg_obj_line(symvalue.as_cpointer);
2840: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2841: "writeable file '%s': already in use: "
2842: "%s:%u", cfg_obj_asstring(obj),
2843: file, line);
2844: return (ISC_R_EXISTS);
2845: }
2846: result = isc_symtab_lookup(symtab, cfg_obj_asstring(obj), 2,
2847: &symvalue);
2848: if (result == ISC_R_SUCCESS) {
2849: file = cfg_obj_file(symvalue.as_cpointer);
2850: line = cfg_obj_line(symvalue.as_cpointer);
2851: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
2852: "writeable file '%s': already in use: "
2853: "%s:%u", cfg_obj_asstring(obj),
2854: file, line);
2855: return (ISC_R_EXISTS);
2856: }
2857: return (ISC_R_SUCCESS);
2858: }
2859:
2860: symvalue.as_cpointer = obj;
2861: result = isc_symtab_define(symtab, cfg_obj_asstring(obj),
2862: writeable ? 2 : 1, symvalue,
2863: isc_symexists_reject);
2864: return (result);
2865: }
2866:
2867: /*
2868: * Check key list for duplicates key names and that the key names
2869: * are valid domain names as these keys are used for TSIG.
2870: *
2871: * Check the key contents for validity.
2872: */
2873: static isc_result_t
2874: check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab,
2875: isc_mem_t *mctx, isc_log_t *logctx)
2876: {
2877: char namebuf[DNS_NAME_FORMATSIZE];
2878: dns_fixedname_t fname;
2879: dns_name_t *name;
2880: isc_result_t result = ISC_R_SUCCESS;
2881: isc_result_t tresult;
2882: const cfg_listelt_t *element;
2883:
2884: name = dns_fixedname_initname(&fname);
2885: for (element = cfg_list_first(keys);
2886: element != NULL;
2887: element = cfg_list_next(element))
2888: {
2889: const cfg_obj_t *key = cfg_listelt_value(element);
2890: const char *keyid = cfg_obj_asstring(cfg_map_getname(key));
2891: isc_symvalue_t symvalue;
2892: isc_buffer_t b;
2893: char *keyname;
2894:
2895: isc_buffer_constinit(&b, keyid, strlen(keyid));
2896: isc_buffer_add(&b, strlen(keyid));
2897: tresult = dns_name_fromtext(name, &b, dns_rootname,
2898: 0, NULL);
2899: if (tresult != ISC_R_SUCCESS) {
2900: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2901: "key '%s': bad key name", keyid);
2902: result = tresult;
2903: continue;
2904: }
2905: tresult = bind9_check_key(key, logctx);
2906: if (tresult != ISC_R_SUCCESS)
2907: return (tresult);
2908:
2909: dns_name_format(name, namebuf, sizeof(namebuf));
2910: keyname = isc_mem_strdup(mctx, namebuf);
2911: if (keyname == NULL)
2912: return (ISC_R_NOMEMORY);
2913: symvalue.as_cpointer = key;
2914: tresult = isc_symtab_define(symtab, keyname, 1, symvalue,
2915: isc_symexists_reject);
2916: if (tresult == ISC_R_EXISTS) {
2917: const char *file;
2918: unsigned int line;
2919:
2920: RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
2921: 1, &symvalue) == ISC_R_SUCCESS);
2922: file = cfg_obj_file(symvalue.as_cpointer);
2923: line = cfg_obj_line(symvalue.as_cpointer);
2924:
2925: if (file == NULL)
2926: file = "<unknown file>";
2927: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
2928: "key '%s': already exists "
2929: "previous definition: %s:%u",
2930: keyid, file, line);
2931: isc_mem_free(mctx, keyname);
2932: result = tresult;
2933: } else if (tresult != ISC_R_SUCCESS) {
2934: isc_mem_free(mctx, keyname);
2935: return (tresult);
2936: }
2937: }
2938: return (result);
2939: }
2940:
2941: static struct {
2942: const char *v4;
2943: const char *v6;
2944: } sources[] = {
2945: { "transfer-source", "transfer-source-v6" },
2946: { "notify-source", "notify-source-v6" },
2947: { "query-source", "query-source-v6" },
2948: { NULL, NULL }
2949: };
2950:
2951: /*
2952: * RNDC keys are not normalised unlike TSIG keys.
2953: *
2954: * "foo." is different to "foo".
2955: */
1.3 christos 2956: static bool
1.1 christos 2957: rndckey_exists(const cfg_obj_t *keylist, const char *keyname) {
2958: const cfg_listelt_t *element;
2959: const cfg_obj_t *obj;
2960: const char *str;
2961:
2962: if (keylist == NULL)
1.3 christos 2963: return (false);
1.1 christos 2964:
2965: for (element = cfg_list_first(keylist);
2966: element != NULL;
2967: element = cfg_list_next(element))
2968: {
2969: obj = cfg_listelt_value(element);
2970: str = cfg_obj_asstring(cfg_map_getname(obj));
2971: if (!strcasecmp(str, keyname))
1.3 christos 2972: return (true);
1.1 christos 2973: }
1.3 christos 2974: return (false);
1.1 christos 2975: }
2976:
2977: static isc_result_t
2978: check_servers(const cfg_obj_t *config, const cfg_obj_t *voptions,
2979: isc_symtab_t *symtab, isc_log_t *logctx)
2980: {
2981: dns_fixedname_t fname;
2982: isc_result_t result = ISC_R_SUCCESS;
2983: isc_result_t tresult;
2984: const cfg_listelt_t *e1, *e2;
2985: const cfg_obj_t *v1, *v2, *keys;
2986: const cfg_obj_t *servers;
2987: isc_netaddr_t n1, n2;
2988: unsigned int p1, p2;
2989: const cfg_obj_t *obj;
2990: char buf[ISC_NETADDR_FORMATSIZE];
2991: char namebuf[DNS_NAME_FORMATSIZE];
2992: const char *xfr;
2993: const char *keyval;
2994: isc_buffer_t b;
2995: int source;
2996: dns_name_t *keyname;
2997:
2998: servers = NULL;
2999: if (voptions != NULL)
3000: (void)cfg_map_get(voptions, "server", &servers);
3001: if (servers == NULL)
3002: (void)cfg_map_get(config, "server", &servers);
3003: if (servers == NULL)
3004: return (ISC_R_SUCCESS);
3005:
3006: for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
3007: v1 = cfg_listelt_value(e1);
3008: cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
3009: /*
3010: * Check that unused bits are zero.
3011: */
3012: tresult = isc_netaddr_prefixok(&n1, p1);
3013: if (tresult != ISC_R_SUCCESS) {
3014: INSIST(tresult == ISC_R_FAILURE);
3015: isc_netaddr_format(&n1, buf, sizeof(buf));
3016: cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
3017: "server '%s/%u': invalid prefix "
3018: "(extra bits specified)", buf, p1);
3019: result = tresult;
3020: }
3021: source = 0;
3022: do {
3023: obj = NULL;
3024: if (n1.family == AF_INET)
3025: xfr = sources[source].v6;
3026: else
3027: xfr = sources[source].v4;
3028: (void)cfg_map_get(v1, xfr, &obj);
3029: if (obj != NULL) {
3030: isc_netaddr_format(&n1, buf, sizeof(buf));
3031: cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
3032: "server '%s/%u': %s not legal",
3033: buf, p1, xfr);
3034: result = ISC_R_FAILURE;
3035: }
3036: } while (sources[++source].v4 != NULL);
3037: e2 = e1;
3038: while ((e2 = cfg_list_next(e2)) != NULL) {
3039: v2 = cfg_listelt_value(e2);
3040: cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
3041: if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
3042: const char *file = cfg_obj_file(v1);
3043: unsigned int line = cfg_obj_line(v1);
3044:
3045: if (file == NULL)
3046: file = "<unknown file>";
3047:
3048: isc_netaddr_format(&n2, buf, sizeof(buf));
3049: cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
3050: "server '%s/%u': already exists "
3051: "previous definition: %s:%u",
3052: buf, p2, file, line);
3053: result = ISC_R_FAILURE;
3054: }
3055: }
3056: keys = NULL;
3057: cfg_map_get(v1, "keys", &keys);
3058: if (keys != NULL) {
3059: /*
3060: * Normalize key name.
3061: */
3062: keyval = cfg_obj_asstring(keys);
3063: isc_buffer_constinit(&b, keyval, strlen(keyval));
3064: isc_buffer_add(&b, strlen(keyval));
3065: keyname = dns_fixedname_initname(&fname);
3066: tresult = dns_name_fromtext(keyname, &b, dns_rootname,
3067: 0, NULL);
3068: if (tresult != ISC_R_SUCCESS) {
3069: cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
3070: "bad key name '%s'", keyval);
3071: result = ISC_R_FAILURE;
3072: continue;
3073: }
3074: dns_name_format(keyname, namebuf, sizeof(namebuf));
3075: tresult = isc_symtab_lookup(symtab, namebuf, 1, NULL);
3076: if (tresult != ISC_R_SUCCESS) {
3077: cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
3078: "unknown key '%s'", keyval);
3079: result = ISC_R_FAILURE;
3080: }
3081: }
3082: }
3083: return (result);
3084: }
3085:
3086: #define ROOT_KSK_2010 0x1
3087: #define ROOT_KSK_2017 0x2
3088: #define DLV_KSK_KEY 0x4
3089:
3090: static isc_result_t
1.3 christos 3091: check_trusted_key(const cfg_obj_t *key, bool managed,
1.1 christos 3092: unsigned int *keyflags, isc_log_t *logctx)
3093: {
3094: const char *keystr, *keynamestr;
3095: dns_fixedname_t fkeyname;
3096: dns_name_t *keyname;
3097: isc_buffer_t b;
3098: isc_region_t r;
3099: isc_result_t result = ISC_R_SUCCESS;
3100: isc_result_t tresult;
1.3 christos 3101: uint32_t flags, proto, alg;
1.1 christos 3102: unsigned char keydata[4096];
3103:
3104: flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
3105: proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
3106: alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
3107:
3108: keyname = dns_fixedname_initname(&fkeyname);
3109: keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
3110:
3111: isc_buffer_constinit(&b, keynamestr, strlen(keynamestr));
3112: isc_buffer_add(&b, strlen(keynamestr));
3113: result = dns_name_fromtext(keyname, &b, dns_rootname, 0, NULL);
3114: if (result != ISC_R_SUCCESS) {
3115: cfg_obj_log(key, logctx, ISC_LOG_WARNING, "bad key name: %s\n",
3116: isc_result_totext(result));
3117: result = ISC_R_FAILURE;
3118: }
3119:
3120: if (flags > 0xffff) {
3121: cfg_obj_log(key, logctx, ISC_LOG_WARNING,
3122: "flags too big: %u\n", flags);
3123: result = ISC_R_FAILURE;
3124: }
3125: if (proto > 0xff) {
3126: cfg_obj_log(key, logctx, ISC_LOG_WARNING,
3127: "protocol too big: %u\n", proto);
3128: result = ISC_R_FAILURE;
3129: }
3130: if (alg > 0xff) {
3131: cfg_obj_log(key, logctx, ISC_LOG_WARNING,
3132: "algorithm too big: %u\n", alg);
3133: result = ISC_R_FAILURE;
3134: }
3135:
3136: if (managed) {
3137: const char *initmethod;
3138: initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
3139:
3140: if (strcasecmp(initmethod, "initial-key") != 0) {
3141: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
3142: "managed key '%s': "
3143: "invalid initialization method '%s'",
3144: keynamestr, initmethod);
3145: result = ISC_R_FAILURE;
3146: }
3147: }
3148:
3149: isc_buffer_init(&b, keydata, sizeof(keydata));
3150:
3151: keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
3152: tresult = isc_base64_decodestring(keystr, &b);
3153:
3154: if (tresult != ISC_R_SUCCESS) {
3155: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
3156: "%s", isc_result_totext(tresult));
3157: result = ISC_R_FAILURE;
3158: } else {
3159: isc_buffer_usedregion(&b, &r);
3160:
1.4 christos 3161: if ((alg == DST_ALG_RSASHA1) &&
1.1 christos 3162: r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
3163: cfg_obj_log(key, logctx, ISC_LOG_WARNING,
3164: "%s key '%s' has a weak exponent",
3165: managed ? "managed" : "trusted",
3166: keynamestr);
3167: }
3168:
3169: if (result == ISC_R_SUCCESS && dns_name_equal(keyname, dns_rootname)) {
3170: static const unsigned char root_ksk_2010[] = {
3171: 0x03, 0x01, 0x00, 0x01, 0xa8, 0x00, 0x20, 0xa9,
3172: 0x55, 0x66, 0xba, 0x42, 0xe8, 0x86, 0xbb, 0x80,
3173: 0x4c, 0xda, 0x84, 0xe4, 0x7e, 0xf5, 0x6d, 0xbd,
3174: 0x7a, 0xec, 0x61, 0x26, 0x15, 0x55, 0x2c, 0xec,
3175: 0x90, 0x6d, 0x21, 0x16, 0xd0, 0xef, 0x20, 0x70,
3176: 0x28, 0xc5, 0x15, 0x54, 0x14, 0x4d, 0xfe, 0xaf,
3177: 0xe7, 0xc7, 0xcb, 0x8f, 0x00, 0x5d, 0xd1, 0x82,
3178: 0x34, 0x13, 0x3a, 0xc0, 0x71, 0x0a, 0x81, 0x18,
3179: 0x2c, 0xe1, 0xfd, 0x14, 0xad, 0x22, 0x83, 0xbc,
3180: 0x83, 0x43, 0x5f, 0x9d, 0xf2, 0xf6, 0x31, 0x32,
3181: 0x51, 0x93, 0x1a, 0x17, 0x6d, 0xf0, 0xda, 0x51,
3182: 0xe5, 0x4f, 0x42, 0xe6, 0x04, 0x86, 0x0d, 0xfb,
3183: 0x35, 0x95, 0x80, 0x25, 0x0f, 0x55, 0x9c, 0xc5,
3184: 0x43, 0xc4, 0xff, 0xd5, 0x1c, 0xbe, 0x3d, 0xe8,
3185: 0xcf, 0xd0, 0x67, 0x19, 0x23, 0x7f, 0x9f, 0xc4,
3186: 0x7e, 0xe7, 0x29, 0xda, 0x06, 0x83, 0x5f, 0xa4,
3187: 0x52, 0xe8, 0x25, 0xe9, 0xa1, 0x8e, 0xbc, 0x2e,
3188: 0xcb, 0xcf, 0x56, 0x34, 0x74, 0x65, 0x2c, 0x33,
3189: 0xcf, 0x56, 0xa9, 0x03, 0x3b, 0xcd, 0xf5, 0xd9,
3190: 0x73, 0x12, 0x17, 0x97, 0xec, 0x80, 0x89, 0x04,
3191: 0x1b, 0x6e, 0x03, 0xa1, 0xb7, 0x2d, 0x0a, 0x73,
3192: 0x5b, 0x98, 0x4e, 0x03, 0x68, 0x73, 0x09, 0x33,
3193: 0x23, 0x24, 0xf2, 0x7c, 0x2d, 0xba, 0x85, 0xe9,
3194: 0xdb, 0x15, 0xe8, 0x3a, 0x01, 0x43, 0x38, 0x2e,
3195: 0x97, 0x4b, 0x06, 0x21, 0xc1, 0x8e, 0x62, 0x5e,
3196: 0xce, 0xc9, 0x07, 0x57, 0x7d, 0x9e, 0x7b, 0xad,
3197: 0xe9, 0x52, 0x41, 0xa8, 0x1e, 0xbb, 0xe8, 0xa9,
3198: 0x01, 0xd4, 0xd3, 0x27, 0x6e, 0x40, 0xb1, 0x14,
3199: 0xc0, 0xa2, 0xe6, 0xfc, 0x38, 0xd1, 0x9c, 0x2e,
3200: 0x6a, 0xab, 0x02, 0x64, 0x4b, 0x28, 0x13, 0xf5,
3201: 0x75, 0xfc, 0x21, 0x60, 0x1e, 0x0d, 0xee, 0x49,
3202: 0xcd, 0x9e, 0xe9, 0x6a, 0x43, 0x10, 0x3e, 0x52,
3203: 0x4d, 0x62, 0x87, 0x3d };
3204: static const unsigned char root_ksk_2017[] = {
3205: 0x03, 0x01, 0x00, 0x01, 0xac, 0xff, 0xb4, 0x09,
3206: 0xbc, 0xc9, 0x39, 0xf8, 0x31, 0xf7, 0xa1, 0xe5,
3207: 0xec, 0x88, 0xf7, 0xa5, 0x92, 0x55, 0xec, 0x53,
3208: 0x04, 0x0b, 0xe4, 0x32, 0x02, 0x73, 0x90, 0xa4,
3209: 0xce, 0x89, 0x6d, 0x6f, 0x90, 0x86, 0xf3, 0xc5,
3210: 0xe1, 0x77, 0xfb, 0xfe, 0x11, 0x81, 0x63, 0xaa,
3211: 0xec, 0x7a, 0xf1, 0x46, 0x2c, 0x47, 0x94, 0x59,
3212: 0x44, 0xc4, 0xe2, 0xc0, 0x26, 0xbe, 0x5e, 0x98,
3213: 0xbb, 0xcd, 0xed, 0x25, 0x97, 0x82, 0x72, 0xe1,
3214: 0xe3, 0xe0, 0x79, 0xc5, 0x09, 0x4d, 0x57, 0x3f,
3215: 0x0e, 0x83, 0xc9, 0x2f, 0x02, 0xb3, 0x2d, 0x35,
3216: 0x13, 0xb1, 0x55, 0x0b, 0x82, 0x69, 0x29, 0xc8,
3217: 0x0d, 0xd0, 0xf9, 0x2c, 0xac, 0x96, 0x6d, 0x17,
3218: 0x76, 0x9f, 0xd5, 0x86, 0x7b, 0x64, 0x7c, 0x3f,
3219: 0x38, 0x02, 0x9a, 0xbd, 0xc4, 0x81, 0x52, 0xeb,
3220: 0x8f, 0x20, 0x71, 0x59, 0xec, 0xc5, 0xd2, 0x32,
3221: 0xc7, 0xc1, 0x53, 0x7c, 0x79, 0xf4, 0xb7, 0xac,
3222: 0x28, 0xff, 0x11, 0x68, 0x2f, 0x21, 0x68, 0x1b,
3223: 0xf6, 0xd6, 0xab, 0xa5, 0x55, 0x03, 0x2b, 0xf6,
3224: 0xf9, 0xf0, 0x36, 0xbe, 0xb2, 0xaa, 0xa5, 0xb3,
3225: 0x77, 0x8d, 0x6e, 0xeb, 0xfb, 0xa6, 0xbf, 0x9e,
3226: 0xa1, 0x91, 0xbe, 0x4a, 0xb0, 0xca, 0xea, 0x75,
3227: 0x9e, 0x2f, 0x77, 0x3a, 0x1f, 0x90, 0x29, 0xc7,
3228: 0x3e, 0xcb, 0x8d, 0x57, 0x35, 0xb9, 0x32, 0x1d,
3229: 0xb0, 0x85, 0xf1, 0xb8, 0xe2, 0xd8, 0x03, 0x8f,
3230: 0xe2, 0x94, 0x19, 0x92, 0x54, 0x8c, 0xee, 0x0d,
3231: 0x67, 0xdd, 0x45, 0x47, 0xe1, 0x1d, 0xd6, 0x3a,
3232: 0xf9, 0xc9, 0xfc, 0x1c, 0x54, 0x66, 0xfb, 0x68,
3233: 0x4c, 0xf0, 0x09, 0xd7, 0x19, 0x7c, 0x2c, 0xf7,
3234: 0x9e, 0x79, 0x2a, 0xb5, 0x01, 0xe6, 0xa8, 0xa1,
3235: 0xca, 0x51, 0x9a, 0xf2, 0xcb, 0x9b, 0x5f, 0x63,
3236: 0x67, 0xe9, 0x4c, 0x0d, 0x47, 0x50, 0x24, 0x51,
3237: 0x35, 0x7b, 0xe1, 0xb5 };
3238: if (flags == 257 && proto == 3 && alg == 8 &&
3239: isc_buffer_usedlength(&b) == sizeof(root_ksk_2010) &&
3240: !memcmp(keydata, root_ksk_2010, sizeof(root_ksk_2010))) {
3241: *keyflags |= ROOT_KSK_2010;
3242: }
3243: if (flags == 257 && proto == 3 && alg == 8 &&
3244: isc_buffer_usedlength(&b) == sizeof(root_ksk_2017) &&
3245: !memcmp(keydata, root_ksk_2017, sizeof(root_ksk_2017))) {
3246: *keyflags |= ROOT_KSK_2017;
3247: }
3248: }
3249: if (result == ISC_R_SUCCESS && dns_name_equal(keyname, &dlviscorg)) {
3250: static const unsigned char dlviscorgkey[] = {
3251: 0x04, 0x40, 0x00, 0x00, 0x03, 0xc7, 0x32, 0xef,
3252: 0xf9, 0xa2, 0x7c, 0xeb, 0x10, 0x4e, 0xf3, 0xd5,
3253: 0xe8, 0x26, 0x86, 0x0f, 0xd6, 0x3c, 0xed, 0x3e,
3254: 0x8e, 0xea, 0x19, 0xad, 0x6d, 0xde, 0xb9, 0x61,
3255: 0x27, 0xe0, 0xcc, 0x43, 0x08, 0x4d, 0x7e, 0x94,
3256: 0xbc, 0xb6, 0x6e, 0xb8, 0x50, 0xbf, 0x9a, 0xcd,
3257: 0xdf, 0x64, 0x4a, 0xb4, 0xcc, 0xd7, 0xe8, 0xc8,
3258: 0xfb, 0xd2, 0x37, 0x73, 0x78, 0xd0, 0xf8, 0x5e,
3259: 0x49, 0xd6, 0xe7, 0xc7, 0x67, 0x24, 0xd3, 0xc2,
3260: 0xc6, 0x7f, 0x3e, 0x8c, 0x01, 0xa5, 0xd8, 0x56,
3261: 0x4b, 0x2b, 0xcb, 0x7e, 0xd6, 0xea, 0xb8, 0x5b,
3262: 0xe9, 0xe7, 0x03, 0x7a, 0x8e, 0xdb, 0xe0, 0xcb,
3263: 0xfa, 0x4e, 0x81, 0x0f, 0x89, 0x9e, 0xc0, 0xc2,
3264: 0xdb, 0x21, 0x81, 0x70, 0x7b, 0x43, 0xc6, 0xef,
3265: 0x74, 0xde, 0xf5, 0xf6, 0x76, 0x90, 0x96, 0xf9,
3266: 0xe9, 0xd8, 0x60, 0x31, 0xd7, 0xb9, 0xca, 0x65,
3267: 0xf8, 0x04, 0x8f, 0xe8, 0x43, 0xe7, 0x00, 0x2b,
3268: 0x9d, 0x3f, 0xc6, 0xf2, 0x6f, 0xd3, 0x41, 0x6b,
3269: 0x7f, 0xc9, 0x30, 0xea, 0xe7, 0x0c, 0x4f, 0x01,
3270: 0x65, 0x80, 0xf7, 0xbe, 0x8e, 0x71, 0xb1, 0x3c,
3271: 0xf1, 0x26, 0x1c, 0x0b, 0x5e, 0xfd, 0x44, 0x64,
3272: 0x63, 0xad, 0x99, 0x7e, 0x42, 0xe8, 0x04, 0x00,
3273: 0x03, 0x2c, 0x74, 0x3d, 0x22, 0xb4, 0xb6, 0xb6,
3274: 0xbc, 0x80, 0x7b, 0xb9, 0x9b, 0x05, 0x95, 0x5c,
3275: 0x3b, 0x02, 0x1e, 0x53, 0xf4, 0x70, 0xfe, 0x64,
3276: 0x71, 0xfe, 0xfc, 0x30, 0x30, 0x24, 0xe0, 0x35,
3277: 0xba, 0x0c, 0x40, 0xab, 0x54, 0x76, 0xf3, 0x57,
3278: 0x0e, 0xb6, 0x09, 0x0d, 0x21, 0xd9, 0xc2, 0xcd,
3279: 0xf1, 0x89, 0x15, 0xc5, 0xd5, 0x17, 0xfe, 0x6a,
3280: 0x5f, 0x54, 0x99, 0x97, 0xd2, 0x6a, 0xff, 0xf8,
3281: 0x35, 0x62, 0xca, 0x8c, 0x7c, 0xe9, 0x4f, 0x9f,
3282: 0x64, 0xfd, 0x54, 0xad, 0x4c, 0x33, 0x74, 0x61,
3283: 0x4b, 0x96, 0xac, 0x13, 0x61 };
3284: if (flags == 257 && proto == 3 && alg == 5 &&
3285: isc_buffer_usedlength(&b) == sizeof(dlviscorgkey) &&
3286: !memcmp(keydata, dlviscorgkey, sizeof(dlviscorgkey))) {
3287: *keyflags |= DLV_KSK_KEY;
3288: }
3289: }
3290:
3291: return (result);
3292: }
3293:
1.6 ! christos 3294: /*
! 3295: * Check for conflicts between trusted-keys and managed-keys.
! 3296: */
! 3297: static isc_result_t
! 3298: check_ta_conflicts(const cfg_obj_t *mkeys, const cfg_obj_t *tkeys,
! 3299: bool autovalidation, isc_mem_t *mctx, isc_log_t *logctx)
! 3300: {
! 3301: isc_result_t result = ISC_R_SUCCESS, tresult;
! 3302: const cfg_listelt_t *elt = NULL, *elt2 = NULL;
! 3303: dns_fixedname_t fixed;
! 3304: dns_name_t *name;
! 3305: const cfg_obj_t *obj;
! 3306: const char *str;
! 3307: isc_symtab_t *symtab = NULL;
! 3308: isc_symvalue_t symvalue;
! 3309: char namebuf[DNS_NAME_FORMATSIZE];
! 3310: const char *file;
! 3311: unsigned int line;
! 3312:
! 3313: name = dns_fixedname_initname(&fixed);
! 3314:
! 3315: result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
! 3316: if (result != ISC_R_SUCCESS) {
! 3317: goto cleanup;
! 3318: }
! 3319:
! 3320: for (elt = cfg_list_first(mkeys);
! 3321: elt != NULL;
! 3322: elt = cfg_list_next(elt))
! 3323: {
! 3324: const cfg_obj_t *keylist = cfg_listelt_value(elt);
! 3325: for (elt2 = cfg_list_first(keylist);
! 3326: elt2 != NULL;
! 3327: elt2 = cfg_list_next(elt2))
! 3328: {
! 3329: obj = cfg_listelt_value(elt2);
! 3330: str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
! 3331: tresult = dns_name_fromstring(name, str, 0, NULL);
! 3332: if (tresult != ISC_R_SUCCESS) {
! 3333: /* already reported */
! 3334: continue;
! 3335: }
! 3336:
! 3337: dns_name_format(name, namebuf, sizeof(namebuf));
! 3338: symvalue.as_cpointer = obj;
! 3339: tresult = isc_symtab_define(symtab, namebuf, 1,
! 3340: symvalue,
! 3341: isc_symexists_reject);
! 3342: if (tresult != ISC_R_SUCCESS &&
! 3343: tresult != ISC_R_EXISTS)
! 3344: {
! 3345: result = tresult;
! 3346: continue;
! 3347: }
! 3348: }
! 3349: }
! 3350:
! 3351: for (elt = cfg_list_first(tkeys);
! 3352: elt != NULL;
! 3353: elt = cfg_list_next(elt))
! 3354: {
! 3355: const cfg_obj_t *keylist = cfg_listelt_value(elt);
! 3356: for (elt2 = cfg_list_first(keylist);
! 3357: elt2 != NULL;
! 3358: elt2 = cfg_list_next(elt2))
! 3359: {
! 3360: obj = cfg_listelt_value(elt2);
! 3361: str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
! 3362: result = dns_name_fromstring(name, str, 0, NULL);
! 3363: if (result != ISC_R_SUCCESS) {
! 3364: /* already reported */
! 3365: continue;
! 3366: }
! 3367:
! 3368: if (autovalidation &&
! 3369: dns_name_equal(name, dns_rootname))
! 3370: {
! 3371: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
! 3372: "WARNING: "
! 3373: "trusted-keys for root zone "
! 3374: "used with "
! 3375: "'dnssec-validation auto'. "
! 3376: "KEY ROLLOVERS WILL FAIL.");
! 3377: continue;
! 3378: }
! 3379:
! 3380: dns_name_format(name, namebuf, sizeof(namebuf));
! 3381: tresult = isc_symtab_lookup(symtab, namebuf, 1,
! 3382: &symvalue);
! 3383: if (tresult == ISC_R_SUCCESS) {
! 3384: file = cfg_obj_file(symvalue.as_cpointer);
! 3385: line = cfg_obj_line(symvalue.as_cpointer);
! 3386: if (file == NULL) {
! 3387: file = "<unknown file>";
! 3388: }
! 3389: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
! 3390: "WARNING: "
! 3391: "trusted-keys and managed-keys "
! 3392: "are both used for the "
! 3393: "name '%s'. "
! 3394: "KEY ROLLOVERS WILL FAIL. "
! 3395: "managed-key defined "
! 3396: "(%s:%u)", str, file, line);
! 3397: }
! 3398: }
! 3399: }
! 3400:
! 3401: cleanup:
! 3402: if (symtab != NULL) {
! 3403: isc_symtab_destroy(&symtab);
! 3404: }
! 3405: return (result);
! 3406: }
! 3407:
1.3 christos 3408: typedef enum {
3409: special_zonetype_rpz,
3410: special_zonetype_catz
3411: } special_zonetype_t;
3412:
1.1 christos 3413: static isc_result_t
3414: check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj,
1.3 christos 3415: const char *viewname, isc_symtab_t *symtab, isc_log_t *logctx,
3416: special_zonetype_t specialzonetype)
1.1 christos 3417: {
3418: const cfg_listelt_t *element;
3419: const cfg_obj_t *obj, *nameobj, *zoneobj;
3420: const char *zonename, *zonetype;
3421: const char *forview = " for view ";
3422: isc_symvalue_t value;
3423: isc_result_t result, tresult;
3424: dns_fixedname_t fixed;
3425: dns_name_t *name;
3426: char namebuf[DNS_NAME_FORMATSIZE];
1.3 christos 3427: unsigned int num_zones = 0;
1.1 christos 3428:
3429: if (viewname == NULL) {
3430: viewname = "";
3431: forview = "";
3432: }
3433: result = ISC_R_SUCCESS;
3434:
3435: name = dns_fixedname_initname(&fixed);
3436: obj = cfg_tuple_get(rpz_obj, "zone list");
1.3 christos 3437:
1.1 christos 3438: for (element = cfg_list_first(obj);
3439: element != NULL;
1.3 christos 3440: element = cfg_list_next(element))
3441: {
1.1 christos 3442: obj = cfg_listelt_value(element);
3443: nameobj = cfg_tuple_get(obj, "zone name");
3444: zonename = cfg_obj_asstring(nameobj);
3445: zonetype = "";
3446:
1.3 christos 3447: if (specialzonetype == special_zonetype_rpz) {
3448: if (++num_zones > 64) {
3449: cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR,
3450: "more than 64 response policy "
3451: "zones in view '%s'", viewname);
3452: return (ISC_R_FAILURE);
3453: }
3454: }
3455:
1.1 christos 3456: tresult = dns_name_fromstring(name, zonename, 0, NULL);
3457: if (tresult != ISC_R_SUCCESS) {
3458: cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR,
3459: "bad domain name '%s'", zonename);
3460: if (result == ISC_R_SUCCESS)
3461: result = tresult;
3462: continue;
3463: }
3464: dns_name_format(name, namebuf, sizeof(namebuf));
3465: tresult = isc_symtab_lookup(symtab, namebuf, 3, &value);
3466: if (tresult == ISC_R_SUCCESS) {
3467: obj = NULL;
3468: zoneobj = value.as_cpointer;
3469: if (zoneobj != NULL && cfg_obj_istuple(zoneobj))
3470: zoneobj = cfg_tuple_get(zoneobj, "options");
3471: if (zoneobj != NULL && cfg_obj_ismap(zoneobj))
3472: (void)cfg_map_get(zoneobj, "type", &obj);
3473: if (obj != NULL)
3474: zonetype = cfg_obj_asstring(obj);
3475: }
1.3 christos 3476: if (strcasecmp(zonetype, "primary") != 0 &&
3477: strcasecmp(zonetype, "master") != 0 &&
3478: strcasecmp(zonetype, "secondary") != 0 &&
3479: strcasecmp(zonetype, "slave") != 0)
3480: {
1.1 christos 3481: cfg_obj_log(nameobj, logctx, ISC_LOG_ERROR,
3482: "%s '%s'%s%s is not a master or slave zone",
3483: rpz_catz, zonename, forview, viewname);
3484: if (result == ISC_R_SUCCESS)
3485: result = ISC_R_FAILURE;
3486: }
3487: }
3488: return (result);
3489: }
3490:
1.3 christos 3491: #ifdef HAVE_DLOPEN
3492: /*%
3493: * Data structure used for the 'callback_data' argument to check_one_plugin().
3494: */
3495: struct check_one_plugin_data {
3496: isc_mem_t *mctx;
3497: isc_log_t *lctx;
3498: cfg_aclconfctx_t *actx;
3499: isc_result_t *check_result;
3500: };
3501:
3502: /*%
3503: * A callback for the cfg_pluginlist_foreach() call in check_viewconf() below.
3504: * Since the point is to check configuration of all plugins even when
3505: * processing some of them fails, always return ISC_R_SUCCESS and indicate any
3506: * check failures through the 'check_result' variable passed in via the
3507: * 'callback_data' structure.
3508: */
3509: static isc_result_t
3510: check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3511: const char *plugin_path, const char *parameters,
3512: void *callback_data)
3513: {
3514: struct check_one_plugin_data *data = callback_data;
1.5 christos 3515: char full_path[PATH_MAX];
1.3 christos 3516: isc_result_t result;
3517:
1.5 christos 3518: result = ns_plugin_expandpath(plugin_path,
3519: full_path, sizeof(full_path));
3520: if (result != ISC_R_SUCCESS) {
3521: cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR,
3522: "%s: plugin check failed: "
3523: "unable to get full plugin path: %s",
3524: plugin_path, isc_result_totext(result));
3525: return (result);
3526: }
3527:
3528: result = ns_plugin_check(full_path, parameters, config,
1.3 christos 3529: cfg_obj_file(obj), cfg_obj_line(obj),
3530: data->mctx, data->lctx, data->actx);
3531: if (result != ISC_R_SUCCESS) {
3532: cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR,
3533: "%s: plugin check failed: %s",
1.5 christos 3534: full_path, isc_result_totext(result));
1.3 christos 3535: *data->check_result = result;
3536: }
3537:
3538: return (ISC_R_SUCCESS);
3539: }
3540: #endif
3541:
1.1 christos 3542: static isc_result_t
3543: check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
3544: const char *viewname, dns_rdataclass_t vclass,
1.3 christos 3545: isc_symtab_t *files, bool check_plugins, isc_symtab_t *inview,
1.1 christos 3546: isc_log_t *logctx, isc_mem_t *mctx)
3547: {
3548: const cfg_obj_t *zones = NULL;
1.6 ! christos 3549: const cfg_obj_t *keys = NULL, *tkeys = NULL, *mkeys = NULL;
1.1 christos 3550: #ifndef HAVE_DLOPEN
3551: const cfg_obj_t *dyndb = NULL;
3552: #endif
3553: const cfg_listelt_t *element, *element2;
3554: isc_symtab_t *symtab = NULL;
3555: isc_result_t result = ISC_R_SUCCESS;
3556: isc_result_t tresult = ISC_R_SUCCESS;
3557: cfg_aclconfctx_t *actx = NULL;
3558: const cfg_obj_t *obj;
3559: const cfg_obj_t *options = NULL;
3560: const cfg_obj_t *opts = NULL;
1.3 christos 3561: const cfg_obj_t *plugin_list = NULL;
3562: bool enablednssec, enablevalidation;
1.6 ! christos 3563: bool autovalidation = false;
1.1 christos 3564: const char *valstr = "no";
3565: unsigned int tflags, mflags;
3566:
3567: /*
3568: * Get global options block
3569: */
3570: (void)cfg_map_get(config, "options", &options);
3571:
3572: /*
3573: * The most relevant options for this view
3574: */
3575: if (voptions != NULL)
3576: opts = voptions;
3577: else
3578: opts = options;
3579:
3580: /*
3581: * Check that all zone statements are syntactically correct and
3582: * there are no duplicate zones.
3583: */
3584: tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
1.3 christos 3585: false, &symtab);
1.1 christos 3586: if (tresult != ISC_R_SUCCESS)
3587: return (ISC_R_NOMEMORY);
3588:
3589: cfg_aclconfctx_create(mctx, &actx);
3590:
3591: if (voptions != NULL)
3592: (void)cfg_map_get(voptions, "zone", &zones);
3593: else
3594: (void)cfg_map_get(config, "zone", &zones);
3595:
3596: for (element = cfg_list_first(zones);
3597: element != NULL;
3598: element = cfg_list_next(element))
3599: {
3600: const cfg_obj_t *zone = cfg_listelt_value(element);
3601:
3602: tresult = check_zoneconf(zone, voptions, config, symtab,
3603: files, inview, viewname, vclass,
3604: actx, logctx, mctx);
3605: if (tresult != ISC_R_SUCCESS)
3606: result = ISC_R_FAILURE;
3607: }
3608:
3609: #ifndef HAVE_DLOPEN
3610: if (voptions != NULL)
3611: (void)cfg_map_get(voptions, "dyndb", &dyndb);
3612: else
3613: (void)cfg_map_get(config, "dyndb", &dyndb);
3614:
3615: if (dyndb != NULL) {
3616: cfg_obj_log(dyndb, logctx, ISC_LOG_ERROR,
3617: "dynamic loading of databases is not supported");
3618: if (tresult != ISC_R_SUCCESS)
3619: result = ISC_R_NOTIMPLEMENTED;
3620: }
3621: #endif
3622:
3623: /*
3624: * Check that the response-policy and catalog-zones options
3625: * refer to zones that exist.
3626: */
3627: if (opts != NULL) {
3628: obj = NULL;
1.3 christos 3629: if ((cfg_map_get(opts, "response-policy",
3630: &obj) == ISC_R_SUCCESS) &&
3631: (check_rpz_catz("response-policy zone", obj,
3632: viewname, symtab, logctx,
3633: special_zonetype_rpz) != ISC_R_SUCCESS))
3634: {
1.1 christos 3635: result = ISC_R_FAILURE;
1.3 christos 3636: }
3637:
1.1 christos 3638: obj = NULL;
1.3 christos 3639: if ((cfg_map_get(opts, "catalog-zones",
3640: &obj) == ISC_R_SUCCESS) &&
3641: (check_rpz_catz("catalog zone", obj,
3642: viewname, symtab, logctx,
3643: special_zonetype_catz) != ISC_R_SUCCESS))
3644: {
1.1 christos 3645: result = ISC_R_FAILURE;
1.3 christos 3646: }
1.1 christos 3647: }
3648:
3649: isc_symtab_destroy(&symtab);
3650:
3651: /*
3652: * Check that forwarding is reasonable.
3653: */
3654: if (opts != NULL && check_forward(opts, NULL, logctx) != ISC_R_SUCCESS)
3655: result = ISC_R_FAILURE;
3656:
3657: /*
3658: * Check non-zero options at the global and view levels.
3659: */
3660: if (options != NULL && check_nonzero(options, logctx) != ISC_R_SUCCESS)
3661: result = ISC_R_FAILURE;
3662: if (voptions != NULL &&check_nonzero(voptions, logctx) != ISC_R_SUCCESS)
3663: result = ISC_R_FAILURE;
3664:
3665: /*
3666: * Check that dual-stack-servers is reasonable.
3667: */
3668: if (opts != NULL && check_dual_stack(opts, logctx) != ISC_R_SUCCESS)
3669: result = ISC_R_FAILURE;
3670:
3671: /*
3672: * Check that rrset-order is reasonable.
3673: */
3674: if (opts != NULL && check_order(opts, logctx) != ISC_R_SUCCESS)
3675: result = ISC_R_FAILURE;
3676:
3677: /*
3678: * Check that all key statements are syntactically correct and
3679: * there are no duplicate keys.
3680: */
3681: tresult = isc_symtab_create(mctx, 1000, freekey, mctx,
1.3 christos 3682: false, &symtab);
1.1 christos 3683: if (tresult != ISC_R_SUCCESS)
3684: goto cleanup;
3685:
3686: (void)cfg_map_get(config, "key", &keys);
3687: tresult = check_keylist(keys, symtab, mctx, logctx);
3688: if (tresult == ISC_R_EXISTS)
3689: result = ISC_R_FAILURE;
3690: else if (tresult != ISC_R_SUCCESS) {
3691: result = tresult;
3692: goto cleanup;
3693: }
3694:
3695: if (voptions != NULL) {
3696: keys = NULL;
3697: (void)cfg_map_get(voptions, "key", &keys);
3698: tresult = check_keylist(keys, symtab, mctx, logctx);
3699: if (tresult == ISC_R_EXISTS)
3700: result = ISC_R_FAILURE;
3701: else if (tresult != ISC_R_SUCCESS) {
3702: result = tresult;
3703: goto cleanup;
3704: }
3705: }
3706:
3707: /*
3708: * Global servers can refer to keys in views.
3709: */
3710: if (check_servers(config, voptions, symtab, logctx) != ISC_R_SUCCESS)
3711: result = ISC_R_FAILURE;
3712:
3713: isc_symtab_destroy(&symtab);
3714:
3715: /*
3716: * Check that dnssec-enable/dnssec-validation are sensible.
3717: */
3718: obj = NULL;
3719: if (voptions != NULL)
3720: (void)cfg_map_get(voptions, "dnssec-enable", &obj);
3721: if (obj == NULL && options != NULL)
3722: (void)cfg_map_get(options, "dnssec-enable", &obj);
3723: if (obj == NULL)
1.3 christos 3724: enablednssec = true;
1.1 christos 3725: else
3726: enablednssec = cfg_obj_asboolean(obj);
3727:
3728: obj = NULL;
3729: if (voptions != NULL)
3730: (void)cfg_map_get(voptions, "dnssec-validation", &obj);
3731: if (obj == NULL && options != NULL)
3732: (void)cfg_map_get(options, "dnssec-validation", &obj);
3733: if (obj == NULL) {
3734: enablevalidation = enablednssec;
3735: valstr = "yes";
3736: } else if (cfg_obj_isboolean(obj)) {
3737: enablevalidation = cfg_obj_asboolean(obj);
3738: valstr = enablevalidation ? "yes" : "no";
3739: } else {
1.3 christos 3740: enablevalidation = true;
1.1 christos 3741: valstr = "auto";
3742: }
3743:
3744: if (enablevalidation && !enablednssec)
3745: cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
3746: "'dnssec-validation %s;' and 'dnssec-enable no;'",
3747: valstr);
3748:
3749: /*
3750: * Check trusted-keys and managed-keys.
3751: */
1.6 ! christos 3752: tkeys = NULL;
1.1 christos 3753: if (voptions != NULL)
1.6 ! christos 3754: (void)cfg_map_get(voptions, "trusted-keys", &tkeys);
! 3755: if (tkeys == NULL)
! 3756: (void)cfg_map_get(config, "trusted-keys", &tkeys);
1.1 christos 3757:
3758: tflags = 0;
1.6 ! christos 3759: for (element = cfg_list_first(tkeys);
1.1 christos 3760: element != NULL;
3761: element = cfg_list_next(element))
3762: {
3763: const cfg_obj_t *keylist = cfg_listelt_value(element);
3764: for (element2 = cfg_list_first(keylist);
3765: element2 != NULL;
3766: element2 = cfg_list_next(element2)) {
3767: obj = cfg_listelt_value(element2);
1.3 christos 3768: tresult = check_trusted_key(obj, false, &tflags,
1.1 christos 3769: logctx);
3770: if (tresult != ISC_R_SUCCESS)
3771: result = tresult;
3772: }
3773: }
3774:
3775: if ((tflags & ROOT_KSK_2010) != 0 && (tflags & ROOT_KSK_2017) == 0) {
1.6 ! christos 3776: cfg_obj_log(tkeys, logctx, ISC_LOG_WARNING,
1.1 christos 3777: "trusted-key for root from 2010 without updated "
3778: "trusted-key from 2017: THIS WILL FAIL AFTER "
3779: "KEY ROLLOVER");
3780: }
3781:
3782: if ((tflags & DLV_KSK_KEY) != 0) {
1.6 ! christos 3783: cfg_obj_log(tkeys, logctx, ISC_LOG_WARNING,
1.1 christos 3784: "trusted-key for dlv.isc.org still present; "
3785: "dlv.isc.org has been shut down");
3786: }
3787:
1.6 ! christos 3788: mkeys = NULL;
1.1 christos 3789: if (voptions != NULL)
1.6 ! christos 3790: (void)cfg_map_get(voptions, "managed-keys", &mkeys);
! 3791: if (mkeys == NULL)
! 3792: (void)cfg_map_get(config, "managed-keys", &mkeys);
1.1 christos 3793:
3794: mflags = 0;
1.6 ! christos 3795: for (element = cfg_list_first(mkeys);
1.1 christos 3796: element != NULL;
3797: element = cfg_list_next(element))
3798: {
3799: const cfg_obj_t *keylist = cfg_listelt_value(element);
3800: for (element2 = cfg_list_first(keylist);
3801: element2 != NULL;
1.6 ! christos 3802: element2 = cfg_list_next(element2))
! 3803: {
1.1 christos 3804: obj = cfg_listelt_value(element2);
1.3 christos 3805: tresult = check_trusted_key(obj, true, &mflags,
1.1 christos 3806: logctx);
3807: if (tresult != ISC_R_SUCCESS)
3808: result = tresult;
3809: }
3810: }
3811:
3812: if ((mflags & ROOT_KSK_2010) != 0 && (mflags & ROOT_KSK_2017) == 0) {
1.6 ! christos 3813: cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
1.1 christos 3814: "managed-key for root from 2010 without updated "
3815: "managed-key from 2017");
3816: }
3817:
3818: if ((mflags & DLV_KSK_KEY) != 0) {
1.6 ! christos 3819: cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
1.1 christos 3820: "managed-key for dlv.isc.org still present; "
3821: "dlv.isc.org has been shut down");
3822: }
3823:
3824: if ((tflags & (ROOT_KSK_2010|ROOT_KSK_2017)) != 0 &&
3825: (mflags & (ROOT_KSK_2010|ROOT_KSK_2017)) != 0)
3826: {
1.6 ! christos 3827: cfg_obj_log(mkeys, logctx, ISC_LOG_WARNING,
1.1 christos 3828: "both trusted-keys and managed-keys for the ICANN "
3829: "root are present");
3830: }
3831:
1.6 ! christos 3832: obj = NULL;
! 3833: if (voptions != NULL) {
! 3834: (void)cfg_map_get(voptions, "dnssec-validation", &obj);
! 3835: }
! 3836: if (obj == NULL && options != NULL) {
! 3837: (void)cfg_map_get(options, "dnssec-validation", &obj);
! 3838: }
! 3839: if (obj != NULL && !cfg_obj_isboolean(obj)) {
! 3840: autovalidation = true;
! 3841: }
! 3842:
! 3843: tresult = check_ta_conflicts(mkeys, tkeys,
! 3844: autovalidation, mctx, logctx);
! 3845: if (tresult != ISC_R_SUCCESS) {
! 3846: result = tresult;
! 3847: }
! 3848:
1.1 christos 3849: /*
3850: * Check options.
3851: */
3852: if (voptions != NULL)
3853: tresult = check_options(voptions, logctx, mctx,
3854: optlevel_view);
3855: else
3856: tresult = check_options(config, logctx, mctx,
3857: optlevel_config);
3858: if (tresult != ISC_R_SUCCESS)
3859: result = tresult;
3860:
3861: tresult = check_viewacls(actx, voptions, config, logctx, mctx);
3862: if (tresult != ISC_R_SUCCESS)
3863: result = tresult;
3864:
3865: tresult = check_recursionacls(actx, voptions, viewname,
3866: config, logctx, mctx);
3867: if (tresult != ISC_R_SUCCESS)
3868: result = tresult;
3869:
3870: tresult = check_dns64(actx, voptions, config, logctx, mctx);
3871: if (tresult != ISC_R_SUCCESS)
3872: result = tresult;
3873:
3874: tresult = check_ratelimit(actx, voptions, config, logctx, mctx);
3875: if (tresult != ISC_R_SUCCESS)
3876: result = tresult;
3877:
1.3 christos 3878: /*
3879: * Load plugins.
3880: */
3881: if (check_plugins) {
3882: if (voptions != NULL) {
3883: (void)cfg_map_get(voptions, "plugin", &plugin_list);
3884: } else {
3885: (void)cfg_map_get(config, "plugin", &plugin_list);
3886: }
3887: }
3888:
3889: #ifdef HAVE_DLOPEN
3890: {
3891: struct check_one_plugin_data check_one_plugin_data = {
3892: .mctx = mctx,
3893: .lctx = logctx,
3894: .actx = actx,
3895: .check_result = &tresult,
3896: };
3897:
3898: (void)cfg_pluginlist_foreach(config, plugin_list, logctx,
3899: check_one_plugin,
3900: &check_one_plugin_data);
3901: if (tresult != ISC_R_SUCCESS) {
3902: result = tresult;
3903: }
3904: }
3905: #endif /* HAVE_DLOPEN */
3906:
1.1 christos 3907: cleanup:
3908: if (symtab != NULL)
3909: isc_symtab_destroy(&symtab);
3910: if (actx != NULL)
3911: cfg_aclconfctx_detach(&actx);
3912:
3913: return (result);
3914: }
3915:
3916: static const char *
3917: default_channels[] = {
3918: "default_syslog",
3919: "default_stderr",
3920: "default_debug",
3921: "null",
3922: NULL
3923: };
3924:
3925: static isc_result_t
3926: bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
3927: isc_mem_t *mctx)
3928: {
3929: const cfg_obj_t *categories = NULL;
3930: const cfg_obj_t *category;
3931: const cfg_obj_t *channels = NULL;
3932: const cfg_obj_t *channel;
3933: const cfg_listelt_t *element;
3934: const cfg_listelt_t *delement;
3935: const char *channelname;
3936: const char *catname;
3937: const cfg_obj_t *fileobj = NULL;
3938: const cfg_obj_t *syslogobj = NULL;
3939: const cfg_obj_t *nullobj = NULL;
3940: const cfg_obj_t *stderrobj = NULL;
3941: const cfg_obj_t *logobj = NULL;
3942: isc_result_t result = ISC_R_SUCCESS;
3943: isc_result_t tresult;
3944: isc_symtab_t *symtab = NULL;
3945: isc_symvalue_t symvalue;
3946: int i;
3947:
3948: (void)cfg_map_get(config, "logging", &logobj);
3949: if (logobj == NULL)
3950: return (ISC_R_SUCCESS);
3951:
1.3 christos 3952: result = isc_symtab_create(mctx, 100, NULL, NULL, false, &symtab);
1.1 christos 3953: if (result != ISC_R_SUCCESS)
3954: return (result);
3955:
3956: symvalue.as_cpointer = NULL;
3957: for (i = 0; default_channels[i] != NULL; i++) {
3958: tresult = isc_symtab_define(symtab, default_channels[i], 1,
3959: symvalue, isc_symexists_replace);
3960: if (tresult != ISC_R_SUCCESS)
3961: result = tresult;
3962: }
3963:
3964: cfg_map_get(logobj, "channel", &channels);
3965:
3966: for (element = cfg_list_first(channels);
3967: element != NULL;
3968: element = cfg_list_next(element))
3969: {
3970: channel = cfg_listelt_value(element);
3971: channelname = cfg_obj_asstring(cfg_map_getname(channel));
3972: fileobj = syslogobj = nullobj = stderrobj = NULL;
3973: (void)cfg_map_get(channel, "file", &fileobj);
3974: (void)cfg_map_get(channel, "syslog", &syslogobj);
3975: (void)cfg_map_get(channel, "null", &nullobj);
3976: (void)cfg_map_get(channel, "stderr", &stderrobj);
3977: i = 0;
3978: if (fileobj != NULL)
3979: i++;
3980: if (syslogobj != NULL)
3981: i++;
3982: if (nullobj != NULL)
3983: i++;
3984: if (stderrobj != NULL)
3985: i++;
3986: if (i != 1) {
3987: cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
3988: "channel '%s': exactly one of file, syslog, "
3989: "null, and stderr must be present",
3990: channelname);
3991: result = ISC_R_FAILURE;
3992: }
3993: tresult = isc_symtab_define(symtab, channelname, 1,
3994: symvalue, isc_symexists_replace);
3995: if (tresult != ISC_R_SUCCESS)
3996: result = tresult;
3997: }
3998:
3999: cfg_map_get(logobj, "category", &categories);
4000:
4001: for (element = cfg_list_first(categories);
4002: element != NULL;
4003: element = cfg_list_next(element))
4004: {
4005: category = cfg_listelt_value(element);
4006: catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
4007: if (isc_log_categorybyname(logctx, catname) == NULL) {
4008: cfg_obj_log(category, logctx, ISC_LOG_ERROR,
4009: "undefined category: '%s'", catname);
4010: result = ISC_R_FAILURE;
4011: }
4012: channels = cfg_tuple_get(category, "destinations");
4013: for (delement = cfg_list_first(channels);
4014: delement != NULL;
4015: delement = cfg_list_next(delement))
4016: {
4017: channel = cfg_listelt_value(delement);
4018: channelname = cfg_obj_asstring(channel);
4019: tresult = isc_symtab_lookup(symtab, channelname, 1,
4020: &symvalue);
4021: if (tresult != ISC_R_SUCCESS) {
4022: cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
4023: "undefined channel: '%s'",
4024: channelname);
4025: result = tresult;
4026: }
4027: }
4028: }
4029: isc_symtab_destroy(&symtab);
4030: return (result);
4031: }
4032:
4033: static isc_result_t
4034: bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
4035: isc_log_t *logctx)
4036: {
4037: isc_result_t result = ISC_R_SUCCESS;
4038: const cfg_obj_t *control_keylist;
4039: const cfg_listelt_t *element;
4040: const cfg_obj_t *key;
4041: const char *keyval;
4042:
4043: control_keylist = cfg_tuple_get(control, "keys");
4044: if (cfg_obj_isvoid(control_keylist))
4045: return (ISC_R_SUCCESS);
4046:
4047: for (element = cfg_list_first(control_keylist);
4048: element != NULL;
4049: element = cfg_list_next(element))
4050: {
4051: key = cfg_listelt_value(element);
4052: keyval = cfg_obj_asstring(key);
4053:
4054: if (!rndckey_exists(keylist, keyval)) {
4055: cfg_obj_log(key, logctx, ISC_LOG_ERROR,
4056: "unknown key '%s'", keyval);
4057: result = ISC_R_NOTFOUND;
4058: }
4059: }
4060: return (result);
4061: }
4062:
4063: static isc_result_t
4064: bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
4065: isc_mem_t *mctx)
4066: {
4067: isc_result_t result = ISC_R_SUCCESS, tresult;
4068: cfg_aclconfctx_t *actx = NULL;
4069: const cfg_listelt_t *element, *element2;
4070: const cfg_obj_t *allow;
4071: const cfg_obj_t *control;
4072: const cfg_obj_t *controls;
4073: const cfg_obj_t *controlslist = NULL;
4074: const cfg_obj_t *inetcontrols;
4075: const cfg_obj_t *unixcontrols;
4076: const cfg_obj_t *keylist = NULL;
4077: const char *path;
1.3 christos 4078: uint32_t perm, mask;
1.1 christos 4079: dns_acl_t *acl = NULL;
4080: isc_sockaddr_t addr;
4081: int i;
4082:
4083: (void)cfg_map_get(config, "controls", &controlslist);
4084: if (controlslist == NULL)
4085: return (ISC_R_SUCCESS);
4086:
4087: (void)cfg_map_get(config, "key", &keylist);
4088:
4089: cfg_aclconfctx_create(mctx, &actx);
4090:
4091: /*
4092: * INET: Check allow clause.
4093: * UNIX: Check "perm" for sanity, check path length.
4094: */
4095: for (element = cfg_list_first(controlslist);
4096: element != NULL;
4097: element = cfg_list_next(element)) {
4098: controls = cfg_listelt_value(element);
4099: unixcontrols = NULL;
4100: inetcontrols = NULL;
4101: (void)cfg_map_get(controls, "unix", &unixcontrols);
4102: (void)cfg_map_get(controls, "inet", &inetcontrols);
4103: for (element2 = cfg_list_first(inetcontrols);
4104: element2 != NULL;
4105: element2 = cfg_list_next(element2)) {
4106: control = cfg_listelt_value(element2);
4107: allow = cfg_tuple_get(control, "allow");
4108: tresult = cfg_acl_fromconfig(allow, config, logctx,
4109: actx, mctx, 0, &acl);
4110: if (acl != NULL)
4111: dns_acl_detach(&acl);
4112: if (tresult != ISC_R_SUCCESS)
4113: result = tresult;
4114: tresult = bind9_check_controlskeys(control, keylist,
4115: logctx);
4116: if (tresult != ISC_R_SUCCESS)
4117: result = tresult;
4118: }
4119: for (element2 = cfg_list_first(unixcontrols);
4120: element2 != NULL;
4121: element2 = cfg_list_next(element2)) {
4122: control = cfg_listelt_value(element2);
4123: path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
4124: tresult = isc_sockaddr_frompath(&addr, path);
4125: if (tresult == ISC_R_NOSPACE) {
4126: cfg_obj_log(control, logctx, ISC_LOG_ERROR,
4127: "unix control '%s': path too long",
4128: path);
4129: result = ISC_R_NOSPACE;
4130: }
4131: perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
4132: for (i = 0; i < 3; i++) {
4133: #ifdef NEED_SECURE_DIRECTORY
4134: mask = (0x1 << (i*3)); /* SEARCH */
4135: #else
4136: mask = (0x6 << (i*3)); /* READ + WRITE */
4137: #endif
4138: if ((perm & mask) == mask)
4139: break;
4140: }
4141: if (i == 0) {
4142: cfg_obj_log(control, logctx, ISC_LOG_WARNING,
4143: "unix control '%s' allows access "
4144: "to everyone", path);
4145: } else if (i == 3) {
4146: cfg_obj_log(control, logctx, ISC_LOG_WARNING,
4147: "unix control '%s' allows access "
4148: "to nobody", path);
4149: }
4150: tresult = bind9_check_controlskeys(control, keylist,
4151: logctx);
4152: if (tresult != ISC_R_SUCCESS)
4153: result = tresult;
4154: }
4155: }
4156: cfg_aclconfctx_detach(&actx);
4157: return (result);
4158: }
4159:
4160: isc_result_t
1.3 christos 4161: bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins,
4162: isc_log_t *logctx, isc_mem_t *mctx)
1.1 christos 4163: {
4164: const cfg_obj_t *options = NULL;
4165: const cfg_obj_t *views = NULL;
4166: const cfg_obj_t *acls = NULL;
4167: const cfg_obj_t *kals = NULL;
4168: const cfg_obj_t *obj;
4169: const cfg_listelt_t *velement;
4170: isc_result_t result = ISC_R_SUCCESS;
4171: isc_result_t tresult;
4172: isc_symtab_t *symtab = NULL;
4173: isc_symtab_t *files = NULL;
4174: isc_symtab_t *inview = NULL;
4175:
4176: static const char *builtin[] = { "localhost", "localnets",
4177: "any", "none"};
4178:
4179: (void)cfg_map_get(config, "options", &options);
4180:
4181: if (options != NULL &&
4182: check_options(options, logctx, mctx,
4183: optlevel_options) != ISC_R_SUCCESS)
4184: result = ISC_R_FAILURE;
4185:
4186: if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
4187: result = ISC_R_FAILURE;
4188:
4189: if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
4190: result = ISC_R_FAILURE;
4191:
4192: (void)cfg_map_get(config, "view", &views);
4193:
4194: if (views != NULL && options != NULL)
4195: if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
4196: result = ISC_R_FAILURE;
4197:
4198: /*
4199: * Use case insensitive comparision as not all file systems are
4200: * case sensitive. This will prevent people using FOO.DB and foo.db
4201: * on case sensitive file systems but that shouldn't be a major issue.
4202: */
1.3 christos 4203: tresult = isc_symtab_create(mctx, 100, NULL, NULL, false,
1.1 christos 4204: &files);
4205: if (tresult != ISC_R_SUCCESS) {
4206: result = tresult;
4207: goto cleanup;
4208: }
4209:
4210: tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1.3 christos 4211: true, &inview);
1.1 christos 4212: if (tresult != ISC_R_SUCCESS) {
4213: result = tresult;
4214: goto cleanup;
4215: }
4216:
4217: if (views == NULL) {
1.3 christos 4218: tresult = check_viewconf(config, NULL, NULL,
4219: dns_rdataclass_in, files,
4220: check_plugins, inview, logctx, mctx);
1.1 christos 4221: if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) {
4222: result = ISC_R_FAILURE;
4223: }
4224: } else {
4225: const cfg_obj_t *zones = NULL;
1.3 christos 4226: const cfg_obj_t *plugins = NULL;
1.1 christos 4227:
4228: (void)cfg_map_get(config, "zone", &zones);
4229: if (zones != NULL) {
4230: cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
4231: "when using 'view' statements, "
4232: "all zones must be in views");
4233: result = ISC_R_FAILURE;
4234: }
1.3 christos 4235:
4236: (void)cfg_map_get(config, "plugin", &plugins);
4237: if (plugins != NULL) {
4238: cfg_obj_log(plugins, logctx, ISC_LOG_ERROR,
4239: "when using 'view' statements, "
4240: "all plugins must be defined in views");
4241: result = ISC_R_FAILURE;
4242: }
1.1 christos 4243: }
4244:
1.3 christos 4245: tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab);
1.1 christos 4246: if (tresult != ISC_R_SUCCESS) {
4247: result = tresult;
4248: goto cleanup;
4249: }
4250: for (velement = cfg_list_first(views);
4251: velement != NULL;
4252: velement = cfg_list_next(velement))
4253: {
4254: const cfg_obj_t *view = cfg_listelt_value(velement);
4255: const cfg_obj_t *vname = cfg_tuple_get(view, "name");
4256: const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
4257: const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
4258: dns_rdataclass_t vclass = dns_rdataclass_in;
4259: const char *key = cfg_obj_asstring(vname);
4260: isc_symvalue_t symvalue;
4261: unsigned int symtype;
4262:
4263: tresult = ISC_R_SUCCESS;
4264: if (cfg_obj_isstring(vclassobj)) {
4265: isc_textregion_t r;
4266:
4267: DE_CONST(cfg_obj_asstring(vclassobj), r.base);
4268: r.length = strlen(r.base);
4269: tresult = dns_rdataclass_fromtext(&vclass, &r);
4270: if (tresult != ISC_R_SUCCESS)
4271: cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
4272: "view '%s': invalid class %s",
4273: cfg_obj_asstring(vname), r.base);
4274: }
4275: symtype = vclass + 1;
4276: if (tresult == ISC_R_SUCCESS && symtab != NULL) {
4277: symvalue.as_cpointer = view;
4278: tresult = isc_symtab_define(symtab, key, symtype,
4279: symvalue,
4280: isc_symexists_reject);
4281: if (tresult == ISC_R_EXISTS) {
4282: const char *file;
4283: unsigned int line;
4284: RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
4285: symtype, &symvalue) == ISC_R_SUCCESS);
4286: file = cfg_obj_file(symvalue.as_cpointer);
4287: line = cfg_obj_line(symvalue.as_cpointer);
4288: cfg_obj_log(view, logctx, ISC_LOG_ERROR,
4289: "view '%s': already exists "
4290: "previous definition: %s:%u",
4291: key, file, line);
4292: result = tresult;
4293: } else if (tresult != ISC_R_SUCCESS) {
4294: result = tresult;
4295: } else if ((strcasecmp(key, "_bind") == 0 &&
4296: vclass == dns_rdataclass_ch) ||
4297: (strcasecmp(key, "_default") == 0 &&
4298: vclass == dns_rdataclass_in)) {
4299: cfg_obj_log(view, logctx, ISC_LOG_ERROR,
4300: "attempt to redefine builtin view "
4301: "'%s'", key);
4302: result = ISC_R_EXISTS;
4303: }
4304: }
4305: if (tresult == ISC_R_SUCCESS)
1.3 christos 4306: tresult = check_viewconf(config, voptions, key,
4307: vclass, files, check_plugins,
4308: inview, logctx, mctx);
1.1 christos 4309: if (tresult != ISC_R_SUCCESS)
4310: result = ISC_R_FAILURE;
4311: }
4312:
4313: if (views != NULL && options != NULL) {
4314: obj = NULL;
4315: tresult = cfg_map_get(options, "cache-file", &obj);
4316: if (tresult == ISC_R_SUCCESS) {
4317: cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
4318: "'cache-file' cannot be a global "
4319: "option if views are present");
4320: result = ISC_R_FAILURE;
4321: }
4322: }
4323:
4324: cfg_map_get(config, "acl", &acls);
4325:
4326: if (acls != NULL) {
4327: const cfg_listelt_t *elt;
4328: const cfg_listelt_t *elt2;
4329: const char *aclname;
4330:
4331: for (elt = cfg_list_first(acls);
4332: elt != NULL;
4333: elt = cfg_list_next(elt)) {
4334: const cfg_obj_t *acl = cfg_listelt_value(elt);
4335: unsigned int line = cfg_obj_line(acl);
4336: unsigned int i;
4337:
4338: aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
4339: for (i = 0;
4340: i < sizeof(builtin) / sizeof(builtin[0]);
4341: i++)
4342: if (strcasecmp(aclname, builtin[i]) == 0) {
4343: cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
4344: "attempt to redefine "
4345: "builtin acl '%s'",
4346: aclname);
4347: result = ISC_R_FAILURE;
4348: break;
4349: }
4350:
4351: for (elt2 = cfg_list_next(elt);
4352: elt2 != NULL;
4353: elt2 = cfg_list_next(elt2)) {
4354: const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
4355: const char *name;
4356: name = cfg_obj_asstring(cfg_tuple_get(acl2,
4357: "name"));
4358: if (strcasecmp(aclname, name) == 0) {
4359: const char *file = cfg_obj_file(acl);
4360:
4361: if (file == NULL)
4362: file = "<unknown file>";
4363:
4364: cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
4365: "attempt to redefine "
4366: "acl '%s' previous "
4367: "definition: %s:%u",
4368: name, file, line);
4369: result = ISC_R_FAILURE;
4370: }
4371: }
4372: }
4373: }
4374:
4375: tresult = cfg_map_get(config, "kal", &kals);
4376: if (tresult == ISC_R_SUCCESS) {
4377: const cfg_listelt_t *elt;
4378: const cfg_listelt_t *elt2;
4379: const char *aclname;
4380:
4381: for (elt = cfg_list_first(kals);
4382: elt != NULL;
4383: elt = cfg_list_next(elt)) {
4384: const cfg_obj_t *acl = cfg_listelt_value(elt);
4385:
4386: aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
4387:
4388: for (elt2 = cfg_list_next(elt);
4389: elt2 != NULL;
4390: elt2 = cfg_list_next(elt2)) {
4391: const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
4392: const char *name;
4393: name = cfg_obj_asstring(cfg_tuple_get(acl2,
4394: "name"));
4395: if (strcasecmp(aclname, name) == 0) {
4396: const char *file = cfg_obj_file(acl);
4397: unsigned int line = cfg_obj_line(acl);
4398:
4399: if (file == NULL)
4400: file = "<unknown file>";
4401:
4402: cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
4403: "attempt to redefine "
4404: "kal '%s' previous "
4405: "definition: %s:%u",
4406: name, file, line);
4407: result = ISC_R_FAILURE;
4408: }
4409: }
4410: }
4411: }
4412:
4413: cleanup:
4414: if (symtab != NULL)
4415: isc_symtab_destroy(&symtab);
4416: if (inview != NULL)
4417: isc_symtab_destroy(&inview);
4418: if (files != NULL)
4419: isc_symtab_destroy(&files);
4420:
4421: return (result);
4422: }
CVSweb <webmaster@jp.NetBSD.org>