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