Merge from vendor branch LESS:
[dragonfly.git] / contrib / bind-9.3 / bin / named / zoneconf.c
1 /*
2  * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: zoneconf.c,v 1.87.2.4.10.15 2005/09/06 02:12:39 marka Exp $ */
19
20 #include <config.h>
21
22 #include <isc/buffer.h>
23 #include <isc/file.h>
24 #include <isc/mem.h>
25 #include <isc/print.h>
26 #include <isc/string.h>         /* Required for HP/UX (and others?) */
27 #include <isc/util.h>
28
29 #include <dns/acl.h>
30 #include <dns/fixedname.h>
31 #include <dns/log.h>
32 #include <dns/name.h>
33 #include <dns/rdatatype.h>
34 #include <dns/ssu.h>
35 #include <dns/view.h>
36 #include <dns/zone.h>
37
38 #include <named/config.h>
39 #include <named/globals.h>
40 #include <named/log.h>
41 #include <named/server.h>
42 #include <named/zoneconf.h>
43
44 /*
45  * These are BIND9 server defaults, not necessarily identical to the
46  * library defaults defined in zone.c.
47  */
48 #define RETERR(x) do { \
49         isc_result_t _r = (x); \
50         if (_r != ISC_R_SUCCESS) \
51                 return (_r); \
52         } while (0)
53
54 /*
55  * Convenience function for configuring a single zone ACL.
56  */
57 static isc_result_t
58 configure_zone_acl(cfg_obj_t *zconfig, cfg_obj_t *vconfig, cfg_obj_t *config,
59                    const char *aclname, ns_aclconfctx_t *actx,
60                    dns_zone_t *zone, 
61                    void (*setzacl)(dns_zone_t *, dns_acl_t *),
62                    void (*clearzacl)(dns_zone_t *))
63 {
64         isc_result_t result;
65         cfg_obj_t *maps[4];
66         cfg_obj_t *aclobj = NULL;
67         int i = 0;
68         dns_acl_t *dacl = NULL;
69
70         if (zconfig != NULL)
71                 maps[i++] = cfg_tuple_get(zconfig, "options");
72         if (vconfig != NULL)
73                 maps[i++] = cfg_tuple_get(vconfig, "options");
74         if (config != NULL) {
75                 cfg_obj_t *options = NULL;
76                 (void)cfg_map_get(config, "options", &options);
77                 if (options != NULL)
78                         maps[i++] = options;
79         }
80         maps[i] = NULL;
81
82         result = ns_config_get(maps, aclname, &aclobj);
83         if (aclobj == NULL) {
84                 (*clearzacl)(zone);
85                 return (ISC_R_SUCCESS);
86         }
87
88         result = ns_acl_fromconfig(aclobj, config, actx,
89                                    dns_zone_getmctx(zone), &dacl);
90         if (result != ISC_R_SUCCESS)
91                 return (result);
92         (*setzacl)(zone, dacl);
93         dns_acl_detach(&dacl);
94         return (ISC_R_SUCCESS);
95 }
96
97 /*
98  * Parse the zone update-policy statement.
99  */
100 static isc_result_t
101 configure_zone_ssutable(cfg_obj_t *zconfig, dns_zone_t *zone) {
102         cfg_obj_t *updatepolicy = NULL;
103         cfg_listelt_t *element, *element2;
104         dns_ssutable_t *table = NULL;
105         isc_mem_t *mctx = dns_zone_getmctx(zone);
106         isc_result_t result;
107
108         (void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
109         if (updatepolicy == NULL)
110                 return (ISC_R_SUCCESS);
111
112         result = dns_ssutable_create(mctx, &table);
113         if (result != ISC_R_SUCCESS)
114                 return (result);
115
116         for (element = cfg_list_first(updatepolicy);
117              element != NULL;
118              element = cfg_list_next(element))
119         {
120                 cfg_obj_t *stmt = cfg_listelt_value(element);
121                 cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
122                 cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
123                 cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
124                 cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
125                 cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
126                 char *str;
127                 isc_boolean_t grant = ISC_FALSE;
128                 unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
129                 dns_fixedname_t fname, fident;
130                 isc_buffer_t b;
131                 dns_rdatatype_t *types;
132                 unsigned int i, n;
133
134                 str = cfg_obj_asstring(mode);
135                 if (strcasecmp(str, "grant") == 0)
136                         grant = ISC_TRUE;
137                 else if (strcasecmp(str, "deny") == 0)
138                         grant = ISC_FALSE;
139                 else
140                         INSIST(0);
141
142                 str = cfg_obj_asstring(matchtype);
143                 if (strcasecmp(str, "name") == 0)
144                         mtype = DNS_SSUMATCHTYPE_NAME;
145                 else if (strcasecmp(str, "subdomain") == 0)
146                         mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
147                 else if (strcasecmp(str, "wildcard") == 0)
148                         mtype = DNS_SSUMATCHTYPE_WILDCARD;
149                 else if (strcasecmp(str, "self") == 0)
150                         mtype = DNS_SSUMATCHTYPE_SELF;
151                 else
152                         INSIST(0);
153
154                 dns_fixedname_init(&fident);
155                 str = cfg_obj_asstring(identity);
156                 isc_buffer_init(&b, str, strlen(str));
157                 isc_buffer_add(&b, strlen(str));
158                 result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
159                                            dns_rootname, ISC_FALSE, NULL);
160                 if (result != ISC_R_SUCCESS) {
161                         cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
162                                     "'%s' is not a valid name", str);
163                         goto cleanup;
164                 }
165
166                 dns_fixedname_init(&fname);
167                 str = cfg_obj_asstring(dname);
168                 isc_buffer_init(&b, str, strlen(str));
169                 isc_buffer_add(&b, strlen(str));
170                 result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
171                                            dns_rootname, ISC_FALSE, NULL);
172                 if (result != ISC_R_SUCCESS) {
173                         cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
174                                     "'%s' is not a valid name", str);
175                         goto cleanup;
176                 }
177
178                 n = ns_config_listcount(typelist);
179                 if (n == 0)
180                         types = NULL;
181                 else {
182                         types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
183                         if (types == NULL) {
184                                 result = ISC_R_NOMEMORY;
185                                 goto cleanup;
186                         }
187                 }
188
189                 i = 0;
190                 for (element2 = cfg_list_first(typelist);
191                      element2 != NULL;
192                      element2 = cfg_list_next(element2))
193                 {
194                         cfg_obj_t *typeobj;
195                         isc_textregion_t r;
196
197                         INSIST(i < n);
198
199                         typeobj = cfg_listelt_value(element2);
200                         str = cfg_obj_asstring(typeobj);
201                         r.base = str;
202                         r.length = strlen(str);
203
204                         result = dns_rdatatype_fromtext(&types[i++], &r);
205                         if (result != ISC_R_SUCCESS) {
206                                 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
207                                             "'%s' is not a valid type", str);
208                                 isc_mem_put(mctx, types,
209                                             n * sizeof(dns_rdatatype_t));
210                                 goto cleanup;
211                         }
212                 }
213                 INSIST(i == n);
214
215                 result = dns_ssutable_addrule(table, grant,
216                                               dns_fixedname_name(&fident),
217                                               mtype,
218                                               dns_fixedname_name(&fname),
219                                               n, types);
220                 if (types != NULL)
221                         isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
222                 if (result != ISC_R_SUCCESS) {
223                         goto cleanup;
224                 }
225
226         }
227
228         result = ISC_R_SUCCESS;
229         dns_zone_setssutable(zone, table);
230
231  cleanup:
232         dns_ssutable_detach(&table);
233         return (result);
234 }
235
236 /*
237  * Convert a config file zone type into a server zone type.
238  */
239 static inline dns_zonetype_t
240 zonetype_fromconfig(cfg_obj_t *map) {
241         cfg_obj_t *obj = NULL;
242         isc_result_t result;
243
244         result = cfg_map_get(map, "type", &obj);
245         INSIST(result == ISC_R_SUCCESS);
246         return (ns_config_getzonetype(obj));
247 }
248
249 /*
250  * Helper function for strtoargv().  Pardon the gratuitous recursion.
251  */
252 static isc_result_t
253 strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
254              char ***argvp, unsigned int n)
255 {
256         isc_result_t result;
257         
258         /* Discard leading whitespace. */
259         while (*s == ' ' || *s == '\t')
260                 s++;
261         
262         if (*s == '\0') {
263                 /* We have reached the end of the string. */
264                 *argcp = n;
265                 *argvp = isc_mem_get(mctx, n * sizeof(char *));
266                 if (*argvp == NULL)
267                         return (ISC_R_NOMEMORY);
268         } else {
269                 char *p = s;
270                 while (*p != ' ' && *p != '\t' && *p != '\0')
271                         p++;
272                 if (*p != '\0')
273                         *p++ = '\0';
274
275                 result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
276                 if (result != ISC_R_SUCCESS)
277                         return (result);
278                 (*argvp)[n] = s;
279         }
280         return (ISC_R_SUCCESS);
281 }
282
283 /*
284  * Tokenize the string "s" into whitespace-separated words,
285  * return the number of words in '*argcp' and an array
286  * of pointers to the words in '*argvp'.  The caller
287  * must free the array using isc_mem_put().  The string
288  * is modified in-place.
289  */
290 static isc_result_t
291 strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
292         return (strtoargvsub(mctx, s, argcp, argvp, 0));
293 }
294
295 static void
296 checknames(dns_zonetype_t ztype, cfg_obj_t **maps, cfg_obj_t **objp) {
297         const char *zone = NULL;
298         isc_result_t result;
299
300         switch (ztype) {
301         case dns_zone_slave: zone = "slave"; break;
302         case dns_zone_master: zone = "master"; break;
303         default:
304                 INSIST(0);
305         }
306         result = ns_checknames_get(maps, zone, objp);
307         INSIST(result == ISC_R_SUCCESS);
308 }
309
310 isc_result_t
311 ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig,
312                   ns_aclconfctx_t *ac, dns_zone_t *zone)
313 {
314         isc_result_t result;
315         char *zname;
316         dns_rdataclass_t zclass;
317         dns_rdataclass_t vclass;
318         cfg_obj_t *maps[5];
319         cfg_obj_t *zoptions = NULL;
320         cfg_obj_t *options = NULL;
321         cfg_obj_t *obj;
322         const char *filename = NULL;
323         dns_notifytype_t notifytype = dns_notifytype_yes;
324         isc_sockaddr_t *addrs;
325         dns_name_t **keynames;
326         isc_uint32_t count;
327         char *cpval;
328         unsigned int dbargc;
329         char **dbargv;
330         static char default_dbtype[] = "rbt";
331         isc_mem_t *mctx = dns_zone_getmctx(zone);
332         dns_dialuptype_t dialup = dns_dialuptype_no;
333         dns_zonetype_t ztype;
334         int i;
335         isc_int32_t journal_size;
336         isc_boolean_t multi;
337         isc_boolean_t alt;
338         dns_view_t *view;
339         isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
340
341         i = 0;
342         if (zconfig != NULL) {
343                 zoptions = cfg_tuple_get(zconfig, "options");
344                 maps[i++] = zoptions;
345         }
346         if (vconfig != NULL)
347                 maps[i++] = cfg_tuple_get(vconfig, "options");
348         if (config != NULL) {
349                 (void)cfg_map_get(config, "options", &options);
350                 if (options != NULL)
351                         maps[i++] = options;
352         }
353         maps[i++] = ns_g_defaults;
354         maps[i++] = NULL;
355
356         if (vconfig != NULL)
357                 RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
358                                           dns_rdataclass_in, &vclass));
359         else
360                 vclass = dns_rdataclass_in;
361
362         /*
363          * Configure values common to all zone types.
364          */
365
366         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
367
368         RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
369                                   vclass, &zclass));
370         dns_zone_setclass(zone, zclass);
371
372         ztype = zonetype_fromconfig(zoptions);
373         dns_zone_settype(zone, ztype);
374
375         obj = NULL;
376         result = cfg_map_get(zoptions, "database", &obj);
377         if (result == ISC_R_SUCCESS)
378                 cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
379         else
380                 cpval = default_dbtype;
381
382         if (cpval == NULL)
383                 return(ISC_R_NOMEMORY);
384
385         result = strtoargv(mctx, cpval, &dbargc, &dbargv);
386         if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
387                 isc_mem_free(mctx, cpval);
388                 return (result);
389         }
390
391         /*
392          * ANSI C is strange here.  There is no logical reason why (char **)
393          * cannot be promoted automatically to (const char * const *) by the
394          * compiler w/o generating a warning.
395          */
396         result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
397         isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
398         if (cpval != default_dbtype)
399                 isc_mem_free(mctx, cpval);
400         if (result != ISC_R_SUCCESS)
401                 return (result);
402
403         obj = NULL;
404         result = cfg_map_get(zoptions, "file", &obj);
405         if (result == ISC_R_SUCCESS)
406                 filename = cfg_obj_asstring(obj);
407         RETERR(dns_zone_setfile(zone, filename));
408
409         if (ztype == dns_zone_slave)
410                 RETERR(configure_zone_acl(zconfig, vconfig, config,
411                                           "allow-notify", ac, zone,
412                                           dns_zone_setnotifyacl,
413                                           dns_zone_clearnotifyacl));
414         /*
415          * XXXAG This probably does not make sense for stubs.
416          */
417         RETERR(configure_zone_acl(zconfig, vconfig, config,
418                                   "allow-query", ac, zone,
419                                   dns_zone_setqueryacl,
420                                   dns_zone_clearqueryacl));
421
422         obj = NULL;
423         result = ns_config_get(maps, "dialup", &obj);
424         INSIST(result == ISC_R_SUCCESS);
425         if (cfg_obj_isboolean(obj)) {
426                 if (cfg_obj_asboolean(obj))
427                         dialup = dns_dialuptype_yes;
428                 else
429                         dialup = dns_dialuptype_no;
430         } else {
431                 char *dialupstr = cfg_obj_asstring(obj);
432                 if (strcasecmp(dialupstr, "notify") == 0)
433                         dialup = dns_dialuptype_notify;
434                 else if (strcasecmp(dialupstr, "notify-passive") == 0)
435                         dialup = dns_dialuptype_notifypassive;
436                 else if (strcasecmp(dialupstr, "refresh") == 0)
437                         dialup = dns_dialuptype_refresh;
438                 else if (strcasecmp(dialupstr, "passive") == 0)
439                         dialup = dns_dialuptype_passive;
440                 else
441                         INSIST(0);
442         }
443         dns_zone_setdialup(zone, dialup);
444
445         obj = NULL;
446         result = ns_config_get(maps, "zone-statistics", &obj);
447         INSIST(result == ISC_R_SUCCESS);
448         RETERR(dns_zone_setstatistics(zone, cfg_obj_asboolean(obj)));
449
450         /*
451          * Configure master functionality.  This applies
452          * to primary masters (type "master") and slaves
453          * acting as masters (type "slave"), but not to stubs.
454          */
455         if (ztype != dns_zone_stub) {
456                 obj = NULL;
457                 result = ns_config_get(maps, "notify", &obj);
458                 INSIST(result == ISC_R_SUCCESS);
459                 if (cfg_obj_isboolean(obj)) {
460                         if (cfg_obj_asboolean(obj))
461                                 notifytype = dns_notifytype_yes;
462                         else
463                                 notifytype = dns_notifytype_no;
464                 } else {
465                         char *notifystr = cfg_obj_asstring(obj);
466                         if (strcasecmp(notifystr, "explicit") == 0)
467                                 notifytype = dns_notifytype_explicit;
468                         else
469                                 INSIST(0);
470                 }
471                 dns_zone_setnotifytype(zone, notifytype);
472
473                 obj = NULL;
474                 result = ns_config_get(maps, "also-notify", &obj);
475                 if (result == ISC_R_SUCCESS) {
476                         isc_sockaddr_t *addrs = NULL;
477                         isc_uint32_t addrcount;
478                         result = ns_config_getiplist(config, obj, 0, mctx,
479                                                      &addrs, &addrcount);
480                         if (result != ISC_R_SUCCESS)
481                                 return (result);
482                         result = dns_zone_setalsonotify(zone, addrs,
483                                                         addrcount);
484                         ns_config_putiplist(mctx, &addrs, addrcount);
485                         if (result != ISC_R_SUCCESS)
486                                 return (result);
487                 } else
488                         RETERR(dns_zone_setalsonotify(zone, NULL, 0));
489
490                 obj = NULL;
491                 result = ns_config_get(maps, "notify-source", &obj);
492                 INSIST(result == ISC_R_SUCCESS);
493                 RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
494                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
495
496                 obj = NULL;
497                 result = ns_config_get(maps, "notify-source-v6", &obj);
498                 INSIST(result == ISC_R_SUCCESS);
499                 RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
500                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
501
502                 RETERR(configure_zone_acl(zconfig, vconfig, config,
503                                           "allow-transfer", ac, zone,
504                                           dns_zone_setxfracl,
505                                           dns_zone_clearxfracl));
506
507                 obj = NULL;
508                 result = ns_config_get(maps, "max-transfer-time-out", &obj);
509                 INSIST(result == ISC_R_SUCCESS);
510                 dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
511
512                 obj = NULL;
513                 result = ns_config_get(maps, "max-transfer-idle-out", &obj);
514                 INSIST(result == ISC_R_SUCCESS);
515                 dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
516
517                 obj = NULL;
518                 result =  ns_config_get(maps, "max-journal-size", &obj);
519                 INSIST(result == ISC_R_SUCCESS);
520                 dns_zone_setjournalsize(zone, -1);
521                 if (cfg_obj_isstring(obj)) {
522                         const char *str = cfg_obj_asstring(obj);
523                         INSIST(strcasecmp(str, "unlimited") == 0);
524                         journal_size = ISC_UINT32_MAX / 2;
525                 } else {
526                         isc_resourcevalue_t value;
527                         value = cfg_obj_asuint64(obj);
528                         if (value > ISC_UINT32_MAX / 2) {
529                                 cfg_obj_log(obj, ns_g_lctx,
530                                             ISC_LOG_ERROR,
531                                             "'max-journal-size "
532                                             "%" ISC_PRINT_QUADFORMAT "d' "
533                                             "is too large",
534                                             value);
535                                 RETERR(ISC_R_RANGE);
536                         }
537                         journal_size = (isc_uint32_t)value;
538                 }
539                 dns_zone_setjournalsize(zone, journal_size);
540
541                 obj = NULL;
542                 result = ns_config_get(maps, "ixfr-from-differences", &obj);
543                 INSIST(result == ISC_R_SUCCESS);
544                 dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS,
545                                    cfg_obj_asboolean(obj));
546
547                 checknames(ztype, maps, &obj);
548                 INSIST(obj != NULL);
549                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
550                         fail = ISC_FALSE;
551                         check = ISC_TRUE;
552                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
553                         fail = check = ISC_TRUE;
554                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
555                         fail = check = ISC_FALSE;
556                 } else
557                         INSIST(0);
558                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
559                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);
560         }
561
562         /*
563          * Configure update-related options.  These apply to
564          * primary masters only.
565          */
566         if (ztype == dns_zone_master) {
567                 dns_acl_t *updateacl;
568                 RETERR(configure_zone_acl(zconfig, vconfig, config,
569                                           "allow-update", ac, zone,
570                                           dns_zone_setupdateacl,
571                                           dns_zone_clearupdateacl));
572                 
573                 updateacl = dns_zone_getupdateacl(zone);
574                 if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
575                         isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
576                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
577                                       "zone '%s' allows updates by IP "
578                                       "address, which is insecure",
579                                       zname);
580                 
581                 RETERR(configure_zone_ssutable(zoptions, zone));
582
583                 obj = NULL;
584                 result = ns_config_get(maps, "sig-validity-interval", &obj);
585                 INSIST(result == ISC_R_SUCCESS);
586                 dns_zone_setsigvalidityinterval(zone,
587                                                 cfg_obj_asuint32(obj) * 86400);
588
589                 obj = NULL;
590                 result = ns_config_get(maps, "key-directory", &obj);
591                 if (result == ISC_R_SUCCESS) {
592                         filename = cfg_obj_asstring(obj);
593                         if (!isc_file_isabsolute(filename)) {
594                                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
595                                             "key-directory '%s' "
596                                             "is not absolute", filename);
597                                 return (ISC_R_FAILURE);
598                         }
599                         RETERR(dns_zone_setkeydirectory(zone, filename));
600                 }
601
602         } else if (ztype == dns_zone_slave) {
603                 RETERR(configure_zone_acl(zconfig, vconfig, config,
604                                           "allow-update-forwarding", ac, zone,
605                                           dns_zone_setforwardacl,
606                                           dns_zone_clearforwardacl));
607         }
608
609         /*
610          * Configure slave functionality.
611          */
612         switch (ztype) {
613         case dns_zone_slave:
614         case dns_zone_stub:
615                 obj = NULL;
616                 result = cfg_map_get(zoptions, "masters", &obj);
617                 if (obj != NULL) {
618                         addrs = NULL;
619                         keynames = NULL;
620                         RETERR(ns_config_getipandkeylist(config, obj, mctx,
621                                                          &addrs, &keynames,
622                                                          &count));
623                         result = dns_zone_setmasterswithkeys(zone, addrs,
624                                                              keynames, count);
625                         ns_config_putipandkeylist(mctx, &addrs, &keynames,
626                                                   count);
627                 } else
628                         result = dns_zone_setmasters(zone, NULL, 0);
629                 RETERR(result);
630
631                 multi = ISC_FALSE;
632                 if (count > 1) {
633                         obj = NULL;
634                         result = ns_config_get(maps, "multi-master", &obj);
635                         INSIST(result == ISC_R_SUCCESS);
636                         multi = cfg_obj_asboolean(obj);
637                 }
638                 dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);
639
640                 obj = NULL;
641                 result = ns_config_get(maps, "max-transfer-time-in", &obj);
642                 INSIST(result == ISC_R_SUCCESS);
643                 dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
644
645                 obj = NULL;
646                 result = ns_config_get(maps, "max-transfer-idle-in", &obj);
647                 INSIST(result == ISC_R_SUCCESS);
648                 dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
649
650                 obj = NULL;
651                 result = ns_config_get(maps, "max-refresh-time", &obj);
652                 INSIST(result == ISC_R_SUCCESS);
653                 dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
654
655                 obj = NULL;
656                 result = ns_config_get(maps, "min-refresh-time", &obj);
657                 INSIST(result == ISC_R_SUCCESS);
658                 dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
659
660                 obj = NULL;
661                 result = ns_config_get(maps, "max-retry-time", &obj);
662                 INSIST(result == ISC_R_SUCCESS);
663                 dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
664
665                 obj = NULL;
666                 result = ns_config_get(maps, "min-retry-time", &obj);
667                 INSIST(result == ISC_R_SUCCESS);
668                 dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
669
670                 obj = NULL;
671                 result = ns_config_get(maps, "transfer-source", &obj);
672                 INSIST(result == ISC_R_SUCCESS);
673                 RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
674                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
675
676                 obj = NULL;
677                 result = ns_config_get(maps, "transfer-source-v6", &obj);
678                 INSIST(result == ISC_R_SUCCESS);
679                 RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
680                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
681
682                 obj = NULL;
683                 result = ns_config_get(maps, "alt-transfer-source", &obj);
684                 INSIST(result == ISC_R_SUCCESS);
685                 RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));
686
687                 obj = NULL;
688                 result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
689                 INSIST(result == ISC_R_SUCCESS);
690                 RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));
691
692                 obj = NULL;
693                 (void)ns_config_get(maps, "use-alt-transfer-source", &obj);
694                 if (obj == NULL) {
695                         /*
696                          * Default off when views are in use otherwise
697                          * on for BIND 8 compatibility.
698                          */
699                         view = dns_zone_getview(zone);
700                         if (view != NULL && strcmp(view->name, "_default") == 0)
701                                 alt = ISC_TRUE;
702                         else
703                                 alt = ISC_FALSE;
704                 } else
705                         alt = cfg_obj_asboolean(obj);
706                 dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);
707
708                 break;
709
710         default:
711                 break;
712         }
713
714         return (ISC_R_SUCCESS);
715 }
716
717 isc_boolean_t
718 ns_zone_reusable(dns_zone_t *zone, cfg_obj_t *zconfig) {
719         cfg_obj_t *zoptions = NULL;
720         cfg_obj_t *obj = NULL;
721         const char *cfilename;
722         const char *zfilename;
723
724         zoptions = cfg_tuple_get(zconfig, "options");
725
726         if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone))
727                 return (ISC_FALSE);
728
729         obj = NULL;
730         (void)cfg_map_get(zoptions, "file", &obj);
731         if (obj != NULL)
732                 cfilename = cfg_obj_asstring(obj);
733         else
734                 cfilename = NULL;
735         zfilename = dns_zone_getfile(zone);
736         if (!((cfilename == NULL && zfilename == NULL) ||
737               (cfilename != NULL && zfilename != NULL &&
738                strcmp(cfilename, zfilename) == 0)))
739             return (ISC_FALSE);
740
741         return (ISC_TRUE);
742 }