zoneconf.c 20.9 KB
Newer Older
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
 * Copyright (C) 2004, 2005  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 1999-2003  Internet Software Consortium.
4
 *
5 6 7
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
8
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
16 17
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: zoneconf.c,v 1.116 2005/01/10 23:43:17 marka Exp $ */
David Lawrence's avatar
David Lawrence committed
19

20 21
#include <config.h>

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?) */
Bob Halley's avatar
Bob Halley committed
27
#include <isc/util.h>
28

29
#include <dns/acl.h>
30
#include <dns/fixedname.h>
31
#include <dns/log.h>
32 33
#include <dns/name.h>
#include <dns/rdatatype.h>
Mark Andrews's avatar
Mark Andrews committed
34
#include <dns/ssu.h>
35
#include <dns/view.h>
36
#include <dns/zone.h>
37

38
#include <named/config.h>
39 40
#include <named/globals.h>
#include <named/log.h>
41
#include <named/server.h>
42
#include <named/zoneconf.h>
43

44 45 46 47 48 49 50 51 52 53
/*
 * These are BIND9 server defaults, not necessarily identical to the
 * library defaults defined in zone.c.
 */
#define RETERR(x) do { \
	isc_result_t _r = (x); \
	if (_r != ISC_R_SUCCESS) \
		return (_r); \
	} while (0)

54 55 56 57
/*
 * Convenience function for configuring a single zone ACL.
 */
static isc_result_t
58 59 60
configure_zone_acl(cfg_obj_t *zconfig, cfg_obj_t *vconfig, cfg_obj_t *config,
		   const char *aclname, ns_aclconfctx_t *actx,
		   dns_zone_t *zone, 
61 62 63 64
		   void (*setzacl)(dns_zone_t *, dns_acl_t *),
		   void (*clearzacl)(dns_zone_t *))
{
	isc_result_t result;
65 66 67
	cfg_obj_t *maps[4];
	cfg_obj_t *aclobj = NULL;
	int i = 0;
68
	dns_acl_t *dacl = NULL;
69 70 71 72 73 74 75 76 77 78

	if (zconfig != NULL)
		maps[i++] = cfg_tuple_get(zconfig, "options");
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		cfg_obj_t *options = NULL;
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL)
			maps[i++] = options;
79
	}
80 81 82 83
	maps[i] = NULL;

	result = ns_config_get(maps, aclname, &aclobj);
	if (aclobj == NULL) {
84 85 86
		(*clearzacl)(zone);
		return (ISC_R_SUCCESS);
	}
87 88 89 90 91 92 93 94

	result = ns_acl_fromconfig(aclobj, config, actx,
				   dns_zone_getmctx(zone), &dacl);
	if (result != ISC_R_SUCCESS)
		return (result);
	(*setzacl)(zone, dacl);
	dns_acl_detach(&dacl);
	return (ISC_R_SUCCESS);
95 96
}

