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