config.c 19.9 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Copyright (C) 2004-2008  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
 */

18
/* $Id: config.c,v 1.86 2008/04/03 02:01:08 marka 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
45
46
47
#include <dns/zone.h>

#include <named/config.h>
#include <named/globals.h>

48
/*% default configuration */
49
50
static char defaultconf[] = "\
options {\n\
51
52
53
#	blackhole {none;};\n"
#ifndef WIN32
"	coresize default;\n\
54
	datasize default;\n\
55
56
57
58
	files default;\n\
	stacksize default;\n"
#endif
"	deallocate-on-exit true;\n\
59
60
61
62
#	directory <none>\n\
	dump-file \"named_dump.db\";\n\
	fake-iquery no;\n\
	has-old-clients false;\n\
63
	heartbeat-interval 60;\n\
64
	host-statistics no;\n\
65
	interface-interval 60;\n\
66
67
	listen-on {any;};\n\
	listen-on-v6 {none;};\n\
68
	match-mapped-addresses no;\n\
69
70
	memstatistics-file \"named.memstats\";\n\
	multiple-cnames no;\n\
71
#	named-xfer <obsolete>;\n\
72
73
#	pid-file \"" NS_LOCALSTATEDIR "/named.pid\"; /* or /lwresd.pid */\n\
	port 53;\n\
74
	recursing-file \"named.recursing\";\n\
75
76
"
#ifdef PATH_RANDOMDEV
77
78
"\
	random-device \"" PATH_RANDOMDEV "\";\n\
79
80
"
#endif
81
82
"\
	recursive-clients 1000;\n\
83
	rrset-order {type NS order random; order cyclic; };\n\
84
	serial-queries 20;\n\
85
	serial-query-rate 20;\n\
86
	server-id none;\n\
87
	statistics-file \"named.stats\";\n\
88
	statistics-interval 60;\n\
89
	tcp-clients 100;\n\
Michael Graff's avatar
Michael Graff committed
90
	tcp-listen-queue 3;\n\
91
92
93
94
95
96
97
98
99
#	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\
100
	edns-udp-size 4096;\n\
101
	max-udp-size 4096;\n\
102
	request-nsid false;\n\
103
104
105
106
\n\
	/* view */\n\
	allow-notify {none;};\n\
	allow-update-forwarding {none;};\n\
107
	allow-query-cache { localnets; localhost; };\n\
108
	allow-query-cache-on { any; };\n\
109
	allow-recursion { localnets; localhost; };\n\
110
	allow-recursion-on { any; };\n\
111
#	allow-v6-synthesis <obsolete>;\n\
112
113
114
#	sortlist <none>\n\
#	topology <none>\n\
	auth-nxdomain false;\n\
Bob Halley's avatar
Bob Halley committed
115
	minimal-responses false;\n\
116
117
118
119
120
121
122
123
124
125
126
	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\
127
	cleaning-interval 60;\n\
128
129
130
131
132
	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\
133
#	max-cache-size default; /* set default in server.c */\n\
134
135
	check-names master fail;\n\
	check-names slave warn;\n\
136
	check-names response ignore;\n\
137
	check-mx warn;\n\
138
	acache-enable no;\n\
139
	acache-cleaning-interval 60;\n\
140
	max-acache-size 16M;\n\
141
142
	dnssec-enable yes;\n\
	dnssec-validation no; /* Make yes for 9.5. */ \n\
143
	dnssec-accept-expired no;\n\
144
145
	clients-per-query 10;\n\
	max-clients-per-query 100;\n\
146
	zero-no-soa-ttl-cache no;\n\
Mark Andrews's avatar
Mark Andrews committed
147
148
149
"

"	/* zone */\n\
150
	allow-query {any;};\n\
151
	allow-query-on {any;};\n\
152
153
154
	allow-transfer {any;};\n\
	notify yes;\n\
#	also-notify <none>\n\
155
	notify-delay 5;\n\
156
	notify-to-soa no;\n\