97
/*
98
 * Parse the zone update-policy statement.
99
 */
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
static isc_result_t
configure_zone_ssutable(cfg_obj_t *zconfig, dns_zone_t *zone) {
	cfg_obj_t *updatepolicy = NULL;
	cfg_listelt_t *element, *element2;
	dns_ssutable_t *table = NULL;
	isc_mem_t *mctx = dns_zone_getmctx(zone);
	isc_result_t result;

	(void)cfg_map_get(zconfig, "update-policy", &updatepolicy);
	if (updatepolicy == NULL)
		return (ISC_R_SUCCESS);

	result = dns_ssutable_create(mctx, &table);
	if (result != ISC_R_SUCCESS)
		return (result);

	for (element = cfg_list_first(updatepolicy);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		cfg_obj_t *stmt = cfg_listelt_value(element);
		cfg_obj_t *mode = cfg_tuple_get(stmt, "mode");
		cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
		cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
		cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
		cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
		char *str;
127 128
		isc_boolean_t grant = ISC_FALSE;
		unsigned int mtype = DNS_SSUMATCHTYPE_NAME;
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
		dns_fixedname_t fname, fident;
		isc_buffer_t b;
		dns_rdatatype_t *types;
		unsigned int i, n;

		str = cfg_obj_asstring(mode);
		if (strcasecmp(str, "grant") == 0)
			grant = ISC_TRUE;
		else if (strcasecmp(str, "deny") == 0)
			grant = ISC_FALSE;
		else
			INSIST(0);

		str = cfg_obj_asstring(matchtype);
		if (strcasecmp(str, "name") == 0)
			mtype = DNS_SSUMATCHTYPE_NAME;
		else if (strcasecmp(str, "subdomain") == 0)
			mtype = DNS_SSUMATCHTYPE_SUBDOMAIN;
		else if (strcasecmp(str, "wildcard") == 0)
			mtype = DNS_SSUMATCHTYPE_WILDCARD;
		else if (strcasecmp(str, "self") == 0)
			mtype = DNS_SSUMATCHTYPE_SELF;
		else
			INSIST(0);

		dns_fixedname_init(&fident);
		str = cfg_obj_asstring(identity);
		isc_buffer_init(&b, str, strlen(str));
		isc_buffer_add(&b, strlen(str));
		result = dns_name_fromtext(dns_fixedname_name(&fident), &b,
					   dns_rootname, ISC_FALSE, NULL);
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
				    "'%s' is not a valid name", str);
			goto cleanup;
		}

		dns_fixedname_init(&fname);
		str = cfg_obj_asstring(dname);
		isc_buffer_init(&b, str, strlen(str));
		isc_buffer_add(&b, strlen(str));
		result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
					   dns_rootname, ISC_FALSE, NULL);
		if (result != ISC_R_SUCCESS) {
			cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
				    "'%s' is not a valid name", str);
			goto cleanup;
		}

		n = ns_config_listcount(typelist);
		if (n == 0)
			types = NULL;
		else {
			types = isc_mem_get(mctx, n * sizeof(dns_rdatatype_t));
			if (types == NULL) {
				result = ISC_R_NOMEMORY;
				goto cleanup;
			}
		}

		i = 0;
		for (element2 = cfg_list_first(typelist);
		     element2 != NULL;
		     element2 = cfg_list_next(element2))
		{
			cfg_obj_t *typeobj;
			isc_textregion_t r;

			INSIST(i < n);

			typeobj = cfg_listelt_value(element2);
			str = cfg_obj_asstring(typeobj);
			r.base = str;
			r.length = strlen(str);

			result = dns_rdatatype_fromtext(&types[i++], &r);
			if (result != ISC_R_SUCCESS) {
				cfg_obj_log(identity, ns_g_lctx, ISC_LOG_ERROR,
					    "'%s' is not a valid type", str);
				isc_mem_put(mctx, types,
					    n * sizeof(dns_rdatatype_t));
				goto cleanup;
			}
		}
		INSIST(i == n);

		result = dns_ssutable_addrule(table, grant,
					      dns_fixedname_name(&fident),
					      mtype,
					      dns_fixedname_name(&fname),
					      n, types);
		if (types != NULL)
			isc_mem_put(mctx, types, n * sizeof(dns_rdatatype_t));
		if (result != ISC_R_SUCCESS) {
			goto cleanup;
		}

226
	}
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

	result = ISC_R_SUCCESS;
	dns_zone_setssutable(zone, table);

 cleanup:
	dns_ssutable_detach(&table);
	return (result);
}

/*
 * Convert a config file zone type into a server zone type.
 */
static inline dns_zonetype_t
zonetype_fromconfig(cfg_obj_t *map) {
	cfg_obj_t *obj = NULL;
	isc_result_t result;

	result = cfg_map_get(map, "type", &obj);
	INSIST(result == ISC_R_SUCCESS);
	return (ns_config_getzonetype(obj));
247 248
}

249 250 251 252
/*
 * Helper function for strtoargv().  Pardon the gratuitous recursion.
 */
