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