157
158
159
160
161
162
163
	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\
164
	alt-transfer-source *;\n\
165
	alt-transfer-source-v6 *;\n\
166
167
168
169
	max-transfer-time-in 120;\n\
	max-transfer-time-out 120;\n\
	max-transfer-idle-in 60;\n\
	max-transfer-idle-out 60;\n\
170
171
172
173
	max-retry-time 1209600; /* 2 weeks */\n\
	min-retry-time 500;\n\
	max-refresh-time 2419200; /* 4 weeks */\n\
	min-refresh-time 300;\n\
174
	multi-master no;\n\
175
	sig-validity-interval 30; /* days */\n\
176
177
178
	sig-signing-nodes 100;\n\
	sig-signing-signatures 10;\n\
	sig-signing-type 65535;\n\
179
	zone-statistics false;\n\
180
	max-journal-size unlimited;\n\
181
	ixfr-from-differences false;\n\
182
	check-wildcard yes;\n\
183
184
	check-sibling yes;\n\
	check-integrity yes;\n\
185
186
	check-mx-cname warn;\n\
	check-srv-cname warn;\n\
187
	zero-no-soa-ttl yes;\n\
188
	update-check-ksk yes;\n\
189
	try-tcp-refresh yes; /* BIND 8 compat */\n\
190
};\n\
Mark Andrews's avatar
Mark Andrews committed
191
192
193
"

"#\n\
Mark Andrews's avatar
Mark Andrews committed
194
#  Zones in the \"_bind\" view are NOT counted in the count of zones.\n\
195
#\n\
196
197
view \"_bind\" chaos {\n\
	recursion no;\n\
198
	notify no;\n\
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
\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\
214
215
216
217
	zone \"id.server\" chaos {\n\
		type master;\n\
		database \"_builtin id\";\n\
	};\n\
218
};\n\
219
";
220
221
222
223
224
225
226
227
228
229
230

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
231
ns_config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
232
233
	int i;

234
	for (i = 0;; i++) {
235
236
237
238
239
240
241
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
			return (ISC_R_SUCCESS);
	}
}

