config.c 21.5 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2012  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Copyright (C) 2001-2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
6
7
8
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
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
 */

Automatic Updater's avatar
Automatic Updater committed
18
/* $Id: config.c,v 1.123 2012/01/06 23:46:41 tbox Exp $ */
19
20

/*! \file */
Brian Wellington's avatar
Brian Wellington committed
21
22

#include <config.h>
23
24
25
26
27
28

#include <stdlib.h>

#include <isc/buffer.h>
#include <isc/log.h>
#include <isc/mem.h>
29
#include <isc/parseint.h>
30
31
32
#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
Evan Hunt's avatar
Evan Hunt committed
33
#include <isc/string.h>
34
35
#include <isc/util.h>

36
#include <isccfg/namedconf.h>
37
38
39
40

#include <dns/fixedname.h>
#include <dns/name.h>
#include <dns/rdataclass.h>
41
#include <dns/rdatatype.h>
Brian Wellington's avatar
Brian Wellington committed
42
#include <dns/tsig.h>
43
44
#include <dns/zone.h>

45
46
#include <dst/dst.h>

47
48
49
#include <named/config.h>
#include <named/globals.h>

50
51
#include "bind.keys.h"

52
/*% default configuration */
53
54
static char defaultconf[] = "\
options {\n\
55
56
57
#	blackhole {none;};\n"
#ifndef WIN32
"	coresize default;\n\
58
	datasize default;\n\
59
	files unlimited;\n\
60
61
	stacksize default;\n"
#endif
62
63
64
"#	session-keyfile \"" NS_LOCALSTATEDIR "/run/named/session.key\";\n\
	session-keyname local-ddns;\n\
	session-keyalg hmac-sha256;\n\
65
	deallocate-on-exit true;\n\
66
67
68
69
#	directory <none>\n\
	dump-file \"named_dump.db\";\n\
	fake-iquery no;\n\
	has-old-clients false;\n\
70
	heartbeat-interval 60;\n\
71
	host-statistics no;\n\
72
	interface-interval 60;\n\
73
74
	listen-on {any;};\n\
	listen-on-v6 {none;};\n\
75
	match-mapped-addresses no;\n\
76
	max-rsa-exponent-size 0; /* no limit */\n\
77
78
	memstatistics-file \"named.memstats\";\n\
	multiple-cnames no;\n\
79
#	named-xfer <obsolete>;\n\
80
#	pid-file \"" NS_LOCALSTATEDIR "/run/named/named.pid\"; /* or /lwresd.pid */\n\
81
	bindkeys-file \"" NS_SYSCONFDIR "/bind.keys\";\n\
82
	port 53;\n\
83
	recursing-file \"named.recursing\";\n\
84
	secroots-file \"named.secroots\";\n\
85
86
"
#ifdef PATH_RANDOMDEV
87
88
"\
	random-device \"" PATH_RANDOMDEV "\";\n\
89
90
"
#endif
91
92
"\
	recursive-clients 1000;\n\
93
	resolver-query-timeout 10;\n\
94
	rrset-order { order random; };\n\
95
	serial-queries 20;\n\
96
	serial-query-rate 20;\n\
97
	server-id none;\n\
98
	statistics-file \"named.stats\";\n\
99
	statistics-interval 60;\n\
100
	tcp-clients 100;\n\
Michael Graff's avatar
Michael Graff committed
101
	tcp-listen-queue 3;\n\
102
103
104
105
106
107
108
109
110
#	tkey-dhkey <none>\n\
#	tkey-gssapi-credential <none>\n\
#	tkey-domain <none>\n\
	transfers-per-ns 2;\n\
	transfers-in 10;\n\
	transfers-out 10;\n\
	treat-cr-as-space true;\n\
	use-id-pool true;\n\
	use-ixfr true;\n\
111
	edns-udp-size 4096;\n\
112
	max-udp-size 4096;\n\
113
	request-nsid false;\n\
114
	reserved-sockets 512;\n\
