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