]> CyberLeo.Net >> Repos - FreeBSD/releng/9.3.git/blob - contrib/bind9/bin/named/zoneconf.c
Copy stable/9 to releng/9.3 as part of the 9.3-RELEASE cycle.
[FreeBSD/releng/9.3.git] / contrib / bind9 / bin / named / zoneconf.c
1 /*
2  * Copyright (C) 2004-2014  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id$ */
19
20 /*% */
21
22 #include <config.h>
23
24 #include <isc/buffer.h>
25 #include <isc/file.h>
26 #include <isc/mem.h>
27 #include <isc/print.h>
28 #include <isc/stats.h>
29 #include <isc/string.h>         /* Required for HP/UX (and others?) */
30 #include <isc/util.h>
31
32 #include <dns/acl.h>
33 #include <dns/db.h>
34 #include <dns/fixedname.h>
35 #include <dns/log.h>
36 #include <dns/name.h>
37 #include <dns/rdata.h>
38 #include <dns/rdatatype.h>
39 #include <dns/rdataset.h>
40 #include <dns/rdatalist.h>
41 #include <dns/result.h>
42 #include <dns/sdlz.h>
43 #include <dns/ssu.h>
44 #include <dns/stats.h>
45 #include <dns/view.h>
46 #include <dns/zone.h>
47
48 #include <named/client.h>
49 #include <named/config.h>
50 #include <named/globals.h>
51 #include <named/log.h>
52 #include <named/server.h>
53 #include <named/zoneconf.h>
54
55 /* ACLs associated with zone */
56 typedef enum {
57         allow_notify,
58         allow_query,
59         allow_query_on,
60         allow_transfer,
61         allow_update,
62         allow_update_forwarding
63 } acl_type_t;
64
65 #define RETERR(x) do { \
66         isc_result_t _r = (x); \
67         if (_r != ISC_R_SUCCESS) \
68                 return (_r); \
69         } while (0)
70
71 #define CHECK(x) do { \
72         result = (x); \
73         if (result != ISC_R_SUCCESS) \
74                 goto cleanup; \
75         } while (0)
76
77 /*%
78  * Convenience function for configuring a single zone ACL.
79  */
80 static isc_result_t
81 configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
82                    const cfg_obj_t *config, acl_type_t acltype,
83                    cfg_aclconfctx_t *actx, dns_zone_t *zone,
84                    void (*setzacl)(dns_zone_t *, dns_acl_t *),
85                    void (*clearzacl)(dns_zone_t *))
86 {
87         isc_result_t result;
88         const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL};
89         const cfg_obj_t *aclobj = NULL;
90         int i = 0;
91         dns_acl_t **aclp = NULL, *acl = NULL;
92         const char *aclname;
93         dns_view_t *view;
94
95         view = dns_zone_getview(zone);
96
97         switch (acltype) {
98             case allow_notify:
99                 if (view != NULL)
100                         aclp = &view->notifyacl;
101                 aclname = "allow-notify";
102                 break;
103             case allow_query:
104                 if (view != NULL)
105                         aclp = &view->queryacl;
106                 aclname = "allow-query";
107                 break;
108             case allow_query_on:
109                 if (view != NULL)
110                         aclp = &view->queryonacl;
111                 aclname = "allow-query-on";
112                 break;
113             case allow_transfer:
114                 if (view != NULL)
115                         aclp = &view->transferacl;
116                 aclname = "allow-transfer";
117                 break;
118             case allow_update:
119                 if (view != NULL)
120                         aclp = &view->updateacl;
121                 aclname = "allow-update";
122                 break;
123             case allow_update_forwarding:
124                 if (view != NULL)
125                         aclp = &view->upfwdacl;
126                 aclname = "allow-update-forwarding";
127                 break;
128             default:
129                 INSIST(0);
130                 return (ISC_R_FAILURE);
131         }
132
133         /* First check to see if ACL is defined within the zone */
134         if (zconfig != NULL) {
135                 maps[0] = cfg_tuple_get(zconfig, "options");
136                 (void)ns_config_get(maps, aclname, &aclobj);
137                 if (aclobj != NULL) {
138                         aclp = NULL;
139                         goto parse_acl;
140                 }
141         }
142
143         /* Failing that, see if there's a default ACL already in the view */
144         if (aclp != NULL && *aclp != NULL) {
145                 (*setzacl)(zone, *aclp);
146                 return (ISC_R_SUCCESS);
147         }
148
149         /* Check for default ACLs that haven't been parsed yet */
150         if (vconfig != NULL) {
151                 const cfg_obj_t *options = cfg_tuple_get(vconfig, "options");
152                 if (options != NULL)
153                         maps[i++] = options;
154         }
155         if (config != NULL) {
156                 const cfg_obj_t *options = NULL;
157                 (void)cfg_map_get(config, "options", &options);
158                 if (options != NULL)
159                         maps[i++] = options;
160         }
161         maps[i++] = ns_g_defaults;
162         maps[i] = NULL;
163
164         (void)ns_config_get(maps, aclname, &aclobj);
165         if (aclobj == NULL) {
166                 (*clearzacl)(zone);
167                 return (ISC_R_SUCCESS);
168         }
169
170 parse_acl:
171         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx,
172                                     dns_zone_getmctx(zone), 0, &acl);
173         if (result != ISC_R_SUCCESS)
174                 return (result);
175         (*setzacl)(zone, acl);
176
177         /* Set the view default now */
178         if (aclp != NULL)
179                 dns_acl_attach(acl, aclp);
180
181         dns_acl_detach(&acl);
182         return (ISC_R_SUCCESS);
183 }
184
185 /*%
186  * Parse the zone update-policy statement.
187  */
188 static isc_result_t
189 configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone,
190                         const char *zname)
191 {
192         const cfg_obj_t *updatepolicy = NULL;
193         const cfg_listelt_t *element, *element2;
194         dns_ssutable_t *table = NULL;
195         isc_mem_t *mctx = dns_zone_getmctx(zone);
196         isc_boolean_t autoddns = ISC_FALSE;
197         isc_result_t result;
198
199         (void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
200
201         if (updatepolicy == NULL) {
202                 dns_zone_setssutable(zone, NULL);
203                 return (ISC_R_SUCCESS);
204         }
205
206         if (cfg_obj_isstring(updatepolicy) &&
207             strcmp("local", cfg_obj_asstring(updatepolicy)) == 0) {
208                 autoddns = ISC_TRUE;
209                 updatepolicy = NULL;
210         }
211
212         result = dns_ssutable_create(mctx, &table);
213         if (result != ISC_R_SUCCESS)
214                 return (result);
215
216         for (element = cfg_list_first(updatepolicy);
217              element != NULL;
218              element = cfg_list_next(element))
219         {
220                 const cfg_obj_t *stmt = cfg_listelt_value(element);
221                 const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
222                 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
223                 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
224                 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
225                 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
226                 const char *str;
227                 isc_boolean_t grant = ISC_FALSE;
228                 isc_boolean_t usezone = ISC_FALSE;
229                 unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
230                 dns_fixedname_t fname, fident;
231                 isc_buffer_t b;
232                 dns_rdatatype_t *types;
233                 unsigned int i, n;
234
235                 str = cfg_obj_asstring(mode);
236                 if (strcasecmp(str, "grant") == 0)
237                         grant = ISC_TRUE;
238                 else if (strcasecmp(str, "deny") == 0)
239                         grant = ISC_FALSE;
240                 else
241                         INSIST(0);
242
243                 str = cfg_obj_asstring(matchtype);
244                 if (strcasecmp(str, "name") == 0)
245                         mtype = DNS_SSUMATCHTYPE_NAME;
246                 else if (strcasecmp(str, "subdomain") == 0)
247                         mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
248                 else if (strcasecmp(str, "wildcard") == 0)
249                         mtype = DNS_SSUMATCHTYPE_WILDCARD;
250                 else if (strcasecmp(str, "self") == 0)
251                         mtype = DNS_SSUMATCHTYPE_SELF;
252                 else if (strcasecmp(str, "selfsub") == 0)
253                         mtype = DNS_SSUMATCHTYPE_SELFSUB;
254                 else if (strcasecmp(str, "selfwild") == 0)
255                         mtype = DNS_SSUMATCHTYPE_SELFWILD;
256                 else if (strcasecmp(str, "ms-self") == 0)
257                         mtype = DNS_SSUMATCHTYPE_SELFMS;
258                 else if (strcasecmp(str, "krb5-self") == 0)
259                         mtype = DNS_SSUMATCHTYPE_SELFKRB5;
260                 else if (strcasecmp(str, "ms-subdomain") == 0)
261                         mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
262                 else if (strcasecmp(str, "krb5-subdomain") == 0)
263                         mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
264                 else if (strcasecmp(str, "tcp-self") == 0)
265                         mtype = DNS_SSUMATCHTYPE_TCPSELF;
266                 else if (strcasecmp(str, "6to4-self") == 0)
267                         mtype = DNS_SSUMATCHTYPE_6TO4SELF;
268                 else if (strcasecmp(str, "zonesub") == 0) {
269                         mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
270                         usezone = ISC_TRUE;
271                 } else if (strcasecmp(str, "external") == 0)
272                         mtype = DNS_SSUMATCHTYPE_EXTERNAL;
273                 else
274                         INSIST(0);
275
276                 dns_fixedname_init(&fident);
277                 str = cfg_obj_asstring(identity);
278                 isc_buffer_constinit(&b, str, strlen(str));
279                 isc_buffer_add(&b, strlen(str));
280                 result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
281                                            dns_rootname, 0, NULL);
282                 if (result != ISC_R_SUCCESS) {
283                         cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
284                                     "'%s' is not a valid name", str);
285                         goto cleanup;
286                 }
287
288                 dns_fixedname_init(&fname);
289                 if (usezone) {
290                         result = dns_name_copy(dns_zone_getorigin(zone),
291                                                dns_fixedname_name(&fname),
292                                                NULL);
293                         if (result != ISC_R_SUCCESS) {
294                                 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
295                                             "error copying origin: %s",
296                                             isc_result_totext(result));
297                                 goto cleanup;
298                         }
299                 } else {
300                         str = cfg_obj_asstring(dname);
301                         isc_buffer_constinit(&b, str, strlen(str));
302                         isc_buffer_add(&b, strlen(str));
303                         result = dns_name_fromtext(dns_fixedname_name(&fname),
304                                                    &b, dns_rootname, 0, NULL);
305                         if (result != ISC_R_SUCCESS) {
306                                 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
307                                             "'%s' is not a valid name", str);
308                                 goto cleanup;
309                         }
310                 }
311
312                 n = ns_config_listcount(typelist);
313                 if (n == 0)
314                         types = NULL;
315                 else {
316                         types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
317                         if (types == NULL) {
318                                 result = ISC_R_NOMEMORY;
319                                 goto cleanup;
320                         }
321                 }
322
323                 i = 0;
324                 for (element2 = cfg_list_first(typelist);
325                      element2 != NULL;
326                      element2 = cfg_list_next(element2))
327                 {
328                         const cfg_obj_t *typeobj;
329                         isc_textregion_t r;
330
331                         INSIST(i < n);
332
333                         typeobj = cfg_listelt_value(element2);
334                         str = cfg_obj_asstring(typeobj);
335                         DE_CONST(str, r.base);
336                         r.length = strlen(str);
337
338                         result = dns_rdatatype_fromtext(&types[i++], &r);
339                         if (result != ISC_R_SUCCESS) {
340                                 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
341                                             "'%s' is not a valid type", str);
342                                 isc_mem_put(mctx, types,
343                                             n * sizeof(dns_rdatatype_t));
344                                 goto cleanup;
345                         }
346                 }
347                 INSIST(i == n);
348
349                 result = dns_ssutable_addrule(table, grant,
350                                               dns_fixedname_name(&fident),
351                                               mtype,
352                                               dns_fixedname_name(&fname),
353                                               n, types);
354                 if (types != NULL)
355                         isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
356                 if (result != ISC_R_SUCCESS) {
357                         goto cleanup;
358                 }
359         }
360
361         /*
362          * If "update-policy local;" and a session key exists,
363          * then use the default policy, which is equivalent to:
364          * update-policy { grant <session-keyname> zonesub any; };
365          */
366         if (autoddns) {
367                 dns_rdatatype_t any = dns_rdatatype_any;
368
369                 if (ns_g_server->session_keyname == NULL) {
370                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
371                                       NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
372                                       "failed to enable auto DDNS policy "
373                                       "for zone %s: session key not found",
374                                       zname);
375                         result = ISC_R_NOTFOUND;
376                         goto cleanup;
377                 }
378
379                 result = dns_ssutable_addrule(table, ISC_TRUE,
380                                               ns_g_server->session_keyname,
381                                               DNS_SSUMATCHTYPE_SUBDOMAIN,
382                                               dns_zone_getorigin(zone),
383                                               1, &any);
384
385                 if (result != ISC_R_SUCCESS)
386                         goto cleanup;
387         }
388
389         result = ISC_R_SUCCESS;
390         dns_zone_setssutable(zone, table);
391
392  cleanup:
393         dns_ssutable_detach(&table);
394         return (result);
395 }
396
397 /*
398  * This is the TTL used for internally generated RRsets for static-stub zones.
399  * The value doesn't matter because the mapping is static, but needs to be
400  * defined for the sake of implementation.
401  */
402 #define STATICSTUB_SERVER_TTL 86400
403
404 /*%
405  * Configure an apex NS with glues for a static-stub zone.
406  * For example, for the zone named "example.com", the following RRs will be
407  * added to the zone DB:
408  * example.com. NS example.com.
409  * example.com. A 192.0.2.1
410  * example.com. AAAA 2001:db8::1
411  */
412 static isc_result_t
413 configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone,
414                                  dns_rdatalist_t *rdatalist_ns,
415                                  dns_rdatalist_t *rdatalist_a,
416                                  dns_rdatalist_t *rdatalist_aaaa)
417 {
418         const cfg_listelt_t *element;
419         isc_mem_t *mctx = dns_zone_getmctx(zone);
420         isc_region_t region, sregion;
421         dns_rdata_t *rdata;
422         isc_result_t result = ISC_R_SUCCESS;
423
424         for (element = cfg_list_first(zconfig);
425              element != NULL;
426              element = cfg_list_next(element))
427         {
428                 const isc_sockaddr_t* sa;
429                 isc_netaddr_t na;
430                 const cfg_obj_t *address = cfg_listelt_value(element);
431                 dns_rdatalist_t *rdatalist;
432
433                 sa = cfg_obj_assockaddr(address);
434                 if (isc_sockaddr_getport(sa) != 0) {
435                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
436                                     "port is not configurable for "
437                                     "static stub server-addresses");
438                         return (ISC_R_FAILURE);
439                 }
440                 isc_netaddr_fromsockaddr(&na, sa);
441                 if (isc_netaddr_getzone(&na) != 0) {
442                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
443                                             "scoped address is not allowed "
444                                             "for static stub "
445                                             "server-addresses");
446                         return (ISC_R_FAILURE);
447                 }
448
449                 switch (na.family) {
450                 case AF_INET:
451                         region.length = sizeof(na.type.in);
452                         rdatalist = rdatalist_a;
453                         break;
454                 default:
455                         INSIST(na.family == AF_INET6);
456                         region.length = sizeof(na.type.in6);
457                         rdatalist = rdatalist_aaaa;
458                         break;
459                 }
460
461                 rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length);
462                 if (rdata == NULL)
463                         return (ISC_R_NOMEMORY);
464                 region.base = (unsigned char *)(rdata + 1);
465                 memmove(region.base, &na.type, region.length);
466                 dns_rdata_init(rdata);
467                 dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
468                                      rdatalist->type, &region);
469                 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
470         }
471
472         /*
473          * If no address is specified (unlikely in this context, but possible),
474          * there's nothing to do anymore.
475          */
476         if (ISC_LIST_EMPTY(rdatalist_a->rdata) &&
477             ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) {
478                 return (ISC_R_SUCCESS);
479         }
480
481         /* Add to the list an apex NS with the ns name being the origin name */
482         dns_name_toregion(dns_zone_getorigin(zone), &sregion);
483         rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
484         if (rdata == NULL) {
485                 /*
486                  * Already allocated data will be freed in the caller, so
487                  * we can simply return here.
488                  */
489                 return (ISC_R_NOMEMORY);
490         }
491         region.length = sregion.length;
492         region.base = (unsigned char *)(rdata + 1);
493         memmove(region.base, sregion.base, region.length);
494         dns_rdata_init(rdata);
495         dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
496                              dns_rdatatype_ns, &region);
497         ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link);
498
499         return (result);
500 }
501
502 /*%
503  * Configure an apex NS with an out-of-zone NS names for a static-stub zone.
504  * For example, for the zone named "example.com", something like the following
505  * RRs will be added to the zone DB:
506  * example.com. NS ns.example.net.
507  */
508 static isc_result_t
509 configure_staticstub_servernames(const cfg_obj_t *zconfig, dns_zone_t *zone,
510                                  dns_rdatalist_t *rdatalist, const char *zname)
511 {
512         const cfg_listelt_t *element;
513         isc_mem_t *mctx = dns_zone_getmctx(zone);
514         dns_rdata_t *rdata;
515         isc_region_t sregion, region;
516         isc_result_t result = ISC_R_SUCCESS;
517
518         for (element = cfg_list_first(zconfig);
519              element != NULL;
520              element = cfg_list_next(element))
521         {
522                 const cfg_obj_t *obj;
523                 const char *str;
524                 dns_fixedname_t fixed_name;
525                 dns_name_t *nsname;
526                 isc_buffer_t b;
527
528                 obj = cfg_listelt_value(element);
529                 str = cfg_obj_asstring(obj);
530
531                 dns_fixedname_init(&fixed_name);
532                 nsname = dns_fixedname_name(&fixed_name);
533
534                 isc_buffer_constinit(&b, str, strlen(str));
535                 isc_buffer_add(&b, strlen(str));
536                 result = dns_name_fromtext(nsname, &b, dns_rootname, 0, NULL);
537                 if (result != ISC_R_SUCCESS) {
538                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
539                                             "server-name '%s' is not a valid "
540                                             "name", str);
541                         return (result);
542                 }
543                 if (dns_name_issubdomain(nsname, dns_zone_getorigin(zone))) {
544                         cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
545                                     "server-name '%s' must not be a "
546                                     "subdomain of zone name '%s'",
547                                     str, zname);
548                         return (ISC_R_FAILURE);
549                 }
550
551                 dns_name_toregion(nsname, &sregion);
552                 rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
553                 if (rdata == NULL)
554                         return (ISC_R_NOMEMORY);
555                 region.length = sregion.length;
556                 region.base = (unsigned char *)(rdata + 1);
557                 memmove(region.base, sregion.base, region.length);
558                 dns_rdata_init(rdata);
559                 dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
560                                      dns_rdatatype_ns, &region);
561                 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
562         }
563
564         return (result);
565 }
566
567 /*%
568  * Configure static-stub zone.
569  */
570 static isc_result_t
571 configure_staticstub(const cfg_obj_t *zconfig, dns_zone_t *zone,
572                      const char *zname, const char *dbtype)
573 {
574         int i = 0;
575         const cfg_obj_t *obj;
576         isc_mem_t *mctx = dns_zone_getmctx(zone);
577         dns_db_t *db = NULL;
578         dns_dbversion_t *dbversion = NULL;
579         dns_dbnode_t *apexnode = NULL;
580         dns_name_t apexname;
581         isc_result_t result;
582         dns_rdataset_t rdataset;
583         dns_rdatalist_t rdatalist_ns, rdatalist_a, rdatalist_aaaa;
584         dns_rdatalist_t* rdatalists[] = {
585                 &rdatalist_ns, &rdatalist_a, &rdatalist_aaaa, NULL
586         };
587         dns_rdata_t *rdata;
588         isc_region_t region;
589
590         /* Create the DB beforehand */
591         RETERR(dns_db_create(mctx, dbtype, dns_zone_getorigin(zone),
592                              dns_dbtype_stub, dns_zone_getclass(zone),
593                              0, NULL, &db));
594         dns_zone_setdb(zone, db);
595
596         dns_rdatalist_init(&rdatalist_ns);
597         rdatalist_ns.rdclass = dns_zone_getclass(zone);
598         rdatalist_ns.type = dns_rdatatype_ns;
599         rdatalist_ns.ttl = STATICSTUB_SERVER_TTL;
600
601         dns_rdatalist_init(&rdatalist_a);
602         rdatalist_a.rdclass = dns_zone_getclass(zone);
603         rdatalist_a.type = dns_rdatatype_a;
604         rdatalist_a.ttl = STATICSTUB_SERVER_TTL;
605
606         dns_rdatalist_init(&rdatalist_aaaa);
607         rdatalist_aaaa.rdclass = dns_zone_getclass(zone);
608         rdatalist_aaaa.type = dns_rdatatype_aaaa;
609         rdatalist_aaaa.ttl = STATICSTUB_SERVER_TTL;
610
611         /* Prepare zone RRs from the configuration */
612         obj = NULL;
613         result = cfg_map_get(zconfig, "server-addresses", &obj);
614         if (result == ISC_R_SUCCESS) {
615                 INSIST(obj != NULL);
616                 result = configure_staticstub_serveraddrs(obj, zone,
617                                                           &rdatalist_ns,
618                                                           &rdatalist_a,
619                                                           &rdatalist_aaaa);
620                 if (result != ISC_R_SUCCESS)
621                         goto cleanup;
622         }
623
624         obj = NULL;
625         result = cfg_map_get(zconfig, "server-names", &obj);
626         if (result == ISC_R_SUCCESS) {
627                 INSIST(obj != NULL);
628                 result = configure_staticstub_servernames(obj, zone,
629                                                           &rdatalist_ns,
630                                                           zname);
631                 if (result != ISC_R_SUCCESS)
632                         goto cleanup;
633         }
634
635         /*
636          * Sanity check: there should be at least one NS RR at the zone apex
637          * to trigger delegation.
638          */
639         if (ISC_LIST_EMPTY(rdatalist_ns.rdata)) {
640                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
641                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
642                               "No NS record is configured for a "
643                               "static-stub zone '%s'", zname);
644                 result = ISC_R_FAILURE;
645                 goto cleanup;
646         }
647
648         /*
649          * Now add NS and glue A/AAAA RRsets to the zone DB.
650          * First open a new version for the add operation and get a pointer
651          * to the apex node (all RRs are of the apex name).
652          */
653         result = dns_db_newversion(db, &dbversion);
654         if (result != ISC_R_SUCCESS)
655                 goto cleanup;
656         dns_name_init(&apexname, NULL);
657         dns_name_clone(dns_zone_getorigin(zone), &apexname);
658         result = dns_db_findnode(db, &apexname, ISC_FALSE, &apexnode);
659         if (result != ISC_R_SUCCESS)
660                 goto cleanup;
661
662         /* Add NS RRset */
663         dns_rdataset_init(&rdataset);
664         RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_ns, &rdataset)
665                       == ISC_R_SUCCESS);
666         result = dns_db_addrdataset(db, apexnode, dbversion, 0, &rdataset,
667                                     0, NULL);
668         dns_rdataset_disassociate(&rdataset);
669         if (result != ISC_R_SUCCESS)
670                 goto cleanup;
671
672         /* Add glue A RRset, if any */
673         if (!ISC_LIST_EMPTY(rdatalist_a.rdata)) {
674                 RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_a, &rdataset)
675                               == ISC_R_SUCCESS);
676                 result = dns_db_addrdataset(db, apexnode, dbversion, 0,
677                                             &rdataset, 0, NULL);
678                 dns_rdataset_disassociate(&rdataset);
679                 if (result != ISC_R_SUCCESS)
680                         goto cleanup;
681         }
682
683         /* Add glue AAAA RRset, if any */
684         if (!ISC_LIST_EMPTY(rdatalist_aaaa.rdata)) {
685                 RUNTIME_CHECK(dns_rdatalist_tordataset(&rdatalist_aaaa,
686                                                        &rdataset)
687                               == ISC_R_SUCCESS);
688                 result = dns_db_addrdataset(db, apexnode, dbversion, 0,
689                                             &rdataset, 0, NULL);
690                 dns_rdataset_disassociate(&rdataset);
691                 if (result != ISC_R_SUCCESS)
692                         goto cleanup;
693         }
694
695         result = ISC_R_SUCCESS;
696
697   cleanup:
698         if (apexnode != NULL)
699                 dns_db_detachnode(db, &apexnode);
700         if (dbversion != NULL)
701                 dns_db_closeversion(db, &dbversion, ISC_TRUE);
702         if (db != NULL)
703                 dns_db_detach(&db);
704         for (i = 0; rdatalists[i] != NULL; i++) {
705                 while ((rdata = ISC_LIST_HEAD(rdatalists[i]->rdata)) != NULL) {
706                         ISC_LIST_UNLINK(rdatalists[i]->rdata, rdata, link);
707                         dns_rdata_toregion(rdata, &region);
708                         isc_mem_put(mctx, rdata,
709                                     sizeof(*rdata) + region.length);
710                 }
711         }
712
713         return (result);
714 }
715
716 /*%
717  * Convert a config file zone type into a server zone type.
718  */
719 static inline dns_zonetype_t
720 zonetype_fromconfig(const cfg_obj_t *map) {
721         const cfg_obj_t *obj = NULL;
722         isc_result_t result;
723
724         result = cfg_map_get(map, "type", &obj);
725         INSIST(result == ISC_R_SUCCESS && obj != NULL);
726         return (ns_config_getzonetype(obj));
727 }
728
729 /*%
730  * Helper function for strtoargv().  Pardon the gratuitous recursion.
731  */
732 static isc_result_t
733 strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
734              char ***argvp, unsigned int n)
735 {
736         isc_result_t result;
737
738         /* Discard leading whitespace. */
739         while (*s == ' ' || *s == '\t')
740                 s++;
741
742         if (*s == '\0') {
743                 /* We have reached the end of the string. */
744                 *argcp = n;
745                 *argvp = isc_mem_get(mctx, n * sizeof(char *));
746                 if (*argvp == NULL)
747                         return (ISC_R_NOMEMORY);
748         } else {
749                 char *p = s;
750                 while (*p != ' ' && *p != '\t' && *p != '\0')
751                         p++;
752                 if (*p != '\0')
753                         *p++ = '\0';
754
755                 result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
756                 if (result != ISC_R_SUCCESS)
757                         return (result);
758                 (*argvp)[n] = s;
759         }
760         return (ISC_R_SUCCESS);
761 }
762
763 /*%
764  * Tokenize the string "s" into whitespace-separated words,
765  * return the number of words in '*argcp' and an array
766  * of pointers to the words in '*argvp'.  The caller
767  * must free the array using isc_mem_put().  The string
768  * is modified in-place.
769  */
770 static isc_result_t
771 strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
772         return (strtoargvsub(mctx, s, argcp, argvp, 0));
773 }
774
775 static void
776 checknames(dns_zonetype_t ztype, const cfg_obj_t **maps,
777            const cfg_obj_t **objp)
778 {
779         const char *zone = NULL;
780         isc_result_t result;
781
782         switch (ztype) {
783         case dns_zone_slave: zone = "slave"; break;
784         case dns_zone_master: zone = "master"; break;
785         default:
786                 INSIST(0);
787         }
788         result = ns_checknames_get(maps, zone, objp);
789         INSIST(result == ISC_R_SUCCESS && objp != NULL && *objp != NULL);
790 }
791
792 isc_result_t
793 ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
794                   const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
795                   dns_zone_t *zone, dns_zone_t *raw)
796 {
797         isc_result_t result;
798         const char *zname;
799         dns_rdataclass_t zclass;
800         dns_rdataclass_t vclass;
801         const cfg_obj_t *maps[5];
802         const cfg_obj_t *zoptions = NULL;
803         const cfg_obj_t *options = NULL;
804         const cfg_obj_t *obj;
805         const char *filename = NULL;
806         dns_notifytype_t notifytype = dns_notifytype_yes;
807         isc_sockaddr_t *addrs;
808         dns_name_t **keynames;
809         isc_uint32_t count;
810         char *cpval;
811         unsigned int dbargc;
812         char **dbargv;
813         static char default_dbtype[] = "rbt";
814         isc_mem_t *mctx = dns_zone_getmctx(zone);
815         dns_dialuptype_t dialup = dns_dialuptype_no;
816         dns_zonetype_t ztype;
817         int i;
818         isc_int32_t journal_size;
819         isc_boolean_t multi;
820         isc_boolean_t alt;
821         dns_view_t *view;
822         isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
823         isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE;
824         isc_boolean_t ixfrdiff;
825         dns_masterformat_t masterformat;
826         isc_stats_t *zoneqrystats;
827 #ifdef NEWSTATS
828         dns_stats_t *rcvquerystats;
829 #endif
830         dns_zonestat_level_t statlevel;
831         int seconds;
832         dns_zone_t *mayberaw = (raw != NULL) ? raw : zone;
833
834         i = 0;
835         if (zconfig != NULL) {
836                 zoptions = cfg_tuple_get(zconfig, "options");
837                 maps[i++] = zoptions;
838         }
839         if (vconfig != NULL)
840                 maps[i++] = cfg_tuple_get(vconfig, "options");
841         if (config != NULL) {
842                 (void)cfg_map_get(config, "options", &options);
843                 if (options != NULL)
844                         maps[i++] = options;
845         }
846         maps[i++] = ns_g_defaults;
847         maps[i] = NULL;
848
849         if (vconfig != NULL)
850                 RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
851                                           dns_rdataclass_in, &vclass));
852         else
853                 vclass = dns_rdataclass_in;
854
855         /*
856          * Configure values common to all zone types.
857          */
858
859         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
860
861         RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
862                                   vclass, &zclass));
863         dns_zone_setclass(zone, zclass);
864         if (raw != NULL)
865                 dns_zone_setclass(raw, zclass);
866
867         ztype = zonetype_fromconfig(zoptions);
868         if (raw != NULL) {
869                 dns_zone_settype(raw, ztype);
870                 dns_zone_settype(zone, dns_zone_master);
871         } else
872                 dns_zone_settype(zone, ztype);
873
874
875         obj = NULL;
876         result = cfg_map_get(zoptions, "database", &obj);
877         if (result == ISC_R_SUCCESS)
878                 cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
879         else
880                 cpval = default_dbtype;
881
882         if (cpval == NULL)
883                 return(ISC_R_NOMEMORY);
884
885         result = strtoargv(mctx, cpval, &dbargc, &dbargv);
886         if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
887                 isc_mem_free(mctx, cpval);
888                 return (result);
889         }
890
891         /*
892          * ANSI C is strange here.  There is no logical reason why (char **)
893          * cannot be promoted automatically to (const char * const *) by the
894          * compiler w/o generating a warning.
895          */
896         result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
897         isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
898         if (cpval != default_dbtype)
899                 isc_mem_free(mctx, cpval);
900         if (result != ISC_R_SUCCESS)
901                 return (result);
902
903         obj = NULL;
904         result = cfg_map_get(zoptions, "file", &obj);
905         if (result == ISC_R_SUCCESS)
906                 filename = cfg_obj_asstring(obj);
907
908         /*
909          * Unless we're using some alternative database, a master zone
910          * will be needing a master file.
911          */
912         if (ztype == dns_zone_master && cpval == default_dbtype &&
913             filename == NULL) {
914                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
915                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
916                               "zone '%s': 'file' not specified",
917                               zname);
918                 return (ISC_R_FAILURE);
919         }
920
921         if (ztype == dns_zone_slave)
922                 masterformat = dns_masterformat_raw;
923         else
924                 masterformat = dns_masterformat_text;
925         obj = NULL;
926         result= ns_config_get(maps, "masterfile-format", &obj);
927         if (result == ISC_R_SUCCESS) {
928                 const char *masterformatstr = cfg_obj_asstring(obj);
929
930                 if (strcasecmp(masterformatstr, "text") == 0)
931                         masterformat = dns_masterformat_text;
932                 else if (strcasecmp(masterformatstr, "raw") == 0)
933                         masterformat = dns_masterformat_raw;
934                 else
935                         INSIST(0);
936         }
937
938         if (raw != NULL && filename != NULL) {
939 #define SIGNED ".signed"
940                 size_t signedlen = strlen(filename) + sizeof(SIGNED);
941                 char *signedname;
942
943                 RETERR(dns_zone_setfile2(raw, filename, masterformat));
944                 signedname = isc_mem_get(mctx, signedlen);
945                 if (signedname == NULL)
946                         return (ISC_R_NOMEMORY);
947
948                 (void)snprintf(signedname, signedlen, "%s" SIGNED, filename);
949                 result = dns_zone_setfile2(zone, signedname,
950                                            dns_masterformat_raw);
951                 isc_mem_put(mctx, signedname, signedlen);
952                 if (result != ISC_R_SUCCESS)
953                         return (result);
954         } else
955                 RETERR(dns_zone_setfile2(zone, filename, masterformat));
956
957         obj = NULL;
958         result = cfg_map_get(zoptions, "journal", &obj);
959         if (result == ISC_R_SUCCESS)
960                 RETERR(dns_zone_setjournal(mayberaw, cfg_obj_asstring(obj)));
961
962         /*
963          * Notify messages are processed by the raw zone if it exists.
964          */
965         if (ztype == dns_zone_slave)
966                 RETERR(configure_zone_acl(zconfig, vconfig, config,
967                                           allow_notify, ac, mayberaw,
968                                           dns_zone_setnotifyacl,
969                                           dns_zone_clearnotifyacl));
970
971         /*
972          * XXXAG This probably does not make sense for stubs.
973          */
974         RETERR(configure_zone_acl(zconfig, vconfig, config,
975                                   allow_query, ac, zone,
976                                   dns_zone_setqueryacl,
977                                   dns_zone_clearqueryacl));
978
979         RETERR(configure_zone_acl(zconfig, vconfig, config,
980                                   allow_query_on, ac, zone,
981                                   dns_zone_setqueryonacl,
982                                   dns_zone_clearqueryonacl));
983
984         obj = NULL;
985         result = ns_config_get(maps, "dialup", &obj);
986         INSIST(result == ISC_R_SUCCESS && obj != NULL);
987         if (cfg_obj_isboolean(obj)) {
988                 if (cfg_obj_asboolean(obj))
989                         dialup = dns_dialuptype_yes;
990                 else
991                         dialup = dns_dialuptype_no;
992         } else {
993                 const char *dialupstr = cfg_obj_asstring(obj);
994                 if (strcasecmp(dialupstr, "notify") == 0)
995                         dialup = dns_dialuptype_notify;
996                 else if (strcasecmp(dialupstr, "notify-passive") == 0)
997                         dialup = dns_dialuptype_notifypassive;
998                 else if (strcasecmp(dialupstr, "refresh") == 0)
999                         dialup = dns_dialuptype_refresh;
1000                 else if (strcasecmp(dialupstr, "passive") == 0)
1001                         dialup = dns_dialuptype_passive;
1002                 else
1003                         INSIST(0);
1004         }
1005         if (raw != NULL)
1006                 dns_zone_setdialup(raw, dialup);
1007         dns_zone_setdialup(zone, dialup);
1008
1009         obj = NULL;
1010         result = ns_config_get(maps, "zone-statistics", &obj);
1011         INSIST(result == ISC_R_SUCCESS && obj != NULL);
1012         if (cfg_obj_isboolean(obj)) {
1013                 if (cfg_obj_asboolean(obj))
1014                         statlevel = dns_zonestat_full;
1015                 else
1016                         statlevel = dns_zonestat_terse; /* XXX */
1017         } else {
1018                 const char *levelstr = cfg_obj_asstring(obj);
1019                 if (strcasecmp(levelstr, "full") == 0)
1020                         statlevel = dns_zonestat_full;
1021                 else if (strcasecmp(levelstr, "terse") == 0)
1022                         statlevel = dns_zonestat_terse;
1023                 else if (strcasecmp(levelstr, "none") == 0)
1024                         statlevel = dns_zonestat_none;
1025                 else
1026                         INSIST(0);
1027         }
1028         dns_zone_setstatlevel(zone, statlevel);
1029
1030         zoneqrystats  = NULL;
1031 #ifdef NEWSTATS
1032         rcvquerystats = NULL;
1033 #endif
1034         if (statlevel == dns_zonestat_full) {
1035                 RETERR(isc_stats_create(mctx, &zoneqrystats,
1036                                         dns_nsstatscounter_max));
1037 #ifdef NEWSTATS
1038                 RETERR(dns_rdatatypestats_create(mctx,
1039                                         &rcvquerystats));
1040 #endif
1041         }
1042         dns_zone_setrequeststats(zone,  zoneqrystats );
1043 #ifdef NEWSTATS
1044         dns_zone_setrcvquerystats(zone, rcvquerystats);
1045 #endif
1046
1047         if (zoneqrystats != NULL)
1048                 isc_stats_detach(&zoneqrystats);
1049
1050 #ifdef NEWSTATS
1051         if(rcvquerystats != NULL)
1052                 dns_stats_detach(&rcvquerystats);
1053 #endif
1054
1055         /*
1056          * Configure master functionality.  This applies
1057          * to primary masters (type "master") and slaves
1058          * acting as masters (type "slave"), but not to stubs.
1059          */
1060         if (ztype != dns_zone_stub && ztype != dns_zone_staticstub &&
1061             ztype != dns_zone_redirect) {
1062                 obj = NULL;
1063                 result = ns_config_get(maps, "notify", &obj);
1064                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1065                 if (cfg_obj_isboolean(obj)) {
1066                         if (cfg_obj_asboolean(obj))
1067                                 notifytype = dns_notifytype_yes;
1068                         else
1069                                 notifytype = dns_notifytype_no;
1070                 } else {
1071                         const char *notifystr = cfg_obj_asstring(obj);
1072                         if (strcasecmp(notifystr, "explicit") == 0)
1073                                 notifytype = dns_notifytype_explicit;
1074                         else if (strcasecmp(notifystr, "master-only") == 0)
1075                                 notifytype = dns_notifytype_masteronly;
1076                         else
1077                                 INSIST(0);
1078                 }
1079                 if (raw != NULL)
1080                         dns_zone_setnotifytype(raw, dns_notifytype_no);
1081                 dns_zone_setnotifytype(zone, notifytype);
1082
1083                 obj = NULL;
1084                 result = ns_config_get(maps, "also-notify", &obj);
1085                 if (result == ISC_R_SUCCESS) {
1086                         isc_uint32_t addrcount;
1087                         addrs = NULL;
1088                         keynames = NULL;
1089                         RETERR(ns_config_getipandkeylist(config, obj, mctx,
1090                                                          &addrs, &keynames,
1091                                                          &addrcount));
1092                         result = dns_zone_setalsonotifywithkeys(zone, addrs,
1093                                                                 keynames,
1094                                                                 addrcount);
1095                         if (addrcount != 0)
1096                                 ns_config_putipandkeylist(mctx, &addrs,
1097                                                           &keynames, addrcount);
1098                         else
1099                                 INSIST(addrs == NULL && keynames == NULL);
1100                         RETERR(result);
1101                 } else
1102                         RETERR(dns_zone_setalsonotify(zone, NULL, 0));
1103
1104                 obj = NULL;
1105                 result = ns_config_get(maps, "notify-source", &obj);
1106                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1107                 RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
1108                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1109
1110                 obj = NULL;
1111                 result = ns_config_get(maps, "notify-source-v6", &obj);
1112                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1113                 RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
1114                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1115
1116                 obj = NULL;
1117                 result = ns_config_get(maps, "notify-to-soa", &obj);
1118                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1119                 dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
1120                                    cfg_obj_asboolean(obj));
1121
1122                 dns_zone_setisself(zone, ns_client_isself, NULL);
1123
1124                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1125                                           allow_transfer, ac, zone,
1126                                           dns_zone_setxfracl,
1127                                           dns_zone_clearxfracl));
1128
1129                 obj = NULL;
1130                 result = ns_config_get(maps, "max-transfer-time-out", &obj);
1131                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1132                 dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
1133
1134                 obj = NULL;
1135                 result = ns_config_get(maps, "max-transfer-idle-out", &obj);
1136                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1137                 dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
1138
1139                 obj = NULL;
1140                 result = ns_config_get(maps, "max-journal-size", &obj);
1141                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1142                 if (raw != NULL)
1143                         dns_zone_setjournalsize(raw, -1);
1144                 dns_zone_setjournalsize(zone, -1);
1145                 if (cfg_obj_isstring(obj)) {
1146                         const char *str = cfg_obj_asstring(obj);
1147                         INSIST(strcasecmp(str, "unlimited") == 0);
1148                         journal_size = ISC_UINT32_MAX / 2;
1149                 } else {
1150                         isc_resourcevalue_t value;
1151                         value = cfg_obj_asuint64(obj);
1152                         if (value > ISC_UINT32_MAX / 2) {
1153                                 cfg_obj_log(obj, ns_g_lctx,
1154                                             ISC_LOG_ERROR,
1155                                             "'max-journal-size "
1156                                             "%" ISC_PRINT_QUADFORMAT "d' "
1157                                             "is too large",
1158                                             value);
1159                                 RETERR(ISC_R_RANGE);
1160                         }
1161                         journal_size = (isc_uint32_t)value;
1162                 }
1163                 if (raw != NULL)
1164                         dns_zone_setjournalsize(raw, journal_size);
1165                 dns_zone_setjournalsize(zone, journal_size);
1166
1167                 obj = NULL;
1168                 result = ns_config_get(maps, "ixfr-from-differences", &obj);
1169                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1170                 if (cfg_obj_isboolean(obj))
1171                         ixfrdiff = cfg_obj_asboolean(obj);
1172                 else if (!strcasecmp(cfg_obj_asstring(obj), "master") &&
1173                          ztype == dns_zone_master)
1174                         ixfrdiff = ISC_TRUE;
1175                 else if (!strcasecmp(cfg_obj_asstring(obj), "slave") &&
1176                         ztype == dns_zone_slave)
1177                         ixfrdiff = ISC_TRUE;
1178                 else
1179                         ixfrdiff = ISC_FALSE;
1180                 if (raw != NULL) {
1181                         dns_zone_setoption(raw, DNS_ZONEOPT_IXFRFROMDIFFS,
1182                                            ISC_TRUE);
1183                         dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1184                                            ISC_TRUE);
1185                 } else
1186                         dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
1187                                            ixfrdiff);
1188
1189                 obj = NULL;
1190                 result = ns_config_get(maps, "request-ixfr", &obj);
1191                 INSIST(result == ISC_R_SUCCESS);
1192                 dns_zone_setrequestixfr(zone, cfg_obj_asboolean(obj));
1193
1194                 checknames(ztype, maps, &obj);
1195                 INSIST(obj != NULL);
1196                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1197                         fail = ISC_FALSE;
1198                         check = ISC_TRUE;
1199                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1200                         fail = check = ISC_TRUE;
1201                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1202                         fail = check = ISC_FALSE;
1203                 } else
1204                         INSIST(0);
1205                 if (raw != NULL) {
1206                         dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMES,
1207                                            check);
1208                         dns_zone_setoption(raw, DNS_ZONEOPT_CHECKNAMESFAIL,
1209                                            fail);
1210                         dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES,
1211                                            ISC_FALSE);
1212                         dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1213                                            ISC_FALSE);
1214                 } else {
1215                         dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES,
1216                                            check);
1217                         dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL,
1218                                            fail);
1219                 }
1220
1221                 obj = NULL;
1222                 result = ns_config_get(maps, "notify-delay", &obj);
1223                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1224                 dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
1225
1226                 obj = NULL;
1227                 result = ns_config_get(maps, "check-sibling", &obj);
1228                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1229                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
1230                                    cfg_obj_asboolean(obj));
1231
1232                 obj = NULL;
1233                 result = ns_config_get(maps, "check-spf", &obj);
1234                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1235                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1236                         check = ISC_TRUE;
1237                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1238                         check = ISC_FALSE;
1239                 } else
1240                         INSIST(0);
1241                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSPF, check);
1242
1243                 obj = NULL;
1244                 result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
1245                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1246                 dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
1247
1248                 obj = NULL;
1249                 result = ns_config_get(maps, "nsec3-test-zone", &obj);
1250                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1251                 dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
1252                                    cfg_obj_asboolean(obj));
1253         } else if (ztype == dns_zone_redirect) {
1254                 dns_zone_setnotifytype(zone, dns_notifytype_no);
1255
1256                 obj = NULL;
1257                 result = ns_config_get(maps, "max-journal-size", &obj);
1258                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1259                 dns_zone_setjournalsize(zone, -1);
1260                 if (cfg_obj_isstring(obj)) {
1261                         const char *str = cfg_obj_asstring(obj);
1262                         INSIST(strcasecmp(str, "unlimited") == 0);
1263                         journal_size = ISC_UINT32_MAX / 2;
1264                 } else {
1265                         isc_resourcevalue_t value;
1266                         value = cfg_obj_asuint64(obj);
1267                         if (value > ISC_UINT32_MAX / 2) {
1268                                 cfg_obj_log(obj, ns_g_lctx,
1269                                             ISC_LOG_ERROR,
1270                                             "'max-journal-size "
1271                                             "%" ISC_PRINT_QUADFORMAT "d' "
1272                                             "is too large",
1273                                             value);
1274                                 RETERR(ISC_R_RANGE);
1275                         }
1276                         journal_size = (isc_uint32_t)value;
1277                 }
1278                 dns_zone_setjournalsize(zone, journal_size);
1279         }
1280
1281         /*
1282          * Configure update-related options.  These apply to
1283          * primary masters only.
1284          */
1285         if (ztype == dns_zone_master) {
1286                 dns_acl_t *updateacl;
1287
1288                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1289                                           allow_update, ac, mayberaw,
1290                                           dns_zone_setupdateacl,
1291                                           dns_zone_clearupdateacl));
1292
1293                 updateacl = dns_zone_getupdateacl(mayberaw);
1294                 if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
1295                         isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
1296                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1297                                       "zone '%s' allows updates by IP "
1298                                       "address, which is insecure",
1299                                       zname);
1300
1301                 RETERR(configure_zone_ssutable(zoptions, mayberaw, zname));
1302         }
1303
1304         if (ztype == dns_zone_master || raw != NULL) {
1305                 isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
1306
1307                 obj = NULL;
1308                 result = ns_config_get(maps, "sig-validity-interval", &obj);
1309                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1310                 {
1311                         const cfg_obj_t *validity, *resign;
1312
1313                         validity = cfg_tuple_get(obj, "validity");
1314                         seconds = cfg_obj_asuint32(validity) * 86400;
1315                         dns_zone_setsigvalidityinterval(zone, seconds);
1316
1317                         resign = cfg_tuple_get(obj, "re-sign");
1318                         if (cfg_obj_isvoid(resign)) {
1319                                 seconds /= 4;
1320                         } else {
1321                                 if (seconds > 7 * 86400)
1322                                         seconds = cfg_obj_asuint32(resign) *
1323                                                         86400;
1324                                 else
1325                                         seconds = cfg_obj_asuint32(resign) *
1326                                                         3600;
1327                         }
1328                         dns_zone_setsigresigninginterval(zone, seconds);
1329                 }
1330
1331                 obj = NULL;
1332                 result = ns_config_get(maps, "key-directory", &obj);
1333                 if (result == ISC_R_SUCCESS) {
1334                         filename = cfg_obj_asstring(obj);
1335                         RETERR(dns_zone_setkeydirectory(zone, filename));
1336                 }
1337
1338                 obj = NULL;
1339                 result = ns_config_get(maps, "sig-signing-signatures", &obj);
1340                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1341                 dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
1342
1343                 obj = NULL;
1344                 result = ns_config_get(maps, "sig-signing-nodes", &obj);
1345                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1346                 dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
1347
1348                 obj = NULL;
1349                 result = ns_config_get(maps, "sig-signing-type", &obj);
1350                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1351                 dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
1352
1353                 obj = NULL;
1354                 result = ns_config_get(maps, "update-check-ksk", &obj);
1355                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1356                 dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
1357                                    cfg_obj_asboolean(obj));
1358
1359                 obj = NULL;
1360                 result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj);
1361                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1362                 dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
1363                                    cfg_obj_asboolean(obj));
1364
1365                 obj = NULL;
1366                 result = ns_config_get(maps, "dnssec-loadkeys-interval", &obj);
1367                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1368                 RETERR(dns_zone_setrefreshkeyinterval(zone,
1369                                                       cfg_obj_asuint32(obj)));
1370
1371                 obj = NULL;
1372                 result = cfg_map_get(zoptions, "auto-dnssec", &obj);
1373                 if (result == ISC_R_SUCCESS) {
1374                         const char *arg = cfg_obj_asstring(obj);
1375                         if (strcasecmp(arg, "allow") == 0)
1376                                 allow = ISC_TRUE;
1377                         else if (strcasecmp(arg, "maintain") == 0)
1378                                 allow = maint = ISC_TRUE;
1379                         else if (strcasecmp(arg, "off") == 0)
1380                                 ;
1381                         else
1382                                 INSIST(0);
1383                         dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
1384                         dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
1385                 }
1386         }
1387
1388         if (ztype == dns_zone_slave) {
1389                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1390                                           allow_update_forwarding, ac,
1391                                           mayberaw, dns_zone_setforwardacl,
1392                                           dns_zone_clearforwardacl));
1393         }
1394
1395         /*%
1396          * Primary master functionality.
1397          */
1398         if (ztype == dns_zone_master) {
1399                 obj = NULL;
1400                 result = ns_config_get(maps, "check-wildcard", &obj);
1401                 if (result == ISC_R_SUCCESS)
1402                         check = cfg_obj_asboolean(obj);
1403                 else
1404                         check = ISC_FALSE;
1405                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKWILDCARD, check);
1406
1407                 obj = NULL;
1408                 result = ns_config_get(maps, "check-dup-records", &obj);
1409                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1410                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1411                         fail = ISC_FALSE;
1412                         check = ISC_TRUE;
1413                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1414                         fail = check = ISC_TRUE;
1415                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1416                         fail = check = ISC_FALSE;
1417                 } else
1418                         INSIST(0);
1419                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRR, check);
1420                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);
1421
1422                 obj = NULL;
1423                 result = ns_config_get(maps, "check-mx", &obj);
1424                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1425                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1426                         fail = ISC_FALSE;
1427                         check = ISC_TRUE;
1428                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1429                         fail = check = ISC_TRUE;
1430                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1431                         fail = check = ISC_FALSE;
1432                 } else
1433                         INSIST(0);
1434                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMX, check);
1435                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKMXFAIL, fail);
1436
1437                 obj = NULL;
1438                 result = ns_config_get(maps, "check-integrity", &obj);
1439                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1440                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_CHECKINTEGRITY,
1441                                    cfg_obj_asboolean(obj));
1442
1443                 obj = NULL;
1444                 result = ns_config_get(maps, "check-mx-cname", &obj);
1445                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1446                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1447                         warn = ISC_TRUE;
1448                         ignore = ISC_FALSE;
1449                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1450                         warn = ignore = ISC_FALSE;
1451                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1452                         warn = ignore = ISC_TRUE;
1453                 } else
1454                         INSIST(0);
1455                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNMXCNAME, warn);
1456                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
1457
1458                 obj = NULL;
1459                 result = ns_config_get(maps, "check-srv-cname", &obj);
1460                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1461                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1462                         warn = ISC_TRUE;
1463                         ignore = ISC_FALSE;
1464                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1465                         warn = ignore = ISC_FALSE;
1466                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1467                         warn = ignore = ISC_TRUE;
1468                 } else
1469                         INSIST(0);
1470                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_WARNSRVCNAME, warn);
1471                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_IGNORESRVCNAME,
1472                                    ignore);
1473
1474                 obj = NULL;
1475                 result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj);
1476                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1477                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_SECURETOINSECURE,
1478                                    cfg_obj_asboolean(obj));
1479
1480                 obj = NULL;
1481                 result = cfg_map_get(zoptions, "dnssec-update-mode", &obj);
1482                 if (result == ISC_R_SUCCESS) {
1483                         const char *arg = cfg_obj_asstring(obj);
1484                         if (strcasecmp(arg, "no-resign") == 0)
1485                                 dns_zone_setkeyopt(zone, DNS_ZONEKEY_NORESIGN,
1486                                                    ISC_TRUE);
1487                         else if (strcasecmp(arg, "maintain") == 0)
1488                                 ;
1489                         else
1490                                 INSIST(0);
1491                 }
1492
1493                 obj = NULL;
1494                 result = ns_config_get(maps, "serial-update-method", &obj);
1495                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1496                 if (strcasecmp(cfg_obj_asstring(obj), "unixtime") == 0)
1497                         dns_zone_setserialupdatemethod(zone,
1498                                                     dns_updatemethod_unixtime);
1499                 else
1500                         dns_zone_setserialupdatemethod(zone,
1501                                                   dns_updatemethod_increment);
1502         }
1503
1504         /*
1505          * Configure slave functionality.
1506          */
1507         switch (ztype) {
1508         case dns_zone_slave:
1509         case dns_zone_stub:
1510         case dns_zone_redirect:
1511                 count = 0;
1512                 obj = NULL;
1513                 (void)cfg_map_get(zoptions, "masters", &obj);
1514                 if (obj != NULL) {
1515                         addrs = NULL;
1516                         keynames = NULL;
1517                         RETERR(ns_config_getipandkeylist(config, obj, mctx,
1518                                                          &addrs, &keynames,
1519                                                          &count));
1520                         result = dns_zone_setmasterswithkeys(mayberaw, addrs,
1521                                                              keynames, count);
1522                         if (count != 0)
1523                                 ns_config_putipandkeylist(mctx, &addrs,
1524                                                           &keynames, count);
1525                         else
1526                                 INSIST(addrs == NULL && keynames == NULL);
1527                 } else
1528                         result = dns_zone_setmasters(mayberaw, NULL, 0);
1529                 RETERR(result);
1530
1531                 multi = ISC_FALSE;
1532                 if (count > 1) {
1533                         obj = NULL;
1534                         result = ns_config_get(maps, "multi-master", &obj);
1535                         INSIST(result == ISC_R_SUCCESS && obj != NULL);
1536                         multi = cfg_obj_asboolean(obj);
1537                 }
1538                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_MULTIMASTER, multi);
1539
1540                 obj = NULL;
1541                 result = ns_config_get(maps, "max-transfer-time-in", &obj);
1542                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1543                 dns_zone_setmaxxfrin(mayberaw, cfg_obj_asuint32(obj) * 60);
1544
1545                 obj = NULL;
1546                 result = ns_config_get(maps, "max-transfer-idle-in", &obj);
1547                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1548                 dns_zone_setidlein(mayberaw, cfg_obj_asuint32(obj) * 60);
1549
1550                 obj = NULL;
1551                 result = ns_config_get(maps, "max-refresh-time", &obj);
1552                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1553                 dns_zone_setmaxrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1554
1555                 obj = NULL;
1556                 result = ns_config_get(maps, "min-refresh-time", &obj);
1557                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1558                 dns_zone_setminrefreshtime(mayberaw, cfg_obj_asuint32(obj));
1559
1560                 obj = NULL;
1561                 result = ns_config_get(maps, "max-retry-time", &obj);
1562                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1563                 dns_zone_setmaxretrytime(mayberaw, cfg_obj_asuint32(obj));
1564
1565                 obj = NULL;
1566                 result = ns_config_get(maps, "min-retry-time", &obj);
1567                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1568                 dns_zone_setminretrytime(mayberaw, cfg_obj_asuint32(obj));
1569
1570                 obj = NULL;
1571                 result = ns_config_get(maps, "transfer-source", &obj);
1572                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1573                 RETERR(dns_zone_setxfrsource4(mayberaw,
1574                                               cfg_obj_assockaddr(obj)));
1575                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1576
1577                 obj = NULL;
1578                 result = ns_config_get(maps, "transfer-source-v6", &obj);
1579                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1580                 RETERR(dns_zone_setxfrsource6(mayberaw,
1581                                               cfg_obj_assockaddr(obj)));
1582                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1583
1584                 obj = NULL;
1585                 result = ns_config_get(maps, "alt-transfer-source", &obj);
1586                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1587                 RETERR(dns_zone_setaltxfrsource4(mayberaw,
1588                                                  cfg_obj_assockaddr(obj)));
1589
1590                 obj = NULL;
1591                 result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
1592                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1593                 RETERR(dns_zone_setaltxfrsource6(mayberaw,
1594                                                  cfg_obj_assockaddr(obj)));
1595
1596                 obj = NULL;
1597                 (void)ns_config_get(maps, "use-alt-transfer-source", &obj);
1598                 if (obj == NULL) {
1599                         /*
1600                          * Default off when views are in use otherwise
1601                          * on for BIND 8 compatibility.
1602                          */
1603                         view = dns_zone_getview(zone);
1604                         if (view != NULL && strcmp(view->name, "_default") == 0)
1605                                 alt = ISC_TRUE;
1606                         else
1607                                 alt = ISC_FALSE;
1608                 } else
1609                         alt = cfg_obj_asboolean(obj);
1610                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_USEALTXFRSRC, alt);
1611
1612                 obj = NULL;
1613                 (void)ns_config_get(maps, "try-tcp-refresh", &obj);
1614                 dns_zone_setoption(mayberaw, DNS_ZONEOPT_TRYTCPREFRESH,
1615                                    cfg_obj_asboolean(obj));
1616                 break;
1617
1618         case dns_zone_staticstub:
1619                 RETERR(configure_staticstub(zoptions, zone, zname,
1620                                             default_dbtype));
1621                 break;
1622
1623         default:
1624                 break;
1625         }
1626
1627         return (ISC_R_SUCCESS);
1628 }
1629
1630
1631 /*
1632  * Set up a DLZ zone as writeable
1633  */
1634 isc_result_t
1635 ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
1636                                 dns_rdataclass_t rdclass, dns_name_t *name)
1637 {
1638         dns_db_t *db = NULL;
1639         isc_time_t now;
1640         isc_result_t result;
1641
1642         TIME_NOW(&now);
1643
1644         dns_zone_settype(zone, dns_zone_dlz);
1645         result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db);
1646         if (result != ISC_R_SUCCESS)
1647                 return (result);
1648         result = dns_zone_dlzpostload(zone, db);
1649         dns_db_detach(&db);
1650         return (result);
1651 }
1652
1653 isc_boolean_t
1654 ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
1655         const cfg_obj_t *zoptions = NULL;
1656         const cfg_obj_t *obj = NULL;
1657         const char *cfilename;
1658         const char *zfilename;
1659         dns_zone_t *raw = NULL;
1660         isc_boolean_t has_raw;
1661         dns_zonetype_t ztype;
1662
1663         zoptions = cfg_tuple_get(zconfig, "options");
1664
1665         /*
1666          * We always reconfigure a static-stub zone for simplicity, assuming
1667          * the amount of data to be loaded is small.
1668          */
1669         if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
1670                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1671                              "not reusable: staticstub");
1672                 return (ISC_FALSE);
1673         }
1674
1675         /* If there's a raw zone, use that for filename and type comparison */
1676         dns_zone_getraw(zone, &raw);
1677         if (raw != NULL) {
1678                 zfilename = dns_zone_getfile(raw);
1679                 ztype = dns_zone_gettype(raw);
1680                 dns_zone_detach(&raw);
1681                 has_raw = ISC_TRUE;
1682         } else {
1683                 zfilename = dns_zone_getfile(zone);
1684                 ztype = dns_zone_gettype(zone);
1685                 has_raw = ISC_FALSE;
1686         }
1687
1688         obj = NULL;
1689         (void)cfg_map_get(zoptions, "inline-signing", &obj);
1690         if ((obj == NULL || !cfg_obj_asboolean(obj)) && has_raw) {
1691                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1692                              "not reusable: old zone was inline-signing");
1693                 return (ISC_FALSE);
1694         } else if ((obj != NULL && cfg_obj_asboolean(obj)) && !has_raw) {
1695                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1696                              "not reusable: old zone was not inline-signing");
1697                 return (ISC_FALSE);
1698         }
1699
1700         if (zonetype_fromconfig(zoptions) != ztype) {
1701                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1702                              "not reusable: type mismatch");
1703                 return (ISC_FALSE);
1704         }
1705
1706         obj = NULL;
1707         (void)cfg_map_get(zoptions, "file", &obj);
1708         if (obj != NULL)
1709                 cfilename = cfg_obj_asstring(obj);
1710         else
1711                 cfilename = NULL;
1712         if (!((cfilename == NULL && zfilename == NULL) ||
1713               (cfilename != NULL && zfilename != NULL &&
1714                strcmp(cfilename, zfilename) == 0)))
1715         {
1716                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1717                              "not reusable: filename mismatch");
1718                 return (ISC_FALSE);
1719         }
1720
1721         return (ISC_TRUE);
1722 }