115
116
117
\n\
	/* DLV */\n\
	dnssec-lookaside . trust-anchor dlv.isc.org;\n\
118
119
120
121
\n\
	/* view */\n\
	allow-notify {none;};\n\
	allow-update-forwarding {none;};\n\
122
	allow-query-cache { localnets; localhost; };\n\
123
	allow-query-cache-on { any; };\n\
124
	allow-recursion { localnets; localhost; };\n\
125
	allow-recursion-on { any; };\n\
126
#	allow-v6-synthesis <obsolete>;\n\
127
128
129
#	sortlist <none>\n\
#	topology <none>\n\
	auth-nxdomain false;\n\
Bob Halley's avatar
Bob Halley committed
130
	minimal-responses false;\n\
131
132
133
134
135
136
137
138
139
140
141
	recursion true;\n\
	provide-ixfr true;\n\
	request-ixfr true;\n\
	fetch-glue no;\n\
	rfc2308-type1 no;\n\
	additional-from-auth true;\n\
	additional-from-cache true;\n\
	query-source address *;\n\
	query-source-v6 address *;\n\
	notify-source *;\n\
	notify-source-v6 *;\n\
142
	cleaning-interval 0;  /* now meaningless */\n\
143
144
145
146
147
	min-roots 2;\n\
	lame-ttl 600;\n\
	max-ncache-ttl 10800; /* 3 hours */\n\
	max-cache-ttl 604800; /* 1 week */\n\
	transfer-format many-answers;\n\
148
	max-cache-size 0;\n\
149
150
	check-names master fail;\n\
	check-names slave warn;\n\
151
	check-names response ignore;\n\
152
	check-dup-records warn;\n\
153
	check-mx warn;\n\
154
	acache-enable no;\n\
155
	acache-cleaning-interval 60;\n\
156
	max-acache-size 16M;\n\
157
	dnssec-enable yes;\n\
158
	dnssec-validation yes; \n\
159
	dnssec-accept-expired no;\n\
160
161
	clients-per-query 10;\n\
	max-clients-per-query 100;\n\
162
	zero-no-soa-ttl-cache no;\n\
163
	nsec3-test-zone no;\n\
164
	allow-new-zones no;\n\
Mark Andrews's avatar
Mark Andrews committed
165
"
Evan Hunt's avatar
Evan Hunt committed
166
#ifdef ALLOW_FILTER_AAAA
167
"	filter-aaaa-on-v4 no;\n\
Evan Hunt's avatar
Evan Hunt committed
168
	filter-aaaa-on-v6 no;\n\
Automatic Updater's avatar
Automatic Updater committed
169
	filter-aaaa { any; };\n\
170
171
"
#endif
Mark Andrews's avatar
Mark Andrews committed
172
173

"	/* zone */\n\
174
	allow-query {any;};\n\
175
	allow-query-on {any;};\n\
176
177
178
	allow-transfer {any;};\n\
	notify yes;\n\
#	also-notify <none>\n\
179
	notify-delay 5;\n\
180
	notify-to-soa no;\n\
181
182
183
184
185
186
187
	dialup no;\n\
#	forward <none>\n\
#	forwarders <none>\n\
	maintain-ixfr-base no;\n\
#	max-ixfr-log-size <obsolete>\n\
	transfer-source *;\n\
	transfer-source-v6 *;\n\
188
	alt-transfer-source *;\n\
189
	alt-transfer-source-v6 *;\n\
190
191
192
193
	max-transfer-time-in 120;\n\
	max-transfer-time-out 120;\n\
	max-transfer-idle-in 60;\n\
	max-transfer-idle-out 60;\n\
194
195
196
197
	max-retry-time 1209600; /* 2 weeks */\n\
	min-retry-time 500;\n\
	max-refresh-time 2419200; /* 4 weeks */\n\
	min-refresh-time 300;\n\
198
	multi-master no;\n\
199
	dnssec-secure-to-insecure no;\n\
200
	sig-validity-interval 30; /* days */\n\
