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