]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/bin/named/zoneconf.c
MFC: r253983-253984
[FreeBSD/stable/8.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: zoneconf.c,v 1.170.14.7 2012/01/31 23:46:39 tbox Exp $ */
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)
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         isc_boolean_t zonestats_on;
828         int seconds;
829
830         i = 0;
831         if (zconfig != NULL) {
832                 zoptions = cfg_tuple_get(zconfig, "options");
833                 maps[i++] = zoptions;
834         }
835         if (vconfig != NULL)
836                 maps[i++] = cfg_tuple_get(vconfig, "options");
837         if (config != NULL) {
838                 (void)cfg_map_get(config, "options", &options);
839                 if (options != NULL)
840                         maps[i++] = options;
841         }
842         maps[i++] = ns_g_defaults;
843         maps[i] = NULL;
844
845         if (vconfig != NULL)
846                 RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
847                                           dns_rdataclass_in, &vclass));
848         else
849                 vclass = dns_rdataclass_in;
850
851         /*
852          * Configure values common to all zone types.
853          */
854
855         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
856
857         RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
858                                   vclass, &zclass));
859         dns_zone_setclass(zone, zclass);
860
861         ztype = zonetype_fromconfig(zoptions);
862         dns_zone_settype(zone, ztype);
863
864         obj = NULL;
865         result = cfg_map_get(zoptions, "database", &obj);
866         if (result == ISC_R_SUCCESS)
867                 cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
868         else
869                 cpval = default_dbtype;
870
871         if (cpval == NULL)
872                 return(ISC_R_NOMEMORY);
873
874         result = strtoargv(mctx, cpval, &dbargc, &dbargv);
875         if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
876                 isc_mem_free(mctx, cpval);
877                 return (result);
878         }
879
880         /*
881          * ANSI C is strange here.  There is no logical reason why (char **)
882          * cannot be promoted automatically to (const char * const *) by the
883          * compiler w/o generating a warning.
884          */
885         result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
886         isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
887         if (cpval != default_dbtype)
888                 isc_mem_free(mctx, cpval);
889         if (result != ISC_R_SUCCESS)
890                 return (result);
891
892         obj = NULL;
893         result = cfg_map_get(zoptions, "file", &obj);
894         if (result == ISC_R_SUCCESS)
895                 filename = cfg_obj_asstring(obj);
896
897         /*
898          * Unless we're using some alternative database, a master zone
899          * will be needing a master file.
900          */
901         if (ztype == dns_zone_master && cpval == default_dbtype &&
902             filename == NULL) {
903                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
904                               NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
905                               "zone '%s': 'file' not specified",
906                               zname);
907                 return (ISC_R_FAILURE);
908         }
909
910         masterformat = dns_masterformat_text;
911         obj = NULL;
912         result= ns_config_get(maps, "masterfile-format", &obj);
913         if (result == ISC_R_SUCCESS) {
914                 const char *masterformatstr = cfg_obj_asstring(obj);
915
916                 if (strcasecmp(masterformatstr, "text") == 0)
917                         masterformat = dns_masterformat_text;
918                 else if (strcasecmp(masterformatstr, "raw") == 0)
919                         masterformat = dns_masterformat_raw;
920                 else
921                         INSIST(0);
922         }
923         RETERR(dns_zone_setfile2(zone, filename, masterformat));
924
925         obj = NULL;
926         result = cfg_map_get(zoptions, "journal", &obj);
927         if (result == ISC_R_SUCCESS)
928                 RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj)));
929
930         if (ztype == dns_zone_slave)
931                 RETERR(configure_zone_acl(zconfig, vconfig, config,
932                                           allow_notify, ac, zone,
933                                           dns_zone_setnotifyacl,
934                                           dns_zone_clearnotifyacl));
935         /*
936          * XXXAG This probably does not make sense for stubs.
937          */
938         RETERR(configure_zone_acl(zconfig, vconfig, config,
939                                   allow_query, ac, zone,
940                                   dns_zone_setqueryacl,
941                                   dns_zone_clearqueryacl));
942
943         RETERR(configure_zone_acl(zconfig, vconfig, config,
944                                   allow_query_on, ac, zone,
945                                   dns_zone_setqueryonacl,
946                                   dns_zone_clearqueryonacl));
947
948         obj = NULL;
949         result = ns_config_get(maps, "dialup", &obj);
950         INSIST(result == ISC_R_SUCCESS && obj != NULL);
951         if (cfg_obj_isboolean(obj)) {
952                 if (cfg_obj_asboolean(obj))
953                         dialup = dns_dialuptype_yes;
954                 else
955                         dialup = dns_dialuptype_no;
956         } else {
957                 const char *dialupstr = cfg_obj_asstring(obj);
958                 if (strcasecmp(dialupstr, "notify") == 0)
959                         dialup = dns_dialuptype_notify;
960                 else if (strcasecmp(dialupstr, "notify-passive") == 0)
961                         dialup = dns_dialuptype_notifypassive;
962                 else if (strcasecmp(dialupstr, "refresh") == 0)
963                         dialup = dns_dialuptype_refresh;
964                 else if (strcasecmp(dialupstr, "passive") == 0)
965                         dialup = dns_dialuptype_passive;
966                 else
967                         INSIST(0);
968         }
969         dns_zone_setdialup(zone, dialup);
970
971         obj = NULL;
972         result = ns_config_get(maps, "zone-statistics", &obj);
973         INSIST(result == ISC_R_SUCCESS && obj != NULL);
974         zonestats_on = cfg_obj_asboolean(obj);
975         zoneqrystats = NULL;
976         if (zonestats_on) {
977                 RETERR(isc_stats_create(mctx, &zoneqrystats,
978                                         dns_nsstatscounter_max));
979         }
980         dns_zone_setrequeststats(zone, zoneqrystats);
981         if (zoneqrystats != NULL)
982                 isc_stats_detach(&zoneqrystats);
983
984         /*
985          * Configure master functionality.  This applies
986          * to primary masters (type "master") and slaves
987          * acting as masters (type "slave"), but not to stubs.
988          */
989         if (ztype != dns_zone_stub && ztype != dns_zone_staticstub) {
990                 obj = NULL;
991                 result = ns_config_get(maps, "notify", &obj);
992                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
993                 if (cfg_obj_isboolean(obj)) {
994                         if (cfg_obj_asboolean(obj))
995                                 notifytype = dns_notifytype_yes;
996                         else
997                                 notifytype = dns_notifytype_no;
998                 } else {
999                         const char *notifystr = cfg_obj_asstring(obj);
1000                         if (strcasecmp(notifystr, "explicit") == 0)
1001                                 notifytype = dns_notifytype_explicit;
1002                         else if (strcasecmp(notifystr, "master-only") == 0)
1003                                 notifytype = dns_notifytype_masteronly;
1004                         else
1005                                 INSIST(0);
1006                 }
1007                 dns_zone_setnotifytype(zone, notifytype);
1008
1009                 obj = NULL;
1010                 result = ns_config_get(maps, "also-notify", &obj);
1011                 if (result == ISC_R_SUCCESS) {
1012                         isc_sockaddr_t *addrs = NULL;
1013                         isc_uint32_t addrcount;
1014                         result = ns_config_getiplist(config, obj, 0, mctx,
1015                                                      &addrs, &addrcount);
1016                         if (result != ISC_R_SUCCESS)
1017                                 return (result);
1018                         result = dns_zone_setalsonotify(zone, addrs,
1019                                                         addrcount);
1020                         ns_config_putiplist(mctx, &addrs, addrcount);
1021                         if (result != ISC_R_SUCCESS)
1022                                 return (result);
1023                 } else
1024                         RETERR(dns_zone_setalsonotify(zone, NULL, 0));
1025
1026                 obj = NULL;
1027                 result = ns_config_get(maps, "notify-source", &obj);
1028                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1029                 RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
1030                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1031
1032                 obj = NULL;
1033                 result = ns_config_get(maps, "notify-source-v6", &obj);
1034                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1035                 RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
1036                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1037
1038                 obj = NULL;
1039                 result = ns_config_get(maps, "notify-to-soa", &obj);
1040                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1041                 dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
1042                                    cfg_obj_asboolean(obj));
1043
1044                 dns_zone_setisself(zone, ns_client_isself, NULL);
1045
1046                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1047                                           allow_transfer, ac, zone,
1048                                           dns_zone_setxfracl,
1049                                           dns_zone_clearxfracl));
1050
1051                 obj = NULL;
1052                 result = ns_config_get(maps, "max-transfer-time-out", &obj);
1053                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1054                 dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
1055
1056                 obj = NULL;
1057                 result = ns_config_get(maps, "max-transfer-idle-out", &obj);
1058                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1059                 dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
1060
1061                 obj = NULL;
1062                 result =  ns_config_get(maps, "max-journal-size", &obj);
1063                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1064                 dns_zone_setjournalsize(zone, -1);
1065                 if (cfg_obj_isstring(obj)) {
1066                         const char *str = cfg_obj_asstring(obj);
1067                         INSIST(strcasecmp(str, "unlimited") == 0);
1068                         journal_size = ISC_UINT32_MAX / 2;
1069                 } else {
1070                         isc_resourcevalue_t value;
1071                         value = cfg_obj_asuint64(obj);
1072                         if (value > ISC_UINT32_MAX / 2) {
1073                                 cfg_obj_log(obj, ns_g_lctx,
1074                                             ISC_LOG_ERROR,
1075                                             "'max-journal-size "
1076                                             "%" ISC_PRINT_QUADFORMAT "d' "
1077                                             "is too large",
1078                                             value);
1079                                 RETERR(ISC_R_RANGE);
1080                         }
1081                         journal_size = (isc_uint32_t)value;
1082                 }
1083                 dns_zone_setjournalsize(zone, journal_size);
1084
1085                 obj = NULL;
1086                 result = ns_config_get(maps, "ixfr-from-differences", &obj);
1087                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1088                 if (cfg_obj_isboolean(obj))
1089                         ixfrdiff = cfg_obj_asboolean(obj);
1090                 else if (!strcasecmp(cfg_obj_asstring(obj), "master") &&
1091                          ztype == dns_zone_master)
1092                         ixfrdiff = ISC_TRUE;
1093                 else if (!strcasecmp(cfg_obj_asstring(obj), "slave") &&
1094                         ztype == dns_zone_slave)
1095                         ixfrdiff = ISC_TRUE;
1096                 else
1097                         ixfrdiff = ISC_FALSE;
1098                 dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff);
1099
1100                 checknames(ztype, maps, &obj);
1101                 INSIST(obj != NULL);
1102                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1103                         fail = ISC_FALSE;
1104                         check = ISC_TRUE;
1105                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1106                         fail = check = ISC_TRUE;
1107                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1108                         fail = check = ISC_FALSE;
1109                 } else
1110                         INSIST(0);
1111                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
1112                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);
1113
1114                 obj = NULL;
1115                 result = ns_config_get(maps, "notify-delay", &obj);
1116                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1117                 dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
1118
1119                 obj = NULL;
1120                 result = ns_config_get(maps, "check-sibling", &obj);
1121                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1122                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
1123                                    cfg_obj_asboolean(obj));
1124
1125                 obj = NULL;
1126                 result = ns_config_get(maps, "check-spf", &obj);
1127                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1128                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1129                         check = ISC_TRUE;
1130                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1131                         check = ISC_FALSE;
1132                 } else
1133                         INSIST(0);
1134                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSPF, check);
1135
1136                 obj = NULL;
1137                 result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
1138                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1139                 dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
1140
1141                 obj = NULL;
1142                 result = ns_config_get(maps, "nsec3-test-zone", &obj);
1143                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1144                 dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
1145                                    cfg_obj_asboolean(obj));
1146         }
1147
1148         /*
1149          * Configure update-related options.  These apply to
1150          * primary masters only.
1151          */
1152         if (ztype == dns_zone_master) {
1153                 dns_acl_t *updateacl;
1154
1155                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1156                                           allow_update, ac, zone,
1157                                           dns_zone_setupdateacl,
1158                                           dns_zone_clearupdateacl));
1159
1160                 updateacl = dns_zone_getupdateacl(zone);
1161                 if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
1162                         isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
1163                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
1164                                       "zone '%s' allows updates by IP "
1165                                       "address, which is insecure",
1166                                       zname);
1167
1168                 RETERR(configure_zone_ssutable(zoptions, zone, zname));
1169
1170                 obj = NULL;
1171                 result = ns_config_get(maps, "sig-validity-interval", &obj);
1172                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1173                 {
1174                         const cfg_obj_t *validity, *resign;
1175
1176                         validity = cfg_tuple_get(obj, "validity");
1177                         seconds = cfg_obj_asuint32(validity) * 86400;
1178                         dns_zone_setsigvalidityinterval(zone, seconds);
1179
1180                         resign = cfg_tuple_get(obj, "re-sign");
1181                         if (cfg_obj_isvoid(resign)) {
1182                                 seconds /= 4;
1183                         } else {
1184                                 if (seconds > 7 * 86400)
1185                                         seconds = cfg_obj_asuint32(resign) *
1186                                                         86400;
1187                                 else
1188                                         seconds = cfg_obj_asuint32(resign) *
1189                                                         3600;
1190                         }
1191                         dns_zone_setsigresigninginterval(zone, seconds);
1192                 }
1193
1194                 obj = NULL;
1195                 result = ns_config_get(maps, "key-directory", &obj);
1196                 if (result == ISC_R_SUCCESS) {
1197                         filename = cfg_obj_asstring(obj);
1198                         RETERR(dns_zone_setkeydirectory(zone, filename));
1199                 }
1200
1201                 obj = NULL;
1202                 result = ns_config_get(maps, "sig-signing-signatures", &obj);
1203                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1204                 dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
1205
1206                 obj = NULL;
1207                 result = ns_config_get(maps, "sig-signing-nodes", &obj);
1208                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1209                 dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
1210
1211                 obj = NULL;
1212                 result = ns_config_get(maps, "sig-signing-type", &obj);
1213                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1214                 dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
1215
1216                 obj = NULL;
1217                 result = ns_config_get(maps, "update-check-ksk", &obj);
1218                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1219                 dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
1220                                    cfg_obj_asboolean(obj));
1221
1222                 obj = NULL;
1223                 result = ns_config_get(maps, "dnssec-dnskey-kskonly", &obj);
1224                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1225                 dns_zone_setoption(zone, DNS_ZONEOPT_DNSKEYKSKONLY,
1226                                    cfg_obj_asboolean(obj));
1227         } else if (ztype == dns_zone_slave) {
1228                 RETERR(configure_zone_acl(zconfig, vconfig, config,
1229                                           allow_update_forwarding, ac, zone,
1230                                           dns_zone_setforwardacl,
1231                                           dns_zone_clearforwardacl));
1232         }
1233
1234         /*%
1235          * Primary master functionality.
1236          */
1237         if (ztype == dns_zone_master) {
1238                 isc_boolean_t allow = ISC_FALSE, maint = ISC_FALSE;
1239
1240                 obj = NULL;
1241                 result = ns_config_get(maps, "check-wildcard", &obj);
1242                 if (result == ISC_R_SUCCESS)
1243                         check = cfg_obj_asboolean(obj);
1244                 else
1245                         check = ISC_FALSE;
1246                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);
1247
1248                 obj = NULL;
1249                 result = ns_config_get(maps, "check-dup-records", &obj);
1250                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1251                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1252                         fail = ISC_FALSE;
1253                         check = ISC_TRUE;
1254                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1255                         fail = check = ISC_TRUE;
1256                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1257                         fail = check = ISC_FALSE;
1258                 } else
1259                         INSIST(0);
1260                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRR, check);
1261                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKDUPRRFAIL, fail);
1262
1263                 obj = NULL;
1264                 result = ns_config_get(maps, "check-mx", &obj);
1265                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1266                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1267                         fail = ISC_FALSE;
1268                         check = ISC_TRUE;
1269                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1270                         fail = check = ISC_TRUE;
1271                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1272                         fail = check = ISC_FALSE;
1273                 } else
1274                         INSIST(0);
1275                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check);
1276                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail);
1277
1278                 obj = NULL;
1279                 result = ns_config_get(maps, "check-integrity", &obj);
1280                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1281                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY,
1282                                    cfg_obj_asboolean(obj));
1283
1284                 obj = NULL;
1285                 result = ns_config_get(maps, "check-mx-cname", &obj);
1286                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1287                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1288                         warn = ISC_TRUE;
1289                         ignore = ISC_FALSE;
1290                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1291                         warn = ignore = ISC_FALSE;
1292                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1293                         warn = ignore = ISC_TRUE;
1294                 } else
1295                         INSIST(0);
1296                 dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn);
1297                 dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
1298
1299                 obj = NULL;
1300                 result = ns_config_get(maps, "check-srv-cname", &obj);
1301                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1302                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
1303                         warn = ISC_TRUE;
1304                         ignore = ISC_FALSE;
1305                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
1306                         warn = ignore = ISC_FALSE;
1307                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
1308                         warn = ignore = ISC_TRUE;
1309                 } else
1310                         INSIST(0);
1311                 dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn);
1312                 dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore);
1313
1314                 obj = NULL;
1315                 result = ns_config_get(maps, "dnssec-secure-to-insecure", &obj);
1316                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1317                 dns_zone_setoption(zone, DNS_ZONEOPT_SECURETOINSECURE,
1318                                    cfg_obj_asboolean(obj));
1319
1320                 obj = NULL;
1321                 result = cfg_map_get(zoptions, "auto-dnssec", &obj);
1322                 if (result == ISC_R_SUCCESS) {
1323                         const char *arg = cfg_obj_asstring(obj);
1324                         if (strcasecmp(arg, "allow") == 0)
1325                                 allow = ISC_TRUE;
1326                         else if (strcasecmp(arg, "maintain") == 0)
1327                                 allow = maint = ISC_TRUE;
1328                         else if (strcasecmp(arg, "off") == 0)
1329                                 ;
1330                         else
1331                                 INSIST(0);
1332                         dns_zone_setkeyopt(zone, DNS_ZONEKEY_ALLOW, allow);
1333                         dns_zone_setkeyopt(zone, DNS_ZONEKEY_MAINTAIN, maint);
1334                 }
1335         }
1336
1337         /*
1338          * Configure slave functionality.
1339          */
1340         switch (ztype) {
1341         case dns_zone_slave:
1342         case dns_zone_stub:
1343                 count = 0;
1344                 obj = NULL;
1345                 (void)cfg_map_get(zoptions, "masters", &obj);
1346                 if (obj != NULL) {
1347                         addrs = NULL;
1348                         keynames = NULL;
1349                         RETERR(ns_config_getipandkeylist(config, obj, mctx,
1350                                                          &addrs, &keynames,
1351                                                          &count));
1352                         result = dns_zone_setmasterswithkeys(zone, addrs,
1353                                                              keynames, count);
1354                         if (count != 0)
1355                                 ns_config_putipandkeylist(mctx, &addrs,
1356                                                           &keynames, count);
1357                         else
1358                                 INSIST(addrs == NULL && keynames == NULL);
1359                 } else
1360                         result = dns_zone_setmasters(zone, NULL, 0);
1361                 RETERR(result);
1362
1363                 multi = ISC_FALSE;
1364                 if (count > 1) {
1365                         obj = NULL;
1366                         result = ns_config_get(maps, "multi-master", &obj);
1367                         INSIST(result == ISC_R_SUCCESS && obj != NULL);
1368                         multi = cfg_obj_asboolean(obj);
1369                 }
1370                 dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);
1371
1372                 obj = NULL;
1373                 result = ns_config_get(maps, "max-transfer-time-in", &obj);
1374                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1375                 dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
1376
1377                 obj = NULL;
1378                 result = ns_config_get(maps, "max-transfer-idle-in", &obj);
1379                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1380                 dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
1381
1382                 obj = NULL;
1383                 result = ns_config_get(maps, "max-refresh-time", &obj);
1384                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1385                 dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
1386
1387                 obj = NULL;
1388                 result = ns_config_get(maps, "min-refresh-time", &obj);
1389                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1390                 dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
1391
1392                 obj = NULL;
1393                 result = ns_config_get(maps, "max-retry-time", &obj);
1394                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1395                 dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
1396
1397                 obj = NULL;
1398                 result = ns_config_get(maps, "min-retry-time", &obj);
1399                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1400                 dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
1401
1402                 obj = NULL;
1403                 result = ns_config_get(maps, "transfer-source", &obj);
1404                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1405                 RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
1406                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1407
1408                 obj = NULL;
1409                 result = ns_config_get(maps, "transfer-source-v6", &obj);
1410                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1411                 RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
1412                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
1413
1414                 obj = NULL;
1415                 result = ns_config_get(maps, "alt-transfer-source", &obj);
1416                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1417                 RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));
1418
1419                 obj = NULL;
1420                 result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
1421                 INSIST(result == ISC_R_SUCCESS && obj != NULL);
1422                 RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));
1423
1424                 obj = NULL;
1425                 (void)ns_config_get(maps, "use-alt-transfer-source", &obj);
1426                 if (obj == NULL) {
1427                         /*
1428                          * Default off when views are in use otherwise
1429                          * on for BIND 8 compatibility.
1430                          */
1431                         view = dns_zone_getview(zone);
1432                         if (view != NULL && strcmp(view->name, "_default") == 0)
1433                                 alt = ISC_TRUE;
1434                         else
1435                                 alt = ISC_FALSE;
1436                 } else
1437                         alt = cfg_obj_asboolean(obj);
1438                 dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);
1439
1440                 obj = NULL;
1441                 (void)ns_config_get(maps, "try-tcp-refresh", &obj);
1442                 dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH,
1443                                    cfg_obj_asboolean(obj));
1444                 break;
1445
1446         case dns_zone_staticstub:
1447                 RETERR(configure_staticstub(zoptions, zone, zname,
1448                                             default_dbtype));
1449                 break;
1450
1451         default:
1452                 break;
1453         }
1454
1455         return (ISC_R_SUCCESS);
1456 }
1457
1458
1459 /*
1460  * Set up a DLZ zone as writeable
1461  */
1462 isc_result_t
1463 ns_zone_configure_writeable_dlz(dns_dlzdb_t *dlzdatabase, dns_zone_t *zone,
1464                                 dns_rdataclass_t rdclass, dns_name_t *name)
1465 {
1466         dns_db_t *db = NULL;
1467         isc_time_t now;
1468         isc_result_t result;
1469
1470         TIME_NOW(&now);
1471
1472         dns_zone_settype(zone, dns_zone_dlz);
1473         result = dns_sdlz_setdb(dlzdatabase, rdclass, name, &db);
1474         if (result != ISC_R_SUCCESS)
1475                 return result;
1476         result = dns_zone_dlzpostload(zone, db);
1477         dns_db_detach(&db);
1478         return result;
1479 }
1480
1481 isc_boolean_t
1482 ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
1483         const cfg_obj_t *zoptions = NULL;
1484         const cfg_obj_t *obj = NULL;
1485         const char *cfilename;
1486         const char *zfilename;
1487
1488         zoptions = cfg_tuple_get(zconfig, "options");
1489
1490         if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone)) {
1491                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1492                              "not reusable: type mismatch");
1493                 return (ISC_FALSE);
1494         }
1495
1496         /*
1497          * We always reconfigure a static-stub zone for simplicity, assuming
1498          * the amount of data to be loaded is small.
1499          */
1500         if (zonetype_fromconfig(zoptions) == dns_zone_staticstub) {
1501                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1502                              "not reusable: staticstub");
1503                 return (ISC_FALSE);
1504         }
1505
1506         obj = NULL;
1507         (void)cfg_map_get(zoptions, "file", &obj);
1508         if (obj != NULL)
1509                 cfilename = cfg_obj_asstring(obj);
1510         else
1511                 cfilename = NULL;
1512         zfilename = dns_zone_getfile(zone);
1513         if (!((cfilename == NULL && zfilename == NULL) ||
1514               (cfilename != NULL && zfilename != NULL &&
1515                strcmp(cfilename, zfilename) == 0))) {
1516                 dns_zone_log(zone, ISC_LOG_DEBUG(1),
1517                         "not reusable: filename mismatch");
1518                 return (ISC_FALSE);
1519         }
1520
1521         return (ISC_TRUE);
1522 }