201
202
	sig-signing-nodes 100;\n\
	sig-signing-signatures 10;\n\
203
	sig-signing-type 65534;\n\
204
	inline-signing no;\n\
205
	zone-statistics false;\n\
206
	max-journal-size unlimited;\n\
207
	ixfr-from-differences false;\n\
208
	check-wildcard yes;\n\
209
210
	check-sibling yes;\n\
	check-integrity yes;\n\
211
212
	check-mx-cname warn;\n\
	check-srv-cname warn;\n\
213
	zero-no-soa-ttl yes;\n\
214
	update-check-ksk yes;\n\
215
	serial-update-method increment;\n\
216
	dnssec-update-mode maintain;\n\
217
	dnssec-dnskey-kskonly no;\n\
218
	dnssec-loadkeys-interval 60;\n\
219
	try-tcp-refresh yes; /* BIND 8 compat */\n\
220
};\n\
Mark Andrews's avatar
Mark Andrews committed
221
222
223
"

"#\n\
Mark Andrews's avatar
Mark Andrews committed
224
#  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
225
#\n\
226
227
view \"_bind\" chaos {\n\
	recursion no;\n\
228
	notify no;\n\
229
	allow-new-zones no;\n\
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
\n\
	zone \"version.bind\" chaos {\n\
		type master;\n\
		database \"_builtin version\";\n\
	};\n\
\n\
	zone \"hostname.bind\" chaos {\n\
		type master;\n\
		database \"_builtin hostname\";\n\
	};\n\
\n\
	zone \"authors.bind\" chaos {\n\
		type master;\n\
		database \"_builtin authors\";\n\
	};\n\
245
\n\
246
247
248
249
	zone \"id.server\" chaos {\n\
		type master;\n\
		database \"_builtin id\";\n\
	};\n\
250
};\n\
251
252
253
254
255
256
"
"#\n\
#  Default trusted key(s) for builtin DLV support\n\
#  (used if \"dnssec-lookaside auto;\" is set and\n\
#  sysconfdir/bind.keys doesn't exist).\n\
#\n\
257
# BEGIN MANAGED KEYS\n"
258
259

/* Imported from bind.keys.h: */
260
MANAGED_KEYS
261

262
"# END MANAGED KEYS\n\
263
";
264
265
266
267
268
269
270
271
272
273
274

isc_result_t
ns_config_parsedefaults(cfg_parser_t *parser, cfg_obj_t **conf) {
	isc_buffer_t b;

	isc_buffer_init(&b, defaultconf, sizeof(defaultconf) - 1);
	isc_buffer_add(&b, sizeof(defaultconf) - 1);
	return (cfg_parse_buffer(parser, &b, &cfg_type_namedconf, conf));
}

isc_result_t
275
ns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
276
277
	int i;

278
	for (i = 0;; i++) {
279
280
281
282
283
284
285
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
			return (ISC_R_SUCCESS);
	}
}

286
isc_result_t
287
288
289
290
291
292
293
ns_checknames_get(const cfg_obj_t **maps, const char *which,
		  const cfg_obj_t **obj)
{
	const cfg_listelt_t *element;
	const cfg_obj_t *checknames;
	const cfg_obj_t *type;
	const cfg_obj_t *value;
294
295
296
297
298
299
	int i;

	for (i = 0;; i++) {
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		checknames = NULL;
300
		if (cfg_map_get(maps[i], "check-names",
Automatic Updater's avatar
Automatic Updater committed
301
				&checknames) == ISC_R_SUCCESS) {
302
303
304
305
306
307
308
309
310
311
312
313
			/*
			 * Zone map entry is not a list.
			 */
			if (checknames != NULL && !cfg_obj_islist(checknames)) {
				*obj = checknames;
				return (ISC_R_SUCCESS);
			}
			for (element = cfg_list_first(checknames);
			     element != NULL;
			     element = cfg_list_next(element)) {
				value = cfg_listelt_value(element);
				type = cfg_tuple_get(value, "type");
314
315
				if (strcasecmp(cfg_obj_asstring(type),
					       which) == 0) {
316
317
318
319
320
321
322
323
324
					*obj = cfg_tuple_get(value, "mode");
					return (ISC_R_SUCCESS);
				}
			}

		}
	}
}