static isc_result_t
Andreas Gustafsson's avatar
Andreas Gustafsson committed
253 254 255
strtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp,
	     char ***argvp, unsigned int n)
{
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
	isc_result_t result;
	
	/* Discard leading whitespace. */
	while (*s == ' ' || *s == '\t')
		s++;
	
	if (*s == '\0') {
		/* We have reached the end of the string. */
		*argcp = n;
		*argvp = isc_mem_get(mctx, n * sizeof(char *));
		if (*argvp == NULL)
			return (ISC_R_NOMEMORY);
	} else {
		char *p = s;
		while (*p != ' ' && *p != '\t' && *p != '\0')
			p++;
		if (*p != '\0')
			*p++ = '\0';

		result = strtoargvsub(mctx, p, argcp, argvp, n + 1);
		if (result != ISC_R_SUCCESS)
			return (result);
		(*argvp)[n] = s;
	}
	return (ISC_R_SUCCESS);
}

/*
 * Tokenize the string "s" into whitespace-separated words,
 * return the number of words in '*argcp' and an array
 * of pointers to the words in '*argvp'.  The caller
 * must free the array using isc_mem_put().  The string
 * is modified in-place.
 */
static isc_result_t
Andreas Gustafsson's avatar
Andreas Gustafsson committed
291
strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, char ***argvp) {
292 293 294
	return (strtoargvsub(mctx, s, argcp, argvp, 0));
}

295 296 297
static void
checknames(dns_zonetype_t ztype, cfg_obj_t **maps, cfg_obj_t **objp) {
	const char *zone = NULL;
298
	isc_result_t result;
299 300 301 302 303 304 305

	switch (ztype) {
	case dns_zone_slave: zone = "slave"; break;
	case dns_zone_master: zone = "master"; break;
	default:
		INSIST(0);
	}
306 307
	result = ns_checknames_get(maps, zone, objp);
	INSIST(result == ISC_R_SUCCESS);
308 309
}

310
isc_result_t
311 312
ns_zone_configure(cfg_obj_t *config, cfg_obj_t *vconfig, cfg_obj_t *zconfig,
		  ns_aclconfctx_t *ac, dns_zone_t *zone)
313 314
{
	isc_result_t result;
315 316
	char *zname;
	dns_rdataclass_t zclass;
317
	dns_rdataclass_t vclass;
318 319 320 321
	cfg_obj_t *maps[5];
	cfg_obj_t *zoptions = NULL;
	cfg_obj_t *options = NULL;
	cfg_obj_t *obj;
322
	const char *filename = NULL;
323
	dns_notifytype_t notifytype = dns_notifytype_yes;
324 325 326
	isc_sockaddr_t *addrs;
	dns_name_t **keynames;
	isc_uint32_t count;
327 328 329 330 331
	char *cpval;
	unsigned int dbargc;
	char **dbargv;
	static char default_dbtype[] = "rbt";
	isc_mem_t *mctx = dns_zone_getmctx(zone);
332
	dns_dialuptype_t dialup = dns_dialuptype_no;
333 334
	dns_zonetype_t ztype;
	int i;
335
	isc_int32_t journal_size;
336
	isc_boolean_t multi;
337 338
	isc_boolean_t alt;
	dns_view_t *view;
339
	isc_boolean_t check = ISC_FALSE, fail = ISC_FALSE;
340
	isc_boolean_t ixfrdiff;
Michael Graff's avatar
Michael Graff committed
341

342 343 344 345 346 347 348 349 350 351 352 353 354 355
	i = 0;
	if (zconfig != NULL) {
		zoptions = cfg_tuple_get(zconfig, "options");
		maps[i++] = zoptions;
	}
	if (vconfig != NULL)
		maps[i++] = cfg_tuple_get(vconfig, "options");
	if (config != NULL) {
		(void)cfg_map_get(config, "options", &options);
		if (options != NULL)
			maps[i++] = options;
	}
	maps[i++] = ns_g_defaults;
	maps[i++] = NULL;
356 357 358 359 360 361 362

	if (vconfig != NULL)
		RETERR(ns_config_getclass(cfg_tuple_get(vconfig, "class"),
					  dns_rdataclass_in, &vclass));
	else
		vclass = dns_rdataclass_in;

363 364 365
	/*
	 * Configure values common to all zone types.
	 */
366

367
	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
368

369 370
	RETERR(ns_config_getclass(cfg_tuple_get(zconfig, "class"),
				  vclass, &zclass));
371
	dns_zone_setclass(zone, zclass);
372

373 374 375 376 377 378 379 380
	ztype = zonetype_fromconfig(zoptions);
	dns_zone_settype(zone, ztype);

	obj = NULL;
	result = cfg_map_get(zoptions, "database", &obj);
	if (result == ISC_R_SUCCESS)
		cpval = cfg_obj_asstring(obj);
	else
381 382
		cpval = default_dbtype;
	RETERR(strtoargv(mctx, cpval, &dbargc, &dbargv));
383 384 385 386 387 388
	/*
	 * ANSI C is strange here.  There is no logical reason why (char **)
	 * cannot be promoted automatically to (const char * const *) by the
	 * compiler w/o generating a warning.
	 */
	RETERR(dns_zone_setdbtype(zone, dbargc, (const char * const *)dbargv));
389
	isc_mem_put(mctx, dbargv, dbargc * sizeof(*dbargv));
390

391 392 393 394
	obj = NULL;
	result = cfg_map_get(zoptions, "file", &obj);
	if (result == ISC_R_SUCCESS)
		filename = cfg_obj_asstring(obj);
395
	RETERR(dns_zone_setfile(zone, filename));
396

397 398 399 400 401
	obj = NULL;
	result = cfg_map_get(zoptions, "journal", &obj);
	if (result == ISC_R_SUCCESS)
		RETERR(dns_zone_setjournal(zone, cfg_obj_asstring(obj)));

402 403 404
	if (ztype == dns_zone_slave)
		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  "allow-notify", ac, zone,
405 406
					  dns_zone_setnotifyacl,
					  dns_zone_clearnotifyacl));
