2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
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.
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.
18 /* $Id: zoneconf.c,v 1.87.2.6 2004/03/09 06:09:20 marka Exp $ */
22 #include <isc/buffer.h>
24 #include <isc/string.h> /* Required for HP/UX (and others?) */
28 #include <dns/fixedname.h>
31 #include <dns/rdatatype.h>
35 #include <named/config.h>
36 #include <named/globals.h>
37 #include <named/log.h>
38 #include <named/server.h>
39 #include <named/zoneconf.h>
42 * These are BIND9 server defaults, not necessarily identical to the
43 * library defaults defined in zone.c.
45 #define RETERR(x) do { \
46 isc_result_t _r = (x); \
47 if (_r != ISC_R_SUCCESS) \
52 * Convenience function for configuring a single zone ACL.
55 configure_zone_acl(cfg_obj_t *zconfig, cfg_obj_t *vconfig, cfg_obj_t *config,
56 const char *aclname, ns_aclconfctx_t *actx,
58 void (*setzacl)(dns_zone_t *, dns_acl_t *),
59 void (*clearzacl)(dns_zone_t *))
63 cfg_obj_t *aclobj = NULL;
65 dns_acl_t *dacl = NULL;
68 maps[i++] = cfg_tuple_get(zconfig, "options");
70 maps[i++] = cfg_tuple_get(vconfig, "options");
72 cfg_obj_t *options = NULL;
73 (void)cfg_map_get(config, "options", &options);
79 result = ns_config_get(maps, aclname, &aclobj);
82 return (ISC_R_SUCCESS);
85 result = ns_acl_fromconfig(aclobj, config, actx,
86 dns_zone_getmctx(zone), &dacl);
87 if (result != ISC_R_SUCCESS)
89 (*setzacl)(zone, dacl);
90 dns_acl_detach(&dacl);
91 return (ISC_R_SUCCESS);
95 * Parse the zone update-policy statement.
98 configure_zone_ssutable(cfg_obj_t *zconfig, dns_zone_t *zone) {
99 cfg_obj_t *updatepolicy = NULL;
100 cfg_listelt_t *element, *element2;
101 dns_ssutable_t *table = NULL;
102 isc_mem_t *mctx = dns_zone_getmctx(zone);
105 (void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
106 if (updatepolicy == NULL)
107 return (ISC_R_SUCCESS);
109 result = dns_ssutable_create(mctx, &table);
110 if (result != ISC_R_SUCCESS)
113 for (element = cfg_list_first(updatepolicy);
115 element = cfg_list_next(element))
117 cfg_obj_t *stmt = cfg_listelt_value(element);
118 cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
119 cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
120 cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
121 cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
122 cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
124 isc_boolean_t grant = ISC_FALSE;
125 unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
126 dns_fixedname_t fname, fident;
128 dns_rdatatype_t *types;
131 str = cfg_obj_asstring(mode);
132 if (strcasecmp(str, "grant") == 0)
134 else if (strcasecmp(str, "deny") == 0)
139 str = cfg_obj_asstring(matchtype);
140 if (strcasecmp(str, "name") == 0)
141 mtype = DNS_SSUMATCHTYPE_NAME;
142 else if (strcasecmp(str, "subdomain") == 0)
143 mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
144 else if (strcasecmp(str, "wildcard") == 0)
145 mtype = DNS_SSUMATCHTYPE_WILDCARD;
146 else if (strcasecmp(str, "self") == 0)
147 mtype = DNS_SSUMATCHTYPE_SELF;
151 dns_fixedname_init(&fident);
152 str = cfg_obj_asstring(identity);
153 isc_buffer_init(&b, str, strlen(str));
154 isc_buffer_add(&b, strlen(str));
155 result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
156 dns_rootname, ISC_FALSE, NULL);
157 if (result != ISC_R_SUCCESS) {
158 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
159 "'%s' is not a valid name", str);
163 dns_fixedname_init(&fname);
164 str = cfg_obj_asstring(dname);
165 isc_buffer_init(&b, str, strlen(str));
166 isc_buffer_add(&b, strlen(str));
167 result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
168 dns_rootname, ISC_FALSE, NULL);
169 if (result != ISC_R_SUCCESS) {
170 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
171 "'%s' is not a valid name", str);
175 n = ns_config_listcount(typelist);
179 types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
181 result = ISC_R_NOMEMORY;
187 for (element2 = cfg_list_first(typelist);
189 element2 = cfg_list_next(element2))
196 typeobj = cfg_listelt_value(element2);
197 str = cfg_obj_asstring(typeobj);
199 r.length = strlen(str);
201 result = dns_rdatatype_fromtext(&types[i++], &r);
202 if (result != ISC_R_SUCCESS) {
203 cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
204 "'%s' is not a valid type", str);
205 isc_mem_put(mctx, types,
206 n * sizeof(dns_rdatatype_t));
212 result = dns_ssutable_addrule(table, grant,
213 dns_fixedname_name(&fident),
215 dns_fixedname_name(&fname),
218 isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
219 if (result != ISC_R_SUCCESS) {
225 result = ISC_R_SUCCESS;
226 dns_zone_setssutable(zone, table);
229 dns_ssutable_detach(&table);
234 * Convert a config file zone type into a server zone type.
236 static inline dns_zonetype_t
237 zonetype_fromconfig(cfg_obj_t *map) {
238 cfg_obj_t *obj = NULL;
241 result = cfg_map_get(map, "type", &obj);
242 INSIST(result == ISC_R_SUCCESS);
243 return (ns_config_getzonetype(obj));
247 * Helper function for strtoargv(). Pardon the gratuitous recursion.
250 strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
251 char ***argvp, unsigned int n)
255 /* Discard leading whitespace. */
256 while (*s == ' ' || *s == '\t')
260 /* We have reached the end of the string. */
262 *argvp = isc_mem_get(mctx, n * sizeof(char *));
264 return (ISC_R_NOMEMORY);
267 while (*p != ' ' && *p != '\t' && *p != '\0')
272 result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
273 if (result != ISC_R_SUCCESS)
277 return (ISC_R_SUCCESS);
281 * Tokenize the string "s" into whitespace-separated words,
282 * return the number of words in '*argcp' and an array
283 * of pointers to the words in '*argvp'. The caller
284 * must free the array using isc_mem_put(). The string
285 * is modified in-place.
288 strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
289 return (strtoargvsub(mctx, s, argcp, argvp, 0));
293 ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig,
294 ns_aclconfctx_t *ac, dns_zone_t *zone)
298 dns_rdataclass_t zclass;
299 dns_rdataclass_t vclass;
301 cfg_obj_t *zoptions = NULL;
302 cfg_obj_t *options = NULL;
304 const char *filename = NULL;
305 dns_notifytype_t notifytype = dns_notifytype_yes;
306 isc_sockaddr_t *addrs;
307 dns_name_t **keynames;
312 static char default_dbtype[] = "rbt";
313 isc_mem_t *mctx = dns_zone_getmctx(zone);
314 dns_dialuptype_t dialup = dns_dialuptype_no;
315 dns_zonetype_t ztype;
319 if (zconfig != NULL) {
320 zoptions = cfg_tuple_get(zconfig, "options");
321 maps[i++] = zoptions;
324 maps[i++] = cfg_tuple_get(vconfig, "options");
325 if (config != NULL) {
326 (void)cfg_map_get(config, "options", &options);
330 maps[i++] = ns_g_defaults;
334 RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
335 dns_rdataclass_in, &vclass));
337 vclass = dns_rdataclass_in;
340 * Configure values common to all zone types.
343 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
345 RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
347 dns_zone_setclass(zone, zclass);
349 ztype = zonetype_fromconfig(zoptions);
350 dns_zone_settype(zone, ztype);
353 result = cfg_map_get(zoptions, "database", &obj);
354 if (result == ISC_R_SUCCESS)
355 cpval = cfg_obj_asstring(obj);
357 cpval = default_dbtype;
358 RETERR(strtoargv(mctx, cpval, &dbargc, &dbargv));
360 * ANSI C is strange here. There is no logical reason why (char **)
361 * cannot be promoted automatically to (const char * const *) by the
362 * compiler w/o generating a warning.
364 RETERR(dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv));
365 isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
368 result = cfg_map_get(zoptions, "file", &obj);
369 if (result == ISC_R_SUCCESS)
370 filename = cfg_obj_asstring(obj);
371 RETERR(dns_zone_setfile(zone, filename));
373 if (ztype == dns_zone_slave)
374 RETERR(configure_zone_acl(zconfig, vconfig, config,
375 "allow-notify", ac, zone,
376 dns_zone_setnotifyacl,
377 dns_zone_clearnotifyacl));
379 * XXXAG This probably does not make sense for stubs.
381 RETERR(configure_zone_acl(zconfig, vconfig, config,
382 "allow-query", ac, zone,
383 dns_zone_setqueryacl,
384 dns_zone_clearqueryacl));
387 result = ns_config_get(maps, "dialup", &obj);
388 INSIST(result == ISC_R_SUCCESS);
389 if (cfg_obj_isboolean(obj)) {
390 if (cfg_obj_asboolean(obj))
391 dialup = dns_dialuptype_yes;
393 dialup = dns_dialuptype_no;
395 char *dialupstr = cfg_obj_asstring(obj);
396 if (strcasecmp(dialupstr, "notify") == 0)
397 dialup = dns_dialuptype_notify;
398 else if (strcasecmp(dialupstr, "notify-passive") == 0)
399 dialup = dns_dialuptype_notifypassive;
400 else if (strcasecmp(dialupstr, "refresh") == 0)
401 dialup = dns_dialuptype_refresh;
402 else if (strcasecmp(dialupstr, "passive") == 0)
403 dialup = dns_dialuptype_passive;
407 dns_zone_setdialup(zone, dialup);
410 result = ns_config_get(maps, "zone-statistics", &obj);
411 INSIST(result == ISC_R_SUCCESS);
412 dns_zone_setstatistics(zone, cfg_obj_asboolean(obj));
415 * Configure master functionality. This applies
416 * to primary masters (type "master") and slaves
417 * acting as masters (type "slave"), but not to stubs.
419 if (ztype != dns_zone_stub) {
421 result = ns_config_get(maps, "notify", &obj);
422 INSIST(result == ISC_R_SUCCESS);
423 if (cfg_obj_isboolean(obj)) {
424 if (cfg_obj_asboolean(obj))
425 notifytype = dns_notifytype_yes;
427 notifytype = dns_notifytype_no;
429 char *notifystr = cfg_obj_asstring(obj);
430 if (strcasecmp(notifystr, "explicit") == 0)
431 notifytype = dns_notifytype_explicit;
435 dns_zone_setnotifytype(zone, notifytype);
438 result = ns_config_get(maps, "also-notify", &obj);
439 if (result == ISC_R_SUCCESS) {
440 isc_sockaddr_t *addrs = NULL;
441 isc_uint32_t addrcount;
442 result = ns_config_getiplist(config, obj, 0, mctx,
444 if (result != ISC_R_SUCCESS)
446 result = dns_zone_setalsonotify(zone, addrs,
448 ns_config_putiplist(mctx, &addrs, addrcount);
449 if (result != ISC_R_SUCCESS)
452 RETERR(dns_zone_setalsonotify(zone, NULL, 0));
455 result = ns_config_get(maps, "notify-source", &obj);
456 INSIST(result == ISC_R_SUCCESS);
457 dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj));
458 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
461 result = ns_config_get(maps, "notify-source-v6", &obj);
462 INSIST(result == ISC_R_SUCCESS);
463 dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj));
464 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
466 RETERR(configure_zone_acl(zconfig, vconfig, config,
467 "allow-transfer", ac, zone,
469 dns_zone_clearxfracl));
472 result = ns_config_get(maps, "max-transfer-time-out", &obj);
473 INSIST(result == ISC_R_SUCCESS);
474 dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
477 result = ns_config_get(maps, "max-transfer-idle-out", &obj);
478 INSIST(result == ISC_R_SUCCESS);
479 dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
483 * Configure update-related options. These apply to
484 * primary masters only.
486 if (ztype == dns_zone_master) {
487 dns_acl_t *updateacl;
488 RETERR(configure_zone_acl(zconfig, vconfig, config,
489 "allow-update", ac, zone,
490 dns_zone_setupdateacl,
491 dns_zone_clearupdateacl));
493 updateacl = dns_zone_getupdateacl(zone);
494 if (updateacl != NULL && dns_acl_isinsecure(updateacl))
495 isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
496 NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
497 "zone '%s' allows updates by IP "
498 "address, which is insecure",
501 RETERR(configure_zone_ssutable(zoptions, zone));
504 result = ns_config_get(maps, "sig-validity-interval", &obj);
505 INSIST(result == ISC_R_SUCCESS);
506 dns_zone_setsigvalidityinterval(zone,
507 cfg_obj_asuint32(obj) * 86400);
508 } else if (ztype == dns_zone_slave) {
509 RETERR(configure_zone_acl(zconfig, vconfig, config,
510 "allow-update-forwarding", ac, zone,
511 dns_zone_setforwardacl,
512 dns_zone_clearforwardacl));
516 * Configure slave functionality.
522 result = cfg_map_get(zoptions, "masters", &obj);
526 RETERR(ns_config_getipandkeylist(config, obj, mctx,
529 result = dns_zone_setmasterswithkeys(zone, addrs,
531 ns_config_putipandkeylist(mctx, &addrs, &keynames,
534 result = dns_zone_setmasters(zone, NULL, 0);
538 result = ns_config_get(maps, "max-transfer-time-in", &obj);
539 INSIST(result == ISC_R_SUCCESS);
540 dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
543 result = ns_config_get(maps, "max-transfer-idle-in", &obj);
544 INSIST(result == ISC_R_SUCCESS);
545 dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
548 result = ns_config_get(maps, "max-refresh-time", &obj);
549 INSIST(result == ISC_R_SUCCESS);
550 dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
553 result = ns_config_get(maps, "min-refresh-time", &obj);
554 INSIST(result == ISC_R_SUCCESS);
555 dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
558 result = ns_config_get(maps, "max-retry-time", &obj);
559 INSIST(result == ISC_R_SUCCESS);
560 dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
563 result = ns_config_get(maps, "min-retry-time", &obj);
564 INSIST(result == ISC_R_SUCCESS);
565 dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
568 result = ns_config_get(maps, "transfer-source", &obj);
569 INSIST(result == ISC_R_SUCCESS);
570 dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj));
571 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
574 result = ns_config_get(maps, "transfer-source-v6", &obj);
575 INSIST(result == ISC_R_SUCCESS);
576 dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj));
577 ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
585 return (ISC_R_SUCCESS);
589 ns_zone_reusable(dns_zone_t *zone, cfg_obj_t *zconfig) {
590 cfg_obj_t *zoptions = NULL;
591 cfg_obj_t *obj = NULL;
592 const char *cfilename;
593 const char *zfilename;
595 zoptions = cfg_tuple_get(zconfig, "options");
597 if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone))
601 (void)cfg_map_get(zoptions, "file", &obj);
603 cfilename = cfg_obj_asstring(obj);
606 zfilename = dns_zone_getfile(zone);
607 if (!((cfilename == NULL && zfilename == NULL) ||
608 (cfilename != NULL && zfilename != NULL &&
609 strcmp(cfilename, zfilename) == 0)))