325
int
326
327
ns_config_listcount(const cfg_obj_t *list) {
	const cfg_listelt_t *e;
328
329
330
331
332
333
334
335
336
	int i = 0;

	for (e = cfg_list_first(list); e != NULL; e = cfg_list_next(e))
		i++;

	return (i);
}

isc_result_t
337
ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
338
		   dns_rdataclass_t *classp) {
339
	isc_textregion_t r;
340
	isc_result_t result;
341
342

	if (!cfg_obj_isstring(classobj)) {
343
		*classp = defclass;
344
345
		return (ISC_R_SUCCESS);
	}
346
347
	DE_CONST(cfg_obj_asstring(classobj), r.base);
	r.length = strlen(r.base);
348
349
350
	result = dns_rdataclass_fromtext(classp, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
351
			    "unknown class '%s'", r.base);
352
	return (result);
353
354
}

355
isc_result_t
356
ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
357
358
359
360
361
362
363
364
		   dns_rdatatype_t *typep) {
	isc_textregion_t r;
	isc_result_t result;

	if (!cfg_obj_isstring(typeobj)) {
		*typep = deftype;
		return (ISC_R_SUCCESS);
	}
365
366
	DE_CONST(cfg_obj_asstring(typeobj), r.base);
	r.length = strlen(r.base);
367
368
369
	result = dns_rdatatype_fromtext(typep, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR,
370
			    "unknown type '%s'", r.base);
371
372
373
	return (result);
}

374
dns_zonetype_t
375
ns_config_getzonetype(const cfg_obj_t *zonetypeobj) {
376
	dns_zonetype_t ztype = dns_zone_none;
377
	const char *str;
378
379

	str = cfg_obj_asstring(zonetypeobj);
380
	if (strcasecmp(str, "master") == 0)
381
		ztype = dns_zone_master;
382
	else if (strcasecmp(str, "slave") == 0)
383
		ztype = dns_zone_slave;
384
	else if (strcasecmp(str, "stub") == 0)
385
		ztype = dns_zone_stub;
386
387
	else if (strcasecmp(str, "static-stub") == 0)
		ztype = dns_zone_staticstub;
388
389
	else if (strcasecmp(str, "redirect") == 0)
		ztype = dns_zone_redirect;
390
391
392
393
394
395
	else
		INSIST(0);
	return (ztype);
}

isc_result_t
396
ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
397
398
399
400
		    in_port_t defport, isc_mem_t *mctx,
		    isc_sockaddr_t **addrsp, isc_uint32_t *countp)
{
	int count, i = 0;
401
402
403
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj;
	const cfg_listelt_t *element;
404
405
406
407
408
	isc_sockaddr_t *addrs;
	in_port_t port;
	isc_result_t result;

	INSIST(addrsp != NULL && *addrsp == NULL);
409
	INSIST(countp != NULL);
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461

	addrlist = cfg_tuple_get(list, "addresses");
	count = ns_config_listcount(addrlist);

	portobj = cfg_tuple_get(list, "port");
	if (cfg_obj_isuint32(portobj)) {
		isc_uint32_t val = cfg_obj_asuint32(portobj);
		if (val > ISC_UINT16_MAX) {
			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
				    "port '%u' out of range", val);
			return (ISC_R_RANGE);
		}
		port = (in_port_t) val;
	} else if (defport != 0)
		port = defport;
	else {
		result = ns_config_getport(config, &port);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

	addrs = isc_mem_get(mctx, count * sizeof(isc_sockaddr_t));
	if (addrs == NULL)
		return (ISC_R_NOMEMORY);

	for (element = cfg_list_first(addrlist);
	     element != NULL;
	     element = cfg_list_next(element), i++)
	{
		INSIST(i < count);
		addrs[i] = *cfg_obj_assockaddr(cfg_listelt_value(element));
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
	}
	INSIST(i == count);

	*addrsp = addrs;
	*countp = count;

	return (ISC_R_SUCCESS);
}