407 408 409
	/*
	 * XXXAG This probably does not make sense for stubs.
	 */
410 411
	RETERR(configure_zone_acl(zconfig, vconfig, config,
				  "allow-query", ac, zone,
412 413 414
				  dns_zone_setqueryacl,
				  dns_zone_clearqueryacl));

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
	obj = NULL;
	result = ns_config_get(maps, "dialup", &obj);
	INSIST(result == ISC_R_SUCCESS);
	if (cfg_obj_isboolean(obj)) {
		if (cfg_obj_asboolean(obj))
			dialup = dns_dialuptype_yes;
		else
			dialup = dns_dialuptype_no;
	} else {
		char *dialupstr = cfg_obj_asstring(obj);
		if (strcasecmp(dialupstr, "notify") == 0)
			dialup = dns_dialuptype_notify;
		else if (strcasecmp(dialupstr, "notify-passive") == 0)
			dialup = dns_dialuptype_notifypassive;
		else if (strcasecmp(dialupstr, "refresh") == 0)
			dialup = dns_dialuptype_refresh;
		else if (strcasecmp(dialupstr, "passive") == 0)
			dialup = dns_dialuptype_passive;
		else
			INSIST(0);
	}
436
	dns_zone_setdialup(zone, dialup);
437

438 439 440
	obj = NULL;
	result = ns_config_get(maps, "zone-statistics", &obj);
	INSIST(result == ISC_R_SUCCESS);
441
	RETERR(dns_zone_setstatistics(zone, cfg_obj_asboolean(obj)));
442

443 444 445 446 447
	/*
	 * Configure master functionality.  This applies
	 * to primary masters (type "master") and slaves
	 * acting as masters (type "slave"), but not to stubs.
	 */
