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