void
ns_config_putiplist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
		    isc_uint32_t count)
{
	INSIST(addrsp != NULL && *addrsp != NULL);

	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
	*addrsp = NULL;
}

462
static isc_result_t
463
get_masters_def(const cfg_obj_t *cctx, const char *name,
Automatic Updater's avatar
Automatic Updater committed
464
		const cfg_obj_t **ret)
465
{
466
	isc_result_t result;
467
468
	const cfg_obj_t *masters = NULL;
	const cfg_listelt_t *elt;
469
470
471
472
473
474
475

	result = cfg_map_get(cctx, "masters", &masters);
	if (result != ISC_R_SUCCESS)
		return (result);
	for (elt = cfg_list_first(masters);
	     elt != NULL;
	     elt = cfg_list_next(elt)) {
476
		const cfg_obj_t *list;
477
478
479
480
481
482
483
484
485
486
487
488
489
		const char *listname;

		list = cfg_listelt_value(elt);
		listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));

		if (strcasecmp(listname, name) == 0) {
			*ret = list;
			return (ISC_R_SUCCESS);
		}
	}
	return (ISC_R_NOTFOUND);
}

490
isc_result_t
491
492
493
ns_config_getipandkeylist(const cfg_obj_t *config, const cfg_obj_t *list,
			  isc_mem_t *mctx, isc_sockaddr_t **addrsp,
			  dns_name_t ***keysp, isc_uint32_t *countp)
494
{
495
496
497
	isc_uint32_t addrcount = 0, keycount = 0, i = 0;
	isc_uint32_t listcount = 0, l = 0, j;
	isc_uint32_t stackcount = 0, pushed = 0;
498
	isc_result_t result;
499
500
501
	const cfg_listelt_t *element;
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj;
502
503
504
505
	in_port_t port;
	dns_fixedname_t fname;
	isc_sockaddr_t *addrs = NULL;
	dns_name_t **keys = NULL;
Mark Andrews's avatar
Mark Andrews committed
506
	struct { const char *name; } *lists = NULL;
507
	struct {
508
		const cfg_listelt_t *element;
509
510
		in_port_t port;
	} *stack = NULL;
511

512
513
514
	REQUIRE(addrsp != NULL && *addrsp == NULL);
	REQUIRE(keysp != NULL && *keysp == NULL);
	REQUIRE(countp != NULL);
515

516
 newlist:
517
518
519
520
521
522
523
	addrlist = cfg_tuple_get(list, "addresses");
	portobj = cfg_tuple_get(list, "port");
	if (cfg_obj_isuint32(portobj)) {
		isc_uint32_t val = cfg_obj_asuint32(portobj);
		if (val > ISC_UINT16_MAX) {
			cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
				    "port '%u' out of range", val);
524
525
			result = ISC_R_RANGE;
			goto cleanup;
526
527
528
529
530
		}
		port = (in_port_t) val;
	} else {
		result = ns_config_getport(config, &port);
		if (result != ISC_R_SUCCESS)
531
			goto cleanup;
532
533
534
535
	}

	result = ISC_R_NOMEMORY;

536
537
538
	element = cfg_list_first(addrlist);
 resume:
	for ( ;
539
	     element != NULL;
540
	     element = cfg_list_next(element))