448 449 450 451 452 453 454 455 456 457 458 459 460
	if (ztype != dns_zone_stub) {
		obj = NULL;
		result = ns_config_get(maps, "notify", &obj);
		INSIST(result == ISC_R_SUCCESS);
		if (cfg_obj_isboolean(obj)) {
			if (cfg_obj_asboolean(obj))
				notifytype = dns_notifytype_yes;
			else
				notifytype = dns_notifytype_no;
		} else {
			char *notifystr = cfg_obj_asstring(obj);
			if (strcasecmp(notifystr, "explicit") == 0)
				notifytype = dns_notifytype_explicit;
461 462
			else if (strcasecmp(notifystr, "master-only") == 0)
				notifytype = dns_notifytype_masteronly;
463 464 465
			else
				INSIST(0);
		}
466
		dns_zone_setnotifytype(zone, notifytype);
467

468 469
		obj = NULL;
		result = ns_config_get(maps, "also-notify", &obj);
470
		if (result == ISC_R_SUCCESS) {
471
			isc_sockaddr_t *addrs = NULL;
472
			isc_uint32_t addrcount;
473 474 475 476 477 478
			result = ns_config_getiplist(config, obj, 0, mctx,
						     &addrs, &addrcount);
			if (result != ISC_R_SUCCESS)
				return (result);
			result = dns_zone_setalsonotify(zone, addrs,
							addrcount);
479
			ns_config_putiplist(mctx, &addrs, addrcount);
480 481 482
			if (result != ISC_R_SUCCESS)
				return (result);
		} else
483
			RETERR(dns_zone_setalsonotify(zone, NULL, 0));
484

485 486 487
		obj = NULL;
		result = ns_config_get(maps, "notify-source", &obj);
		INSIST(result == ISC_R_SUCCESS);
488
		RETERR(dns_zone_setnotifysrc4(zone, cfg_obj_assockaddr(obj)));
489
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
490

491 492 493
		obj = NULL;
		result = ns_config_get(maps, "notify-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
494
		RETERR(dns_zone_setnotifysrc6(zone, cfg_obj_assockaddr(obj)));
495
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
496

497 498
		RETERR(configure_zone_acl(zconfig, vconfig, config,
					  "allow-transfer", ac, zone,
499 500
					  dns_zone_setxfracl,
					  dns_zone_clearxfracl));
501

502 503 504
		obj = NULL;
		result = ns_config_get(maps, "max-transfer-time-out", &obj);
		INSIST(result == ISC_R_SUCCESS);
505
		dns_zone_setmaxxfrout(zone, cfg_obj_asuint32(obj) * 60);
506

507 508 509
		obj = NULL;
		result = ns_config_get(maps, "max-transfer-idle-out", &obj);
		INSIST(result == ISC_R_SUCCESS);
510
		dns_zone_setidleout(zone, cfg_obj_asuint32(obj) * 60);
511 512

		obj = NULL;
513
		result =  ns_config_get(maps, "max-journal-size", &obj);
514 515 516 517 518 519 520 521 522 523 524 525 526
		INSIST(result == ISC_R_SUCCESS);
		dns_zone_setjournalsize(zone, -1);
		if (cfg_obj_isstring(obj)) {
			const char *str = cfg_obj_asstring(obj);
			INSIST(strcasecmp(str, "unlimited") == 0);
			journal_size = ISC_UINT32_MAX / 2;
		} else {
			isc_resourcevalue_t value;
			value = cfg_obj_asuint64(obj);
			if (value > ISC_UINT32_MAX / 2) {
				cfg_obj_log(obj, ns_g_lctx,
					    ISC_LOG_ERROR,
					    "'max-journal-size "
Andreas Gustafsson's avatar
Andreas Gustafsson committed
527 528
					    "%" ISC_PRINT_QUADFORMAT "d' "
					    "is too large",
529 530
					    value);
				RETERR(ISC_R_RANGE);
531
			}
532 533 534
			journal_size = (isc_uint32_t)value;
		}
		dns_zone_setjournalsize(zone, journal_size);
535 536 537 538

		obj = NULL;
		result = ns_config_get(maps, "ixfr-from-differences", &obj);
		INSIST(result == ISC_R_SUCCESS);
539 540 541 542 543 544 545 546 547 548 549
		if (cfg_obj_isboolean(obj))
			ixfrdiff = cfg_obj_asboolean(obj);
		else if (strcasecmp(cfg_obj_asstring(obj), "master") &&
			 ztype == dns_zone_master)
			ixfrdiff = ISC_TRUE;
		else if (strcasecmp(cfg_obj_asstring(obj), "slave") &&
			ztype == dns_zone_slave)
			ixfrdiff = ISC_TRUE;
		else
			ixfrdiff = ISC_FALSE;
		dns_zone_setoption(zone, DNS_ZONEOPT_IXFRFROMDIFFS, ixfrdiff);
550 551 552 553 554 555 556 557 558 559 560 561 562 563

		checknames(ztype, maps, &obj);
		INSIST(obj != NULL);
		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
			fail = ISC_FALSE;
			check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
			fail = check = ISC_TRUE;
		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
			fail = check = ISC_FALSE;
		} else
			INSIST(0);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMES, check);
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKNAMESFAIL, fail);
564
	}