242
isc_result_t
243
244
245
246
247
248
249
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;
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
	int i;

	for (i = 0;; i++) {
		if (maps[i] == NULL)
			return (ISC_R_NOTFOUND);
		checknames = NULL;
		if (cfg_map_get(maps[i], "check-names", &checknames) == ISC_R_SUCCESS) {
			/*
			 * 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");
				if (strcasecmp(cfg_obj_asstring(type), which) == 0) {
					*obj = cfg_tuple_get(value, "mode");
					return (ISC_R_SUCCESS);
				}
			}

		}
	}
}

279
int
280
281
ns_config_listcount(const cfg_obj_t *list) {
	const cfg_listelt_t *e;
282
283
284
285
286
287
288
289
290
	int i = 0;

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

	return (i);
}

isc_result_t
291
ns_config_getclass(const cfg_obj_t *classobj, dns_rdataclass_t defclass,
292
		   dns_rdataclass_t *classp) {
293
	isc_textregion_t r;
294
	isc_result_t result;
295
296

	if (!cfg_obj_isstring(classobj)) {
297
		*classp = defclass;
298
299
		return (ISC_R_SUCCESS);
	}
300
301
	DE_CONST(cfg_obj_asstring(classobj), r.base);
	r.length = strlen(r.base);
302
303
304
	result = dns_rdataclass_fromtext(classp, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(classobj, ns_g_lctx, ISC_LOG_ERROR,
305
			    "unknown class '%s'", r.base);
306
	return (result);
307
308
}

309
isc_result_t
310
ns_config_gettype(const cfg_obj_t *typeobj, dns_rdatatype_t deftype,
311
312
313
314
315
316
317
318
		   dns_rdatatype_t *typep) {
	isc_textregion_t r;
	isc_result_t result;

	if (!cfg_obj_isstring(typeobj)) {
		*typep = deftype;
		return (ISC_R_SUCCESS);
	}
319
320
	DE_CONST(cfg_obj_asstring(typeobj), r.base);
	r.length = strlen(r.base);
321
322
323
	result = dns_rdatatype_fromtext(typep, &r);
	if (result != ISC_R_SUCCESS)
		cfg_obj_log(typeobj, ns_g_lctx, ISC_LOG_ERROR,
324
			    "unknown type '%s'", r.base);
325
326
327
	return (result);
}

328
dns_zonetype_t
329
ns_config_getzonetype(const cfg_obj_t *zonetypeobj) {
330
	dns_zonetype_t ztype = dns_zone_none;
331
	const char *str;
332
333

	str = cfg_obj_asstring(zonetypeobj);
334
	if (strcasecmp(str, "master") == 0)
335
		ztype = dns_zone_master;
336
	else if (strcasecmp(str, "slave") == 0)
337
		ztype = dns_zone_slave;
338
	else if (strcasecmp(str, "stub") == 0)
339
340
341
342
343
344
345
		ztype = dns_zone_stub;
	else
		INSIST(0);
	return (ztype);
}

isc_result_t
346
ns_config_getiplist(const cfg_obj_t *config, const cfg_obj_t *list,
347
348
349
350
		    in_port_t defport, isc_mem_t *mctx,
		    isc_sockaddr_t **addrsp, isc_uint32_t *countp)
{
	int count, i = 0;
351
352
353
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj;
	const cfg_listelt_t *element;
354
355
356
357
358
	isc_sockaddr_t *addrs;
	in_port_t port;
	isc_result_t result;

	INSIST(addrsp != NULL && *addrsp == NULL);
359
	INSIST(countp != NULL);
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411

	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;
}

412
static isc_result_t
413
get_masters_def(const cfg_obj_t *cctx, const char *name,
Automatic Updater's avatar
Automatic Updater committed
414
		const cfg_obj_t **ret)
415
{
416
	isc_result_t result;
417
418
	const cfg_obj_t *masters = NULL;
	const cfg_listelt_t *elt;
419
420
421
422
423
424
425

	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)) {
426
		const cfg_obj_t *list;
427
428
429
430
431
432
433
434
435
436
437
438
439
		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);
}

440
isc_result_t
441
442
443
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)
444
{
445
446
447
	isc_uint32_t addrcount = 0, keycount = 0, i = 0;
	isc_uint32_t listcount = 0, l = 0, j;
	isc_uint32_t stackcount = 0, pushed = 0;
448
	isc_result_t result;
449
450
451
	const cfg_listelt_t *element;
	const cfg_obj_t *addrlist;
	const cfg_obj_t *portobj;
452
453
454
455
	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
456
	struct { const char *name; } *lists = NULL;
457
	struct {
458
		const cfg_listelt_t *element;
459
460
		in_port_t port;
	} *stack = NULL;
461

462
463
464
	REQUIRE(addrsp != NULL && *addrsp == NULL);
	REQUIRE(keysp != NULL && *keysp == NULL);
	REQUIRE(countp != NULL);
465

466
 newlist:
467
468
469
470
471
472
473
	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);
474
475
			result = ISC_R_RANGE;
			goto cleanup;
476
477
478
479
480
		}
		port = (in_port_t) val;
	} else {
		result = ns_config_getport(config, &port);
		if (result != ISC_R_SUCCESS)
481
			goto cleanup;
482
483
484
485
	}

	result = ISC_R_NOMEMORY;

486
487
488
	element = cfg_list_first(addrlist);
 resume:
	for ( ;
489
	     element != NULL;
490
	     element = cfg_list_next(element))
491
	{
492
493
		const cfg_obj_t *addr;
		const cfg_obj_t *key;
494
		const char *keystr;
495
496
		isc_buffer_t b;

497
498
		addr = cfg_tuple_get(cfg_listelt_value(element),
				     "masterselement");
499
500
		key = cfg_tuple_get(cfg_listelt_value(element), "key");

501
		if (!cfg_obj_issockaddr(addr)) {
502
			const char *listname = cfg_obj_asstring(addr);
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
			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
525
				if (strcasecmp(lists[j].name, listname) == 0)
526
527
528
529
530
531
					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
532
				    "masters \"%s\" not found", listname);
533
534
535
536
537
538

				result = tresult;
				goto cleanup;
			}
			if (tresult != ISC_R_SUCCESS)
				goto cleanup;
Mark Andrews's avatar
Mark Andrews committed
539
			lists[l++].name = listname;
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
			/* 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) {
591
592
				memcpy(new, keys, oldsize);
				isc_mem_put(mctx, keys, oldsize);
593
594
595
596
597
			}
			keys = new;
			keycount = newlen;
		}

598
599
600
601
		addrs[i] = *cfg_obj_assockaddr(addr);
		if (isc_sockaddr_getport(&addrs[i]) == 0)
			isc_sockaddr_setport(&addrs[i], port);
		keys[i] = NULL;
602
603
		if (!cfg_obj_isstring(key)) {
			i++;
604
			continue;
605
		}
606
607
608
609
		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
610

611
612
613
614
615
616
617
618
619
620
621
622
		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,
					   dns_rootname, ISC_FALSE, NULL);
		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;
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
		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;
644
		isc_mem_put(mctx, addrs, oldsize);
645
646
647
648
649
650
651
652
653
654
655
656
		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;
657
		isc_mem_put(mctx, keys, oldsize);
658
659
		keys = new;
		keycount = i;
660
	}
661
662
663
664
665

	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
666

667
	INSIST(keycount == addrcount);
668
669
670

	*addrsp = addrs;
	*keysp = keys;
671
	*countp = addrcount;
672
673
674
675
676

	return (ISC_R_SUCCESS);

 cleanup:
	if (addrs != NULL)
677
		isc_mem_put(mctx, addrs, addrcount * sizeof(isc_sockaddr_t));
678
	if (keys != NULL) {
679
		for (j = 0; j <= i; j++) {
680
681
682
683
684
685
			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));
		}
686
		isc_mem_put(mctx, keys, keycount * sizeof(dns_name_t *));
687
	}
688
689
690
691
	if (lists != NULL)
		isc_mem_put(mctx, lists, listcount * sizeof(*lists));
	if (stack != NULL)
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
	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
718
719
720
721
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;
722
723
724
	isc_result_t result;
	int i;

725
	(void)cfg_map_get(config, "options", &options);
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
	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
743

744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
struct keyalgorithms {
	const char *str;
	enum { hmacnone, hmacmd5, hmacsha1, hmacsha224,
	       hmacsha256, hmacsha384, hmacsha512 } hmac;
	isc_uint16_t size;
} algorithms[] = {
	{ "hmac-md5", hmacmd5, 128 },
	{ "hmac-md5.sig-alg.reg.int", hmacmd5, 0 },
	{ "hmac-md5.sig-alg.reg.int.", hmacmd5, 0 },
	{ "hmac-sha1", hmacsha1, 160 },
	{ "hmac-sha224", hmacsha224, 224 },
	{ "hmac-sha256", hmacsha256, 256 },
	{ "hmac-sha384", hmacsha384, 384 },
	{ "hmac-sha512", hmacsha512, 512 },
	{  NULL, hmacnone, 0 }
};

Brian Wellington's avatar
Brian Wellington committed
761
isc_result_t
762
763
ns_config_getkeyalgorithm(const char *str, dns_name_t **name,
			  isc_uint16_t *digestbits)
Brian Wellington's avatar
Brian Wellington committed
764
{
765
766
767
768
769
770
771
772
773
774
775
	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
776
	}
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
	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);
		}
	}
	if (digestbits != NULL)
		*digestbits = bits;
	return (ISC_R_SUCCESS);
Brian Wellington's avatar
Brian Wellington committed
805
}