541
	{
542
543
		const cfg_obj_t *addr;
		const cfg_obj_t *key;
544
		const char *keystr;
545
546
		isc_buffer_t b;

547
548
		addr = cfg_tuple_get(cfg_listelt_value(element),
				     "masterselement");
549
550
		key = cfg_tuple_get(cfg_listelt_value(element), "key");

551
		if (!cfg_obj_issockaddr(addr)) {
552
			const char *listname = cfg_obj_asstring(addr);
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
			isc_result_t tresult;

			/* Grow lists? */
			if (listcount == l) {
				void * new;
				isc_uint32_t newlen = listcount + 16;
				size_t newsize, oldsize;

				newsize = newlen * sizeof(*lists);
				oldsize = listcount * sizeof(*lists);
				new = isc_mem_get(mctx, newsize);
				if (new == NULL)
					goto cleanup;
				if (listcount != 0) {
					memcpy(new, lists, oldsize);
					isc_mem_put(mctx, lists, oldsize);
				}
				lists = new;
				listcount = newlen;
			}
			/* Seen? */
			for (j = 0; j < l; j++)
Mark Andrews's avatar
Mark Andrews committed
575
				if (strcasecmp(lists[j].name, listname) == 0)
576
577
578
579
580
581
					break;
			if (j < l)
				continue;
			tresult = get_masters_def(config, listname, &list);
			if (tresult == ISC_R_NOTFOUND) {
				cfg_obj_log(addr, ns_g_lctx, ISC_LOG_ERROR,
Automatic Updater's avatar
Automatic Updater committed
582
				    "masters \"%s\" not found", listname);
583
584
585
586
587
588

				result = tresult;
				goto cleanup;
			}
			if (tresult != ISC_R_SUCCESS)
				goto cleanup;
Mark Andrews's avatar
Mark Andrews committed
589
			lists[l++].name = listname;
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
			/* Grow stack? */
			if (stackcount == pushed) {
				void * new;
				isc_uint32_t newlen = stackcount + 16;
				size_t newsize, oldsize;

				newsize = newlen * sizeof(*stack);
				oldsize = stackcount * sizeof(*stack);
				new = isc_mem_get(mctx, newsize);
				if (new == NULL)
					goto cleanup;
				if (stackcount != 0) {
					memcpy(new, stack, oldsize);
					isc_mem_put(mctx, stack, oldsize);
				}
				stack = new;
				stackcount = newlen;
			}
			/*
			 * We want to resume processing this list on the
			 * next element.
			 */
			stack[pushed].element = cfg_list_next(element);
			stack[pushed].port = port;
			pushed++;
			goto newlist;
		}

		if (i == addrcount) {
			void * new;
			isc_uint32_t newlen = addrcount + 16;
			size_t newsize, oldsize;

			newsize = newlen * sizeof(isc_sockaddr_t);
			oldsize = addrcount * sizeof(isc_sockaddr_t);
			new = isc_mem_get(mctx, newsize);
			if (new == NULL)
				goto cleanup;
			if (addrcount != 0) {
				memcpy(new, addrs, oldsize);
				isc_mem_put(mctx, addrs, oldsize);
			}
			addrs = new;
			addrcount = newlen;

			newsize = newlen * sizeof(dns_name_t *);
			oldsize = keycount * sizeof(dns_name_t *);
			new = isc_mem_get(mctx, newsize);
			if (new == NULL)
				goto cleanup;
			if (keycount != 0) {
641
642
				memcpy(new, keys, oldsize);
				isc_mem_put(mctx, keys, oldsize);
643
644
645
646
647
			}
			keys = new;
			keycount = newlen;
		}

648
649
650
651
		addrs[i] = *cfg_obj_assockaddr(addr);
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
		keys[i] = NULL;
652
653
		if (!cfg_obj_isstring(key)) {
			i++;
654
			continue;
655
		}
656
657
658
659
		keys[i] = isc_mem_get(mctx, sizeof(dns_name_t));
		if (keys[i] == NULL)
			goto cleanup;
		dns_name_init(keys[i], NULL);
Automatic Updater's avatar
Automatic Updater committed
660

661
662
663
664
665
		keystr = cfg_obj_asstring(key);
		isc_buffer_init(&b, keystr, strlen(keystr));
		isc_buffer_add(&b, strlen(keystr));
		dns_fixedname_init(&fname);
		result = dns_name_fromtext(dns_fixedname_name(&fname), &b,
666
					   dns_rootname, 0, NULL);
667
668
669
670
671
672
		if (result != ISC_R_SUCCESS)
			goto cleanup;
		result = dns_name_dup(dns_fixedname_name(&fname), mctx,
				      keys[i]);
		if (result != ISC_R_SUCCESS)
			goto cleanup;
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
		i++;
	}
	if (pushed != 0) {
		pushed--;
		element = stack[pushed].element;
		port = stack[pushed].port;
		goto resume;
	}
	if (i < addrcount) {
		void * new;
		size_t newsize, oldsize;

		newsize = i * sizeof(isc_sockaddr_t);
		oldsize = addrcount * sizeof(isc_sockaddr_t);
		if (i != 0) {
			new = isc_mem_get(mctx, newsize);
			if (new == NULL)
				goto cleanup;
			memcpy(new, addrs, newsize);
		} else
			new = NULL;
694
		isc_mem_put(mctx, addrs, oldsize);
695
696
697
698
699
700
701
702
703
704
705
706
		addrs = new;
		addrcount = i;

		newsize = i * sizeof(dns_name_t *);
		oldsize = keycount * sizeof(dns_name_t *);
		if (i != 0) {
			new = isc_mem_get(mctx, newsize);
			if (new == NULL)
				goto cleanup;
			memcpy(new, keys,  newsize);
		} else
			new = NULL;
707
		isc_mem_put(mctx, keys, oldsize);
708
709
		keys = new;
		keycount = i;
710
	}