565

566 567 568 569
	/*
	 * Configure update-related options.  These apply to
	 * primary masters only.
	 */
570
	if (ztype == dns_zone_master) {
571
		dns_acl_t *updateacl;
572
		RETERR(configure_zone_acl(zconfig, vconfig, config,
573
					  "allow-update", ac, zone,
574 575
					  dns_zone_setupdateacl,
					  dns_zone_clearupdateacl));
576 577 578 579 580 581 582
		
		updateacl = dns_zone_getupdateacl(zone);
		if (updateacl != NULL  && dns_acl_isinsecure(updateacl))
			isc_log_write(ns_g_lctx, DNS_LOGCATEGORY_SECURITY,
				      NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
				      "zone '%s' allows updates by IP "
				      "address, which is insecure",
583
				      zname);
584
		
585 586 587 588 589
		RETERR(configure_zone_ssutable(zoptions, zone));

		obj = NULL;
		result = ns_config_get(maps, "sig-validity-interval", &obj);
		INSIST(result == ISC_R_SUCCESS);
590 591
		dns_zone_setsigvalidityinterval(zone,
						cfg_obj_asuint32(obj) * 86400);
592 593 594 595 596 597 598 599 600 601 602 603 604

		obj = NULL;
		result = ns_config_get(maps, "key-directory", &obj);
		if (result == ISC_R_SUCCESS) {
			filename = cfg_obj_asstring(obj);
			if (!isc_file_isabsolute(filename)) {
				cfg_obj_log(obj, ns_g_lctx, ISC_LOG_ERROR,
					    "key-directory '%s' "
					    "is not absolute", filename);
				return (ISC_R_FAILURE);
			}
			RETERR(dns_zone_setkeydirectory(zone, filename));
		}
605 606 607 608 609 610 611
		obj = NULL;
		result = ns_config_get(maps, "check-wildcard", &obj);
		if (result == ISC_R_SUCCESS)
			check = cfg_obj_asboolean(obj);
		else
			check = ISC_FALSE;
		dns_zone_setoption(zone, DNS_ZONEOPT_CHECKWILDCARD, check);
612
	} else if (ztype == dns_zone_slave) {
613
		RETERR(configure_zone_acl(zconfig, vconfig, config,
614
					  "allow-update-forwarding", ac, zone,
615 616
					  dns_zone_setforwardacl,
					  dns_zone_clearforwardacl));
617
	}
618

