]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/bind9/bin/named/zoneconf.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / bind9 / bin / named / zoneconf.c
1 /*
2  * Copyright (C) 2004-2009  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.147.50.2 2009/01/29 23:47:44 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/fixedname.h>
34 #include <dns/log.h>
35 #include <dns/name.h>
36 #include <dns/rdatatype.h>
37 #include <dns/ssu.h>
38 #include <dns/stats.h>
39 #include <dns/view.h>
40 #include <dns/zone.h>
41
42 #include <named/client.h>
43 #include <named/config.h>
44 #include <named/globals.h>
45 #include <named/log.h>
46 #include <named/server.h>
47 #include <named/zoneconf.h>
48
49 /* ACLs associated with zone */
50 typedef enum {
51         allow_notify,
52         allow_query,
53         allow_transfer,
54         allow_update,
55         allow_update_forwarding
56 } acl_type_t;
57
58 /*%
59  * These are BIND9 server defaults, not necessarily identical to the
60  * library defaults defined in zone.c.
61  */
62 #define RETERR(x) do { \
63         isc_result_t _r = (x); \
64         if (_r != ISC_R_SUCCESS) \
65                 return (_r); \
66         } while (0)
67
68 /*%
69  * Convenience function for configuring a single zone ACL.
70  */
71 static isc_result_t
72 configure_zone_acl(const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
73                    const cfg_obj_t *config, acl_type_t acltype,
74                    cfg_aclconfctx_t *actx, dns_zone_t *zone,
75                    void (*setzacl)(dns_zone_t *, dns_acl_t *),
76                    void (*clearzacl)(dns_zone_t *))
77 {
78         isc_result_t result;
79         const cfg_obj_t *maps[5] = {NULL, NULL, NULL, NULL, NULL};
80         const cfg_obj_t *aclobj = NULL;
81         int i = 0;
82         dns_acl_t **aclp = NULL, *acl = NULL;
83         const char *aclname;
84         dns_view_t *view;
85
86         view = dns_zone_getview(zone);
87
88         switch (acltype) {
89             case allow_notify:
90                 if (view != NULL)
91                         aclp = &view->notifyacl;
92                 aclname = "allow-notify";
93                 break;
94             case allow_query:
95                 if (view != NULL)
96                         aclp = &view->queryacl;
97                 aclname = "allow-query";
98                 break;
99             case allow_transfer:
100                 if (view != NULL)
101                         aclp = &view->transferacl;
102                 aclname = "allow-transfer";
103                 break;
104             case allow_update:
105                 if (view != NULL)
106                         aclp = &view->updateacl;
107                 aclname = "allow-update";
108                 break;
109             case allow_update_forwarding:
110                 if (view != NULL)
111                         aclp = &view->upfwdacl;
112                 aclname = "allow-update-forwarding";
113                 break;
114             default:
115                 INSIST(0);
116                 return (ISC_R_FAILURE);
117         }
118
119         /* First check to see if ACL is defined within the zone */
120         if (zconfig != NULL) {
121                 maps[0] = cfg_tuple_get(zconfig, "options");
122                 ns_config_get(maps, aclname, &aclobj);
123                 if (aclobj != NULL) {
124                         aclp = NULL;
125                         goto parse_acl;
126                 }
127         }
128
129         /* Failing that, see if there's a default ACL already in the view */
130         if (aclp != NULL && *aclp != NULL) {
131                 (*setzacl)(zone, *aclp);
132                 return (ISC_R_SUCCESS);
133         }
134
135         /* Check for default ACLs that haven't been parsed yet */
136         if (vconfig != NULL)
137                 maps[i++] = cfg_tuple_get(vconfig, "options");
138         if (config != NULL) {
139                 const cfg_obj_t *options = NULL;
140                 (void)cfg_map_get(config, "options", &options);
141                 if (options != NULL)
142                         maps[i++] = options;
143         }
144         maps[i++] = ns_g_defaults;
145         maps[i] = NULL;
146
147         result = ns_config_get(maps, aclname, &aclobj);
148         if (aclobj == NULL) {
149                 (*clearzacl)(zone);
150                 return (ISC_R_SUCCESS);
151         }
152
153 parse_acl:
154         result = cfg_acl_fromconfig(aclobj, config, ns_g_lctx, actx,
155                                     dns_zone_getmctx(zone), 0, &acl);
156         if (result != ISC_R_SUCCESS)
157                 return (result);
158         (*setzacl)(zone, acl);
159
160         /* Set the view default now */
161         if (aclp != NULL)
162                 dns_acl_attach(acl, aclp);
163
164         dns_acl_detach(&acl);
165         return (ISC_R_SUCCESS);
166 }
167
168 /*%
169  * Parse the zone update-policy statement.
170  */
171 static isc_result_t
172 configure_zone_ssutable(const cfg_obj_t *zconfig, dns_zone_t *zone) {
173         const cfg_obj_t *updatepolicy = NULL;
174         const cfg_listelt_t *element, *element2;
175         dns_ssutable_t *table = NULL;
176         isc_mem_t *mctx = dns_zone_getmctx(zone);
177         isc_result_t result;
178
179         (void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
180         if (updatepolicy == NULL) {
181                 dns_zone_setssutable(zone, NULL);
182                 return (ISC_R_SUCCESS);
183         }
184
185         result = dns_ssutable_create(mctx, &table);
186         if (result != ISC_R_SUCCESS)
187                 return (result);
188
189         for (element = cfg_list_first(updatepolicy);
190              element != NULL;
191              element = cfg_list_next(element))
192         {
193                 const cfg_obj_t *stmt = cfg_listelt_value(element);
194                 const cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
195                 const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
196                 const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
197                 const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
198                 const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
199                 const char *str;
200                 isc_boolean_t grant = ISC_FALSE;
201                 unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
202                 dns_fixedname_t fname, fident;
203                 isc_buffer_t b;
204                 dns_rdatatype_t *types;
205                 unsigned int i, n;
206
207                 str = cfg_obj_asstring(mode);
208                 if (strcasecmp(str, "grant") == 0)
209                         grant = ISC_TRUE;
210                 else if (strcasecmp(str, "deny") == 0)
211                         grant = ISC_FALSE;
212                 else
213                         INSIST(0);
214
215                 str = cfg_obj_asstring(matchtype);
216                 if (strcasecmp(str, "name") == 0)
217                         mtype = DNS_SSUMATCHTYPE_NAME;
218                 else if (strcasecmp(str, "subdomain") == 0)
219                         mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
220                 else if (strcasecmp(str, "wildcard") == 0)
221                         mtype = DNS_SSUMATCHTYPE_WILDCARD;
222                 else if (strcasecmp(str, "self") == 0)
223                         mtype = DNS_SSUMATCHTYPE_SELF;
224                 else if (strcasecmp(str, "selfsub") == 0)
225                         mtype = DNS_SSUMATCHTYPE_SELFSUB;
226                 else if (strcasecmp(str, "selfwild") == 0)
227                         mtype = DNS_SSUMATCHTYPE_SELFWILD;
228                 else if (strcasecmp(str, "ms-self") == 0)
229                         mtype = DNS_SSUMATCHTYPE_SELFMS;
230                 else if (strcasecmp(str, "krb5-self") == 0)
231                         mtype = DNS_SSUMATCHTYPE_SELFKRB5;
232                 else if (strcasecmp(str, "ms-subdomain") == 0)
233                         mtype = DNS_SSUMATCHTYPE_SUBDOMAINMS;
234                 else if (strcasecmp(str, "krb5-subdomain") == 0)
235                         mtype = DNS_SSUMATCHTYPE_SUBDOMAINKRB5;
236                 else if (strcasecmp(str, "tcp-self") == 0)
237                         mtype = DNS_SSUMATCHTYPE_TCPSELF;
238                 else if (strcasecmp(str, "6to4-self") == 0)
239                         mtype = DNS_SSUMATCHTYPE_6TO4SELF;
240                 else
241                         INSIST(0);
242
243                 dns_fixedname_init(&fident);
244                 str = cfg_obj_asstring(identity);
245                 isc_buffer_init(&b, str, strlen(str));
246                 isc_buffer_add(&b, strlen(str));
247                 result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
248                                            dns_rootname, ISC_FALSE, NULL);
249                 if (result != ISC_R_SUCCESS) {
250                         cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
251                                     "'%s' is not a valid name", str);
252                         goto cleanup;
253                 }
254
255                 dns_fixedname_init(&fname);
256                 str = cfg_obj_asstring(dname);
257                 isc_buffer_init(&b, str, strlen(str));
258                 isc_buffer_add(&b, strlen(str));
259                 result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
260                                            dns_rootname, ISC_FALSE, NULL);
261                 if (result != ISC_R_SUCCESS) {
262                         cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
263                                     "'%s' is not a valid name", str);
264                         goto cleanup;
265                 }
266
267                 n = ns_config_listcount(typelist);
268                 if (n == 0)
269                         types = NULL;
270                 else {
271                         types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
272                         if (types == NULL) {
273                                 result = ISC_R_NOMEMORY;
274                                 goto cleanup;
275                         }
276                 }
277
278                 i = 0;
279                 for (element2 = cfg_list_first(typelist);
280                      element2 != NULL;
281                      element2 = cfg_list_next(element2))
282                 {
283                         const cfg_obj_t *typeobj;
284                         isc_textregion_t r;
285
286                         INSIST(i < n);
287
288                         typeobj = cfg_listelt_value(element2);
289                         str = cfg_obj_asstring(typeobj);
290                         DE_CONST(str, r.base);
291                         r.length = strlen(str);
292
293                         result = dns_rdatatype_fromtext(&types[i++], &r);
294                         if (result != ISC_R_SUCCESS) {
295                                 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
296                                             "'%s' is not a valid type", str);
297                                 isc_mem_put(mctx, types,
298                                             n * sizeof(dns_rdatatype_t));
299                                 goto cleanup;
300                         }
301                 }
302                 INSIST(i == n);
303
304                 result = dns_ssutable_addrule(table, grant,
305                                               dns_fixedname_name(&fident),
306                                               mtype,
307                                               dns_fixedname_name(&fname),
308                                               n, types);
309                 if (types != NULL)
310                         isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
311                 if (result != ISC_R_SUCCESS) {
312                         goto cleanup;
313                 }
314
315         }
316
317         result = ISC_R_SUCCESS;
318         dns_zone_setssutable(zone, table);
319
320  cleanup:
321         dns_ssutable_detach(&table);
322         return (result);
323 }
324
325 /*%
326  * Convert a config file zone type into a server zone type.
327  */
328 static inline dns_zonetype_t
329 zonetype_fromconfig(const cfg_obj_t *map) {
330         const cfg_obj_t *obj = NULL;
331         isc_result_t result;
332
333         result = cfg_map_get(map, "type", &obj);
334         INSIST(result == ISC_R_SUCCESS);
335         return (ns_config_getzonetype(obj));
336 }
337
338 /*%
339  * Helper function for strtoargv().  Pardon the gratuitous recursion.
340  */
341 static isc_result_t
342 strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
343              char ***argvp, unsigned int n)
344 {
345         isc_result_t result;
346
347         /* Discard leading whitespace. */
348         while (*s == ' ' || *s == '\t')
349                 s++;
350
351         if (*s == '\0') {
352                 /* We have reached the end of the string. */
353                 *argcp = n;
354                 *argvp = isc_mem_get(mctx, n * sizeof(char *));
355                 if (*argvp == NULL)
356                         return (ISC_R_NOMEMORY);
357         } else {
358                 char *p = s;
359                 while (*p != ' ' && *p != '\t' && *p != '\0')
360                         p++;
361                 if (*p != '\0')
362                         *p++ = '\0';
363
364                 result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
365                 if (result != ISC_R_SUCCESS)
366                         return (result);
367                 (*argvp)[n] = s;
368         }
369         return (ISC_R_SUCCESS);
370 }
371
372 /*%
373  * Tokenize the string "s" into whitespace-separated words,
374  * return the number of words in '*argcp' and an array
375  * of pointers to the words in '*argvp'.  The caller
376  * must free the array using isc_mem_put().  The string
377  * is modified in-place.
378  */
379 static isc_result_t
380 strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
381         return (strtoargvsub(mctx, s, argcp, argvp, 0));
382 }
383
384 static void
385 checknames(dns_zonetype_t ztype, const cfg_obj_t **maps,
386            const cfg_obj_t **objp)
387 {
388         const char *zone = NULL;
389         isc_result_t result;
390
391         switch (ztype) {
392         case dns_zone_slave: zone = "slave"; break;
393         case dns_zone_master: zone = "master"; break;
394         default:
395                 INSIST(0);
396         }
397         result = ns_checknames_get(maps, zone, objp);
398         INSIST(result == ISC_R_SUCCESS);
399 }
400
401 isc_result_t
402 ns_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
403                   const cfg_obj_t *zconfig, cfg_aclconfctx_t *ac,
404                   dns_zone_t *zone)
405 {
406         isc_result_t result;
407         const char *zname;
408         dns_rdataclass_t zclass;
409         dns_rdataclass_t vclass;
410         const cfg_obj_t *maps[5];
411         const cfg_obj_t *zoptions = NULL;
412         const cfg_obj_t *options = NULL;
413         const cfg_obj_t *obj;
414         const char *filename = NULL;
415         dns_notifytype_t notifytype = dns_notifytype_yes;
416         isc_sockaddr_t *addrs;
417         dns_name_t **keynames;
418         isc_uint32_t count;
419         char *cpval;
420         unsigned int dbargc;
421         char **dbargv;
422         static char default_dbtype[] = "rbt";
423         isc_mem_t *mctx = dns_zone_getmctx(zone);
424         dns_dialuptype_t dialup = dns_dialuptype_no;
425         dns_zonetype_t ztype;
426         int i;
427         isc_int32_t journal_size;
428         isc_boolean_t multi;
429         isc_boolean_t alt;
430         dns_view_t *view;
431         isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
432         isc_boolean_t warn = ISC_FALSE, ignore = ISC_FALSE;
433         isc_boolean_t ixfrdiff;
434         dns_masterformat_t masterformat;
435         isc_stats_t *zoneqrystats;
436         isc_boolean_t zonestats_on;
437         int seconds;
438
439         i = 0;
440         if (zconfig != NULL) {
441                 zoptions = cfg_tuple_get(zconfig, "options");
442                 maps[i++] = zoptions;
443         }
444         if (vconfig != NULL)
445                 maps[i++] = cfg_tuple_get(vconfig, "options");
446         if (config != NULL) {
447                 (void)cfg_map_get(config, "options", &options);
448                 if (options != NULL)
449                         maps[i++] = options;
450         }
451         maps[i++] = ns_g_defaults;
452         maps[i++] = NULL;
453
454         if (vconfig != NULL)
455                 RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
456                                           dns_rdataclass_in, &vclass));
457         else
458                 vclass = dns_rdataclass_in;
459
460         /*
461          * Configure values common to all zone types.
462          */
463
464         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
465
466         RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
467                                   vclass, &zclass));
468         dns_zone_setclass(zone, zclass);
469
470         ztype = zonetype_fromconfig(zoptions);
471         dns_zone_settype(zone, ztype);
472
473         obj = NULL;
474         result = cfg_map_get(zoptions, "database", &obj);
475         if (result == ISC_R_SUCCESS)
476                 cpval = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
477         else
478                 cpval = default_dbtype;
479
480         if (cpval == NULL)
481                 return(ISC_R_NOMEMORY);
482
483         result = strtoargv(mctx, cpval, &dbargc, &dbargv);
484         if (result != ISC_R_SUCCESS && cpval != default_dbtype) {
485                 isc_mem_free(mctx, cpval);
486                 return (result);
487         }
488
489         /*
490          * ANSI C is strange here.  There is no logical reason why (char **)
491          * cannot be promoted automatically to (const char * const *) by the
492          * compiler w/o generating a warning.
493          */
494         result = dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv);
495         isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
496         if (cpval != default_dbtype)
497                 isc_mem_free(mctx, cpval);
498         if (result != ISC_R_SUCCESS)
499                 return (result);
500
501         obj = NULL;
502         result = cfg_map_get(zoptions, "file", &obj);
503         if (result == ISC_R_SUCCESS)
504                 filename = cfg_obj_asstring(obj);
505
506         masterformat = dns_masterformat_text;
507         obj = NULL;
508         result= ns_config_get(maps, "masterfile-format", &obj);
509         if (result == ISC_R_SUCCESS) {
510                 const char *masterformatstr = cfg_obj_asstring(obj);
511
512                 if (strcasecmp(masterformatstr, "text") == 0)
513                         masterformat = dns_masterformat_text;
514                 else if (strcasecmp(masterformatstr, "raw") == 0)
515                         masterformat = dns_masterformat_raw;
516                 else
517                         INSIST(0);
518         }
519         RETERR(dns_zone_setfile2(zone, filename, masterformat));
520
521         obj = NULL;
522         result = cfg_map_get(zoptions, "journal", &obj);
523         if (result == ISC_R_SUCCESS)
524                 RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj)));
525
526         if (ztype == dns_zone_slave)
527                 RETERR(configure_zone_acl(zconfig, vconfig, config,
528                                           allow_notify, ac, zone,
529                                           dns_zone_setnotifyacl,
530                                           dns_zone_clearnotifyacl));
531         /*
532          * XXXAG This probably does not make sense for stubs.
533          */
534         RETERR(configure_zone_acl(zconfig, vconfig, config,
535                                   allow_query, ac, zone,
536                                   dns_zone_setqueryacl,
537                                   dns_zone_clearqueryacl));
538
539         obj = NULL;
540         result = ns_config_get(maps, "dialup", &obj);
541         INSIST(result == ISC_R_SUCCESS);
542         if (cfg_obj_isboolean(obj)) {
543                 if (cfg_obj_asboolean(obj))
544                         dialup = dns_dialuptype_yes;
545                 else
546                         dialup = dns_dialuptype_no;
547         } else {
548                 const char *dialupstr = cfg_obj_asstring(obj);
549                 if (strcasecmp(dialupstr, "notify") == 0)
550                         dialup = dns_dialuptype_notify;
551                 else if (strcasecmp(dialupstr, "notify-passive") == 0)
552                         dialup = dns_dialuptype_notifypassive;
553                 else if (strcasecmp(dialupstr, "refresh") == 0)
554                         dialup = dns_dialuptype_refresh;
555                 else if (strcasecmp(dialupstr, "passive") == 0)
556                         dialup = dns_dialuptype_passive;
557                 else
558                         INSIST(0);
559         }
560         dns_zone_setdialup(zone, dialup);
561
562         obj = NULL;
563         result = ns_config_get(maps, "zone-statistics", &obj);
564         INSIST(result == ISC_R_SUCCESS);
565         zonestats_on = cfg_obj_asboolean(obj);
566         zoneqrystats = NULL;
567         if (zonestats_on) {
568                 RETERR(isc_stats_create(mctx, &zoneqrystats,
569                                         dns_nsstatscounter_max));
570         }
571         dns_zone_setrequeststats(zone, zoneqrystats);
572         if (zoneqrystats != NULL)
573                 isc_stats_detach(&zoneqrystats);
574
575         /*
576          * Configure master functionality.  This applies
577          * to primary masters (type "master") and slaves
578          * acting as masters (type "slave"), but not to stubs.
579          */
580         if (ztype != dns_zone_stub) {
581                 obj = NULL;
582                 result = ns_config_get(maps, "notify", &obj);
583                 INSIST(result == ISC_R_SUCCESS);
584                 if (cfg_obj_isboolean(obj)) {
585                         if (cfg_obj_asboolean(obj))
586                                 notifytype = dns_notifytype_yes;
587                         else
588                                 notifytype = dns_notifytype_no;
589                 } else {
590                         const char *notifystr = cfg_obj_asstring(obj);
591                         if (strcasecmp(notifystr, "explicit") == 0)
592                                 notifytype = dns_notifytype_explicit;
593                         else if (strcasecmp(notifystr, "master-only") == 0)
594                                 notifytype = dns_notifytype_masteronly;
595                         else
596                                 INSIST(0);
597                 }
598                 dns_zone_setnotifytype(zone, notifytype);
599
600                 obj = NULL;
601                 result = ns_config_get(maps, "also-notify", &obj);
602                 if (result == ISC_R_SUCCESS) {
603                         isc_sockaddr_t *addrs = NULL;
604                         isc_uint32_t addrcount;
605                         result = ns_config_getiplist(config, obj, 0, mctx,
606                                                      &addrs, &addrcount);
607                         if (result != ISC_R_SUCCESS)
608                                 return (result);
609                         result = dns_zone_setalsonotify(zone, addrs,
610                                                         addrcount);
611                         ns_config_putiplist(mctx, &addrs, addrcount);
612                         if (result != ISC_R_SUCCESS)
613                                 return (result);
614                 } else
615                         RETERR(dns_zone_setalsonotify(zone, NULL, 0));
616
617                 obj = NULL;
618                 result = ns_config_get(maps, "notify-source", &obj);
619                 INSIST(result == ISC_R_SUCCESS);
620                 RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
621                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
622
623                 obj = NULL;
624                 result = ns_config_get(maps, "notify-source-v6", &obj);
625                 INSIST(result == ISC_R_SUCCESS);
626                 RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
627                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
628
629                 obj = NULL;
630                 result = ns_config_get(maps, "notify-to-soa", &obj);
631                 INSIST(result == ISC_R_SUCCESS);
632                 dns_zone_setoption(zone, DNS_ZONEOPT_NOTIFYTOSOA,
633                                    cfg_obj_asboolean(obj));
634
635                 dns_zone_setisself(zone, ns_client_isself, NULL);
636
637                 RETERR(configure_zone_acl(zconfig, vconfig, config,
638                                           allow_transfer, ac, zone,
639                                           dns_zone_setxfracl,
640                                           dns_zone_clearxfracl));
641
642                 obj = NULL;
643                 result = ns_config_get(maps, "max-transfer-time-out", &obj);
644                 INSIST(result == ISC_R_SUCCESS);
645                 dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
646
647                 obj = NULL;
648                 result = ns_config_get(maps, "max-transfer-idle-out", &obj);
649                 INSIST(result == ISC_R_SUCCESS);
650                 dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
651
652                 obj = NULL;
653                 result =  ns_config_get(maps, "max-journal-size", &obj);
654                 INSIST(result == ISC_R_SUCCESS);
655                 dns_zone_setjournalsize(zone, -1);
656                 if (cfg_obj_isstring(obj)) {
657                         const char *str = cfg_obj_asstring(obj);
658                         INSIST(strcasecmp(str, "unlimited") == 0);
659                         journal_size = ISC_UINT32_MAX / 2;
660                 } else {
661                         isc_resourcevalue_t value;
662                         value = cfg_obj_asuint64(obj);
663                         if (value > ISC_UINT32_MAX / 2) {
664                                 cfg_obj_log(obj, ns_g_lctx,
665                                             ISC_LOG_ERROR,
666                                             "'max-journal-size "
667                                             "%" ISC_PRINT_QUADFORMAT "d' "
668                                             "is too large",
669                                             value);
670                                 RETERR(ISC_R_RANGE);
671                         }
672                         journal_size = (isc_uint32_t)value;
673                 }
674                 dns_zone_setjournalsize(zone, journal_size);
675
676                 obj = NULL;
677                 result = ns_config_get(maps, "ixfr-from-differences", &obj);
678                 INSIST(result == ISC_R_SUCCESS);
679                 if (cfg_obj_isboolean(obj))
680                         ixfrdiff = cfg_obj_asboolean(obj);
681                 else if (strcasecmp(cfg_obj_asstring(obj), "master") &&
682                          ztype == dns_zone_master)
683                         ixfrdiff = ISC_TRUE;
684                 else if (strcasecmp(cfg_obj_asstring(obj), "slave") &&
685                         ztype == dns_zone_slave)
686                         ixfrdiff = ISC_TRUE;
687                 else
688                         ixfrdiff = ISC_FALSE;
689                 dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff);
690
691                 checknames(ztype, maps, &obj);
692                 INSIST(obj != NULL);
693                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
694                         fail = ISC_FALSE;
695                         check = ISC_TRUE;
696                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
697                         fail = check = ISC_TRUE;
698                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
699                         fail = check = ISC_FALSE;
700                 } else
701                         INSIST(0);
702                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
703                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);
704
705                 obj = NULL;
706                 result = ns_config_get(maps, "notify-delay", &obj);
707                 INSIST(result == ISC_R_SUCCESS);
708                 dns_zone_setnotifydelay(zone, cfg_obj_asuint32(obj));
709
710                 obj = NULL;
711                 result = ns_config_get(maps, "check-sibling", &obj);
712                 INSIST(result == ISC_R_SUCCESS);
713                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKSIBLING,
714                                    cfg_obj_asboolean(obj));
715
716                 obj = NULL;
717                 result = ns_config_get(maps, "zero-no-soa-ttl", &obj);
718                 INSIST(result == ISC_R_SUCCESS);
719                 dns_zone_setzeronosoattl(zone, cfg_obj_asboolean(obj));
720
721                 obj = NULL;
722                 result = ns_config_get(maps, "nsec3-test-zone", &obj);
723                 INSIST(result == ISC_R_SUCCESS);
724                 dns_zone_setoption(zone, DNS_ZONEOPT_NSEC3TESTZONE,
725                                    cfg_obj_asboolean(obj));
726         }
727
728         /*
729          * Configure update-related options.  These apply to
730          * primary masters only.
731          */
732         if (ztype == dns_zone_master) {
733                 dns_acl_t *updateacl;
734                 RETERR(configure_zone_acl(zconfig, vconfig, config,
735                                           allow_update, ac, zone,
736                                           dns_zone_setupdateacl,
737                                           dns_zone_clearupdateacl));
738
739                 updateacl = dns_zone_getupdateacl(zone);
740                 if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
741                         isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
742                                       NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
743                                       "zone '%s' allows updates by IP "
744                                       "address, which is insecure",
745                                       zname);
746
747                 RETERR(configure_zone_ssutable(zoptions, zone));
748
749                 obj = NULL;
750                 result = ns_config_get(maps, "sig-validity-interval", &obj);
751                 INSIST(result == ISC_R_SUCCESS);
752                 {
753                         const cfg_obj_t *validity, *resign;
754
755                         validity = cfg_tuple_get(obj, "validity");
756                         seconds = cfg_obj_asuint32(validity) * 86400;
757                         dns_zone_setsigvalidityinterval(zone, seconds);
758
759                         resign = cfg_tuple_get(obj, "re-sign");
760                         if (cfg_obj_isvoid(resign)) {
761                                 seconds /= 4;
762                         } else {
763                                 if (seconds > 7 * 86400)
764                                         seconds = cfg_obj_asuint32(resign) *
765                                                         86400;
766                                 else
767                                         seconds = cfg_obj_asuint32(resign) *
768                                                         3600;
769                         }
770                         dns_zone_setsigresigninginterval(zone, seconds);
771                 }
772
773                 obj = NULL;
774                 result = ns_config_get(maps, "key-directory", &obj);
775                 if (result == ISC_R_SUCCESS) {
776                         filename = cfg_obj_asstring(obj);
777                         if (!isc_file_isabsolute(filename)) {
778                                 cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
779                                             "key-directory '%s' "
780                                             "is not absolute", filename);
781                                 return (ISC_R_FAILURE);
782                         }
783                         RETERR(dns_zone_setkeydirectory(zone, filename));
784                 }
785
786                 obj = NULL;
787                 result = ns_config_get(maps, "sig-signing-signatures", &obj);
788                 INSIST(result == ISC_R_SUCCESS);
789                 dns_zone_setsignatures(zone, cfg_obj_asuint32(obj));
790
791                 obj = NULL;
792                 result = ns_config_get(maps, "sig-signing-nodes", &obj);
793                 INSIST(result == ISC_R_SUCCESS);
794                 dns_zone_setnodes(zone, cfg_obj_asuint32(obj));
795
796                 obj = NULL;
797                 result = ns_config_get(maps, "sig-signing-type", &obj);
798                 INSIST(result == ISC_R_SUCCESS);
799                 dns_zone_setprivatetype(zone, cfg_obj_asuint32(obj));
800
801                 obj = NULL;
802                 result = ns_config_get(maps, "update-check-ksk", &obj);
803                 INSIST(result == ISC_R_SUCCESS);
804                 dns_zone_setoption(zone, DNS_ZONEOPT_UPDATECHECKKSK,
805                                    cfg_obj_asboolean(obj));
806
807         } else if (ztype == dns_zone_slave) {
808                 RETERR(configure_zone_acl(zconfig, vconfig, config,
809                                           allow_update_forwarding, ac, zone,
810                                           dns_zone_setforwardacl,
811                                           dns_zone_clearforwardacl));
812         }
813
814
815         /*%
816          * Primary master functionality.
817          */
818         if (ztype == dns_zone_master) {
819                 obj = NULL;
820                 result = ns_config_get(maps, "check-wildcard", &obj);
821                 if (result == ISC_R_SUCCESS)
822                         check = cfg_obj_asboolean(obj);
823                 else
824                         check = ISC_FALSE;
825                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);
826
827                 obj = NULL;
828                 result = ns_config_get(maps, "check-mx", &obj);
829                 INSIST(obj != NULL);
830                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
831                         fail = ISC_FALSE;
832                         check = ISC_TRUE;
833                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
834                         fail = check = ISC_TRUE;
835                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
836                         fail = check = ISC_FALSE;
837                 } else
838                         INSIST(0);
839                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMX, check);
840                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKMXFAIL, fail);
841
842                 obj = NULL;
843                 result = ns_config_get(maps, "check-integrity", &obj);
844                 INSIST(obj != NULL);
845                 dns_zone_setoption(zone, DNS_ZONEOPT_CHECKINTEGRITY,
846                                    cfg_obj_asboolean(obj));
847
848                 obj = NULL;
849                 result = ns_config_get(maps, "check-mx-cname", &obj);
850                 INSIST(obj != NULL);
851                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
852                         warn = ISC_TRUE;
853                         ignore = ISC_FALSE;
854                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
855                         warn = ignore = ISC_FALSE;
856                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
857                         warn = ignore = ISC_TRUE;
858                 } else
859                         INSIST(0);
860                 dns_zone_setoption(zone, DNS_ZONEOPT_WARNMXCNAME, warn);
861                 dns_zone_setoption(zone, DNS_ZONEOPT_IGNOREMXCNAME, ignore);
862
863                 obj = NULL;
864                 result = ns_config_get(maps, "check-srv-cname", &obj);
865                 INSIST(obj != NULL);
866                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
867                         warn = ISC_TRUE;
868                         ignore = ISC_FALSE;
869                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
870                         warn = ignore = ISC_FALSE;
871                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
872                         warn = ignore = ISC_TRUE;
873                 } else
874                         INSIST(0);
875                 dns_zone_setoption(zone, DNS_ZONEOPT_WARNSRVCNAME, warn);
876                 dns_zone_setoption(zone, DNS_ZONEOPT_IGNORESRVCNAME, ignore);
877         }
878
879         /*
880          * Configure slave functionality.
881          */
882         switch (ztype) {
883         case dns_zone_slave:
884         case dns_zone_stub:
885                 count = 0;
886                 obj = NULL;
887                 result = cfg_map_get(zoptions, "masters", &obj);
888                 if (obj != NULL) {
889                         addrs = NULL;
890                         keynames = NULL;
891                         RETERR(ns_config_getipandkeylist(config, obj, mctx,
892                                                          &addrs, &keynames,
893                                                          &count));
894                         result = dns_zone_setmasterswithkeys(zone, addrs,
895                                                              keynames, count);
896                         ns_config_putipandkeylist(mctx, &addrs, &keynames,
897                                                   count);
898                 } else
899                         result = dns_zone_setmasters(zone, NULL, 0);
900                 RETERR(result);
901
902                 multi = ISC_FALSE;
903                 if (count > 1) {
904                         obj = NULL;
905                         result = ns_config_get(maps, "multi-master", &obj);
906                         INSIST(result == ISC_R_SUCCESS);
907                         multi = cfg_obj_asboolean(obj);
908                 }
909                 dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);
910
911                 obj = NULL;
912                 result = ns_config_get(maps, "max-transfer-time-in", &obj);
913                 INSIST(result == ISC_R_SUCCESS);
914                 dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
915
916                 obj = NULL;
917                 result = ns_config_get(maps, "max-transfer-idle-in", &obj);
918                 INSIST(result == ISC_R_SUCCESS);
919                 dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
920
921                 obj = NULL;
922                 result = ns_config_get(maps, "max-refresh-time", &obj);
923                 INSIST(result == ISC_R_SUCCESS);
924                 dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
925
926                 obj = NULL;
927                 result = ns_config_get(maps, "min-refresh-time", &obj);
928                 INSIST(result == ISC_R_SUCCESS);
929                 dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
930
931                 obj = NULL;
932                 result = ns_config_get(maps, "max-retry-time", &obj);
933                 INSIST(result == ISC_R_SUCCESS);
934                 dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
935
936                 obj = NULL;
937                 result = ns_config_get(maps, "min-retry-time", &obj);
938                 INSIST(result == ISC_R_SUCCESS);
939                 dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
940
941                 obj = NULL;
942                 result = ns_config_get(maps, "transfer-source", &obj);
943                 INSIST(result == ISC_R_SUCCESS);
944                 RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
945                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
946
947                 obj = NULL;
948                 result = ns_config_get(maps, "transfer-source-v6", &obj);
949                 INSIST(result == ISC_R_SUCCESS);
950                 RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
951                 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
952
953                 obj = NULL;
954                 result = ns_config_get(maps, "alt-transfer-source", &obj);
955                 INSIST(result == ISC_R_SUCCESS);
956                 RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));
957
958                 obj = NULL;
959                 result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
960                 INSIST(result == ISC_R_SUCCESS);
961                 RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));
962
963                 obj = NULL;
964                 (void)ns_config_get(maps, "use-alt-transfer-source", &obj);
965                 if (obj == NULL) {
966                         /*
967                          * Default off when views are in use otherwise
968                          * on for BIND 8 compatibility.
969                          */
970                         view = dns_zone_getview(zone);
971                         if (view != NULL && strcmp(view->name, "_default") == 0)
972                                 alt = ISC_TRUE;
973                         else
974                                 alt = ISC_FALSE;
975                 } else
976                         alt = cfg_obj_asboolean(obj);
977                 dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);
978
979                 obj = NULL;
980                 (void)ns_config_get(maps, "try-tcp-refresh", &obj);
981                 dns_zone_setoption(zone, DNS_ZONEOPT_TRYTCPREFRESH,
982                                    cfg_obj_asboolean(obj));
983                 break;
984
985         default:
986                 break;
987         }
988
989         return (ISC_R_SUCCESS);
990 }
991
992 isc_boolean_t
993 ns_zone_reusable(dns_zone_t *zone, const cfg_obj_t *zconfig) {
994         const cfg_obj_t *zoptions = NULL;
995         const cfg_obj_t *obj = NULL;
996         const char *cfilename;
997         const char *zfilename;
998
999         zoptions = cfg_tuple_get(zconfig, "options");
1000
1001         if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone))
1002                 return (ISC_FALSE);
1003
1004         obj = NULL;
1005         (void)cfg_map_get(zoptions, "file", &obj);
1006         if (obj != NULL)
1007                 cfilename = cfg_obj_asstring(obj);
1008         else
1009                 cfilename = NULL;
1010         zfilename = dns_zone_getfile(zone);
1011         if (!((cfilename == NULL && zfilename == NULL) ||
1012               (cfilename != NULL && zfilename != NULL &&
1013                strcmp(cfilename, zfilename) == 0)))
1014             return (ISC_FALSE);
1015
1016         return (ISC_TRUE);
1017 }