711
712
713
714
715

	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
Automatic Updater's avatar
Automatic Updater committed
716

717
	INSIST(keycount == addrcount);
718
719
720

	*addrsp = addrs;
	*keysp = keys;
721
	*countp = addrcount;
722
723
724
725
726

	return (ISC_R_SUCCESS);

 cleanup:
	if (addrs != NULL)
727
		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
728
	if (keys != NULL) {
729
		for (j = 0; j <= i; j++) {
730
731
732
733
734
735
			if (keys[j] == NULL)
				continue;
			if (dns_name_dynamic(keys[j]))
				dns_name_free(keys[j], mctx);
			isc_mem_put(mctx, keys[j], sizeof(dns_name_t));
		}
736
		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
737
	}
738
739
740
741
	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
	return (result);
}

void
ns_config_putipandkeylist(isc_mem_t *mctx, isc_sockaddr_t **addrsp,
			  dns_name_t ***keysp, isc_uint32_t count)
{
	unsigned int i;
	dns_name_t **keys = *keysp;

	INSIST(addrsp != NULL && *addrsp != NULL);

	isc_mem_put(mctx, *addrsp, count * sizeof(isc_sockaddr_t));
	for (i = 0; i < count; i++) {
		if (keys[i] == NULL)
			continue;
		if (dns_name_dynamic(keys[i]))
			dns_name_free(keys[i], mctx);
		isc_mem_put(mctx, keys[i], sizeof(dns_name_t));
	}
	isc_mem_put(mctx, *keysp, count * sizeof(dns_name_t *));
	*addrsp = NULL;
	*keysp = NULL;
}

isc_result_t
768
769
770
771
ns_config_getport(const cfg_obj_t *config, in_port_t *portp) {
	const cfg_obj_t *maps[3];
	const cfg_obj_t *options = NULL;
	const cfg_obj_t *portobj = NULL;
772
773
774
	isc_result_t result;
	int i;

775
	(void)cfg_map_get(config, "options", &options);
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
	i = 0;
	if (options != NULL)
		maps[i++] = options;
	maps[i++] = ns_g_defaults;
	maps[i] = NULL;

	result = ns_config_get(maps, "port", &portobj);
	INSIST(result == ISC_R_SUCCESS);
	if (cfg_obj_asuint32(portobj) >= ISC_UINT16_MAX) {
		cfg_obj_log(portobj, ns_g_lctx, ISC_LOG_ERROR,
			    "port '%u' out of range",
			    cfg_obj_asuint32(portobj));
		return (ISC_R_RANGE);
	}
	*portp = (in_port_t)cfg_obj_asuint32(portobj);
	return (ISC_R_SUCCESS);
}
Brian Wellington's avatar
Brian Wellington committed
793