619 620 621
	/*
	 * Configure slave functionality.
	 */
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
	switch (ztype) {
	case dns_zone_slave:
	case dns_zone_stub:
		obj = NULL;
		result = cfg_map_get(zoptions, "masters", &obj);
		if (obj != NULL) {
			addrs = NULL;
			keynames = NULL;
			RETERR(ns_config_getipandkeylist(config, obj, mctx,
							 &addrs, &keynames,
							 &count));
			result = dns_zone_setmasterswithkeys(zone, addrs,
							     keynames, count);
			ns_config_putipandkeylist(mctx, &addrs, &keynames,
						  count);
637
		} else
638
			result = dns_zone_setmasters(zone, NULL, 0);
639
		RETERR(result);
640

641 642 643 644 645 646 647 648 649
		multi = ISC_FALSE;
		if (count > 1) {
			obj = NULL;
			result = ns_config_get(maps, "multi-master", &obj);
			INSIST(result == ISC_R_SUCCESS);
			multi = cfg_obj_asboolean(obj);
		}
		dns_zone_setoption(zone, DNS_ZONEOPT_MULTIMASTER, multi);

650 651 652
		obj = NULL;
		result = ns_config_get(maps, "max-transfer-time-in", &obj);
		INSIST(result == ISC_R_SUCCESS);
653
		dns_zone_setmaxxfrin(zone, cfg_obj_asuint32(obj) * 60);
654

655 656 657
		obj = NULL;
		result = ns_config_get(maps, "max-transfer-idle-in", &obj);
		INSIST(result == ISC_R_SUCCESS);
658
		dns_zone_setidlein(zone, cfg_obj_asuint32(obj) * 60);
659

660 661 662 663
		obj = NULL;
		result = ns_config_get(maps, "max-refresh-time", &obj);
		INSIST(result == ISC_R_SUCCESS);
		dns_zone_setmaxrefreshtime(zone, cfg_obj_asuint32(obj));
664

665 666 667 668
		obj = NULL;
		result = ns_config_get(maps, "min-refresh-time", &obj);
		INSIST(result == ISC_R_SUCCESS);
		dns_zone_setminrefreshtime(zone, cfg_obj_asuint32(obj));
669

670 671 672 673
		obj = NULL;
		result = ns_config_get(maps, "max-retry-time", &obj);
		INSIST(result == ISC_R_SUCCESS);
		dns_zone_setmaxretrytime(zone, cfg_obj_asuint32(obj));
674

675 676 677 678
		obj = NULL;
		result = ns_config_get(maps, "min-retry-time", &obj);
		INSIST(result == ISC_R_SUCCESS);
		dns_zone_setminretrytime(zone, cfg_obj_asuint32(obj));
679

680 681 682
		obj = NULL;
		result = ns_config_get(maps, "transfer-source", &obj);
		INSIST(result == ISC_R_SUCCESS);
683
		RETERR(dns_zone_setxfrsource4(zone, cfg_obj_assockaddr(obj)));
684
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
685 686 687 688

		obj = NULL;
		result = ns_config_get(maps, "transfer-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
689
		RETERR(dns_zone_setxfrsource6(zone, cfg_obj_assockaddr(obj)));
690
		ns_add_reserved_dispatch(ns_g_server, cfg_obj_assockaddr(obj));
691

692
		obj = NULL;
693
		result = ns_config_get(maps, "alt-transfer-source", &obj);
694 695 696 697 698 699 700 701 702 703 704 705 706
		INSIST(result == ISC_R_SUCCESS);
		RETERR(dns_zone_setaltxfrsource4(zone, cfg_obj_assockaddr(obj)));

		obj = NULL;
		result = ns_config_get(maps, "alt-transfer-source-v6", &obj);
		INSIST(result == ISC_R_SUCCESS);
		RETERR(dns_zone_setaltxfrsource6(zone, cfg_obj_assockaddr(obj)));

		obj = NULL;
		(void)ns_config_get(maps, "use-alt-transfer-source", &obj);
		if (obj == NULL) {
			/*
			 * Default off when views are in use otherwise
707
			 * on for BIND 8 compatibility.
708 709 710 711 712 713 714 715 716 717
			 */
			view = dns_zone_getview(zone);
			if (view != NULL && strcmp(view->name, "_default") == 0)
				alt = ISC_TRUE;
			else
				alt = ISC_FALSE;
		} else
			alt = cfg_obj_asboolean(obj);
		dns_zone_setoption(zone, DNS_ZONEOPT_USEALTXFRSRC, alt);

718
		break;
719

720 721
	default:
		break;
722 723
	}

724
	return (ISC_R_SUCCESS);
725 726
}

727
isc_boolean_t
728 729 730
ns_zone_reusable(dns_zone_t *zone, cfg_obj_t *zconfig) {
	cfg_obj_t *zoptions = NULL;
	cfg_obj_t *obj = NULL;
731 732 733
	const char *cfilename;
	const char *zfilename;

734 735 736
	zoptions = cfg_tuple_get(zconfig, "options");

	if (zonetype_fromconfig(zoptions) != dns_zone_gettype(zone))
737 738
		return (ISC_FALSE);

739 740 741 742 743 744
	obj = NULL;
	(void)cfg_map_get(zoptions, "file", &obj);
	if (obj != NULL)
		cfilename = cfg_obj_asstring(obj);
	else
		cfilename = NULL;
745
	zfilename = dns_zone_getfile(zone);
746
	if (!((cfilename == NULL && zfilename == NULL) ||
747
	      (cfilename != NULL && zfilename != NULL &&
748 749
	       strcmp(cfilename, zfilename) == 0)))
	    return (ISC_FALSE);
750 751 752

	return (ISC_TRUE);
}