794
795
796
797
struct keyalgorithms {
	const char *str;
	enum { hmacnone, hmacmd5, hmacsha1, hmacsha224,
	       hmacsha256, hmacsha384, hmacsha512 } hmac;
798
	unsigned int type;
799
800
	isc_uint16_t size;
} algorithms[] = {
801
802
803
804
805
806
807
808
809
	{ "hmac-md5", hmacmd5, DST_ALG_HMACMD5, 128 },
	{ "hmac-md5.sig-alg.reg.int", hmacmd5, DST_ALG_HMACMD5, 0 },
	{ "hmac-md5.sig-alg.reg.int.", hmacmd5, DST_ALG_HMACMD5, 0 },
	{ "hmac-sha1", hmacsha1, DST_ALG_HMACSHA1, 160 },
	{ "hmac-sha224", hmacsha224, DST_ALG_HMACSHA224, 224 },
	{ "hmac-sha256", hmacsha256, DST_ALG_HMACSHA256, 256 },
	{ "hmac-sha384", hmacsha384, DST_ALG_HMACSHA384, 384 },
	{ "hmac-sha512", hmacsha512, DST_ALG_HMACSHA512, 512 },
	{  NULL, hmacnone, DST_ALG_UNKNOWN, 0 }
810
811
};

Brian Wellington's avatar
Brian Wellington committed
812
isc_result_t
813
814
ns_config_getkeyalgorithm(const char *str, dns_name_t **name,
			  isc_uint16_t *digestbits)
815
816
817
818
819
820
821
{
	return (ns_config_getkeyalgorithm2(str, name, NULL, digestbits));
}

isc_result_t
ns_config_getkeyalgorithm2(const char *str, dns_name_t **name,
			   unsigned int *typep, isc_uint16_t *digestbits)
Brian Wellington's avatar
Brian Wellington committed
822
{
823
824
825
826
827
828
829
830
831
832
833
	int i;
	size_t len = 0;
	isc_uint16_t bits;
	isc_result_t result;

	for (i = 0; algorithms[i].str != NULL; i++) {
		len = strlen(algorithms[i].str);
		if (strncasecmp(algorithms[i].str, str, len) == 0 &&
		    (str[len] == '\0' ||
		     (algorithms[i].size != 0 && str[len] == '-')))
			break;
Brian Wellington's avatar
Brian Wellington committed
834
	}
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
	if (algorithms[i].str == NULL)
		return (ISC_R_NOTFOUND);
	if (str[len] == '-') {
		result = isc_parse_uint16(&bits, str + len + 1, 10);
		if (result != ISC_R_SUCCESS)
			return (result);
		if (bits > algorithms[i].size)
			return (ISC_R_RANGE);
	} else if (algorithms[i].size == 0)
		bits = 128;
	else
		bits = algorithms[i].size;

	if (name != NULL) {
		switch (algorithms[i].hmac) {
		case hmacmd5: *name = dns_tsig_hmacmd5_name; break;
		case hmacsha1: *name = dns_tsig_hmacsha1_name; break;
		case hmacsha224: *name = dns_tsig_hmacsha224_name; break;
		case hmacsha256: *name = dns_tsig_hmacsha256_name; break;
		case hmacsha384: *name = dns_tsig_hmacsha384_name; break;
		case hmacsha512: *name = dns_tsig_hmacsha512_name; break;
		default:
			INSIST(0);
		}
	}
860
861
	if (typep != NULL)
		*typep = algorithms[i].type;
862
863
864
	if (digestbits != NULL)
		*digestbits = bits;
	return (ISC_R_SUCCESS);
Brian Wellington's avatar
Brian Wellington committed
865
}