GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/bind/lib/bind9/check.c Lines: 0 984 0.0 %
Date: 2016-12-06 Branches: 0 588 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (C) 2004-2007  Internet Systems Consortium, Inc. ("ISC")
3
 * Copyright (C) 2001-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
/* $ISC: check.c,v 1.44.18.35 2007/09/13 05:04:01 each Exp $ */
19
20
/*! \file */
21
22
#include <config.h>
23
24
#include <stdlib.h>
25
26
#include <isc/buffer.h>
27
#include <isc/log.h>
28
#include <isc/mem.h>
29
#include <isc/netaddr.h>
30
#include <isc/parseint.h>
31
#include <isc/region.h>
32
#include <isc/result.h>
33
#include <isc/sockaddr.h>
34
#include <isc/string.h>
35
#include <isc/symtab.h>
36
#include <isc/util.h>
37
38
#include <dns/acl.h>
39
#include <dns/fixedname.h>
40
#include <dns/rdataclass.h>
41
#include <dns/rdatatype.h>
42
#include <dns/secalg.h>
43
44
#include <isccfg/aclconf.h>
45
#include <isccfg/cfg.h>
46
47
#include <bind9/check.h>
48
49
#ifndef DNS_RDATASET_FIXED
50
#define DNS_RDATASET_FIXED 1
51
#endif
52
53
static void
54
freekey(char *key, unsigned int type, isc_symvalue_t value, void *userarg) {
55
	UNUSED(type);
56
	UNUSED(value);
57
	isc_mem_free(userarg, key);
58
}
59
60
static isc_result_t
61
check_orderent(const cfg_obj_t *ent, isc_log_t *logctx) {
62
	isc_result_t result = ISC_R_SUCCESS;
63
	isc_result_t tresult;
64
	isc_textregion_t r;
65
	dns_fixedname_t fixed;
66
	const cfg_obj_t *obj;
67
	dns_rdataclass_t rdclass;
68
	dns_rdatatype_t rdtype;
69
	isc_buffer_t b;
70
	const char *str;
71
72
	dns_fixedname_init(&fixed);
73
	obj = cfg_tuple_get(ent, "class");
74
	if (cfg_obj_isstring(obj)) {
75
76
		DE_CONST(cfg_obj_asstring(obj), r.base);
77
		r.length = strlen(r.base);
78
		tresult = dns_rdataclass_fromtext(&rdclass, &r);
79
		if (tresult != ISC_R_SUCCESS) {
80
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
81
				    "rrset-order: invalid class '%s'",
82
				    r.base);
83
			result = ISC_R_FAILURE;
84
		}
85
	}
86
87
	obj = cfg_tuple_get(ent, "type");
88
	if (cfg_obj_isstring(obj)) {
89
90
		DE_CONST(cfg_obj_asstring(obj), r.base);
91
		r.length = strlen(r.base);
92
		tresult = dns_rdatatype_fromtext(&rdtype, &r);
93
		if (tresult != ISC_R_SUCCESS) {
94
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
95
				    "rrset-order: invalid type '%s'",
96
				    r.base);
97
			result = ISC_R_FAILURE;
98
		}
99
	}
100
101
	obj = cfg_tuple_get(ent, "name");
102
	if (cfg_obj_isstring(obj)) {
103
		str = cfg_obj_asstring(obj);
104
		isc_buffer_init(&b, str, strlen(str));
105
		isc_buffer_add(&b, strlen(str));
106
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
107
					    dns_rootname, ISC_FALSE, NULL);
108
		if (tresult != ISC_R_SUCCESS) {
109
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
110
				    "rrset-order: invalid name '%s'", str);
111
			result = ISC_R_FAILURE;
112
		}
113
	}
114
115
	obj = cfg_tuple_get(ent, "order");
116
	if (!cfg_obj_isstring(obj) ||
117
	    strcasecmp("order", cfg_obj_asstring(obj)) != 0) {
118
		cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
119
			    "rrset-order: keyword 'order' missing");
120
		result = ISC_R_FAILURE;
121
	}
122
123
	obj = cfg_tuple_get(ent, "ordering");
124
	if (!cfg_obj_isstring(obj)) {
125
	    cfg_obj_log(ent, logctx, ISC_LOG_ERROR,
126
			"rrset-order: missing ordering");
127
		result = ISC_R_FAILURE;
128
	} else if (strcasecmp(cfg_obj_asstring(obj), "fixed") == 0) {
129
#if !DNS_RDATASET_FIXED
130
		cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
131
			    "rrset-order: order 'fixed' not fully implemented");
132
#endif
133
	} else if (strcasecmp(cfg_obj_asstring(obj), "random") != 0 &&
134
		   strcasecmp(cfg_obj_asstring(obj), "cyclic") != 0) {
135
		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
136
			    "rrset-order: invalid order '%s'",
137
			    cfg_obj_asstring(obj));
138
		result = ISC_R_FAILURE;
139
	}
140
	return (result);
141
}
142
143
static isc_result_t
144
check_order(const cfg_obj_t *options, isc_log_t *logctx) {
145
	isc_result_t result = ISC_R_SUCCESS;
146
	isc_result_t tresult;
147
	const cfg_listelt_t *element;
148
	const cfg_obj_t *obj = NULL;
149
150
	if (cfg_map_get(options, "rrset-order", &obj) != ISC_R_SUCCESS)
151
		return (result);
152
153
	for (element = cfg_list_first(obj);
154
	     element != NULL;
155
	     element = cfg_list_next(element))
156
	{
157
		tresult = check_orderent(cfg_listelt_value(element), logctx);
158
		if (tresult != ISC_R_SUCCESS)
159
			result = tresult;
160
	}
161
	return (result);
162
}
163
164
static isc_result_t
165
check_dual_stack(const cfg_obj_t *options, isc_log_t *logctx) {
166
	const cfg_listelt_t *element;
167
	const cfg_obj_t *alternates = NULL;
168
	const cfg_obj_t *value;
169
	const cfg_obj_t *obj;
170
	const char *str;
171
	dns_fixedname_t fixed;
172
	dns_name_t *name;
173
	isc_buffer_t buffer;
174
	isc_result_t result = ISC_R_SUCCESS;
175
	isc_result_t tresult;
176
177
	(void)cfg_map_get(options, "dual-stack-servers", &alternates);
178
179
	if (alternates == NULL)
180
		return (ISC_R_SUCCESS);
181
182
	obj = cfg_tuple_get(alternates, "port");
183
	if (cfg_obj_isuint32(obj)) {
184
		isc_uint32_t val = cfg_obj_asuint32(obj);
185
		if (val > ISC_UINT16_MAX) {
186
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
187
				    "port '%u' out of range", val);
188
			result = ISC_R_FAILURE;
189
		}
190
	}
191
	obj = cfg_tuple_get(alternates, "addresses");
192
	for (element = cfg_list_first(obj);
193
	     element != NULL;
194
	     element = cfg_list_next(element)) {
195
		value = cfg_listelt_value(element);
196
		if (cfg_obj_issockaddr(value))
197
			continue;
198
		obj = cfg_tuple_get(value, "name");
199
		str = cfg_obj_asstring(obj);
200
		isc_buffer_init(&buffer, str, strlen(str));
201
		isc_buffer_add(&buffer, strlen(str));
202
		dns_fixedname_init(&fixed);
203
		name = dns_fixedname_name(&fixed);
204
		tresult = dns_name_fromtext(name, &buffer, dns_rootname,
205
					   ISC_FALSE, NULL);
206
		if (tresult != ISC_R_SUCCESS) {
207
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
208
				    "bad name '%s'", str);
209
			result = ISC_R_FAILURE;
210
		}
211
		obj = cfg_tuple_get(value, "port");
212
		if (cfg_obj_isuint32(obj)) {
213
			isc_uint32_t val = cfg_obj_asuint32(obj);
214
			if (val > ISC_UINT16_MAX) {
215
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
216
					    "port '%u' out of range", val);
217
				result = ISC_R_FAILURE;
218
			}
219
		}
220
	}
221
	return (result);
222
}
223
224
static isc_result_t
225
check_forward(const cfg_obj_t *options, isc_log_t *logctx) {
226
	const cfg_obj_t *forward = NULL;
227
	const cfg_obj_t *forwarders = NULL;
228
229
	(void)cfg_map_get(options, "forward", &forward);
230
	(void)cfg_map_get(options, "forwarders", &forwarders);
231
232
	if (forward != NULL && forwarders == NULL) {
233
		cfg_obj_log(forward, logctx, ISC_LOG_ERROR,
234
			    "no matching 'forwarders' statement");
235
		return (ISC_R_FAILURE);
236
	}
237
	return (ISC_R_SUCCESS);
238
}
239
240
static isc_result_t
241
disabled_algorithms(const cfg_obj_t *disabled, isc_log_t *logctx) {
242
	isc_result_t result = ISC_R_SUCCESS;
243
	isc_result_t tresult;
244
	const cfg_listelt_t *element;
245
	const char *str;
246
	isc_buffer_t b;
247
	dns_fixedname_t fixed;
248
	dns_name_t *name;
249
	const cfg_obj_t *obj;
250
251
	dns_fixedname_init(&fixed);
252
	name = dns_fixedname_name(&fixed);
253
	obj = cfg_tuple_get(disabled, "name");
254
	str = cfg_obj_asstring(obj);
255
	isc_buffer_init(&b, str, strlen(str));
256
	isc_buffer_add(&b, strlen(str));
257
	tresult = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
258
	if (tresult != ISC_R_SUCCESS) {
259
		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
260
			    "bad domain name '%s'", str);
261
		result = tresult;
262
	}
263
264
	obj = cfg_tuple_get(disabled, "algorithms");
265
266
	for (element = cfg_list_first(obj);
267
	     element != NULL;
268
	     element = cfg_list_next(element))
269
	{
270
		isc_textregion_t r;
271
		dns_secalg_t alg;
272
		isc_result_t tresult;
273
274
		DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
275
		r.length = strlen(r.base);
276
277
		tresult = dns_secalg_fromtext(&alg, &r);
278
		if (tresult != ISC_R_SUCCESS) {
279
			isc_uint8_t ui;
280
			result = isc_parse_uint8(&ui, r.base, 10);
281
		}
282
		if (tresult != ISC_R_SUCCESS) {
283
			cfg_obj_log(cfg_listelt_value(element), logctx,
284
				    ISC_LOG_ERROR, "invalid algorithm '%s'",
285
				    r.base);
286
			result = tresult;
287
		}
288
	}
289
	return (result);
290
}
291
292
static isc_result_t
293
nameexist(const cfg_obj_t *obj, const char *name, int value,
294
	  isc_symtab_t *symtab, const char *fmt, isc_log_t *logctx,
295
	  isc_mem_t *mctx)
296
{
297
	char *key;
298
	const char *file;
299
	unsigned int line;
300
	isc_result_t result;
301
	isc_symvalue_t symvalue;
302
303
	key = isc_mem_strdup(mctx, name);
304
	if (key == NULL)
305
		return (ISC_R_NOMEMORY);
306
	symvalue.as_cpointer = obj;
307
	result = isc_symtab_define(symtab, key, value, symvalue,
308
				   isc_symexists_reject);
309
	if (result == ISC_R_EXISTS) {
310
		RUNTIME_CHECK(isc_symtab_lookup(symtab, key, value,
311
						&symvalue) == ISC_R_SUCCESS);
312
		file = cfg_obj_file(symvalue.as_cpointer);
313
		line = cfg_obj_line(symvalue.as_cpointer);
314
315
		if (file == NULL)
316
			file = "<unknown file>";
317
		cfg_obj_log(obj, logctx, ISC_LOG_ERROR, fmt, key, file, line);
318
		isc_mem_free(mctx, key);
319
		result = ISC_R_EXISTS;
320
	} else if (result != ISC_R_SUCCESS) {
321
		isc_mem_free(mctx, key);
322
	}
323
	return (result);
324
}
325
326
static isc_result_t
327
mustbesecure(const cfg_obj_t *secure, isc_symtab_t *symtab, isc_log_t *logctx,
328
	     isc_mem_t *mctx)
329
{
330
	const cfg_obj_t *obj;
331
	char namebuf[DNS_NAME_FORMATSIZE];
332
	const char *str;
333
	dns_fixedname_t fixed;
334
	dns_name_t *name;
335
	isc_buffer_t b;
336
	isc_result_t result = ISC_R_SUCCESS;
337
338
	dns_fixedname_init(&fixed);
339
	name = dns_fixedname_name(&fixed);
340
	obj = cfg_tuple_get(secure, "name");
341
	str = cfg_obj_asstring(obj);
342
	isc_buffer_init(&b, str, strlen(str));
343
	isc_buffer_add(&b, strlen(str));
344
	result = dns_name_fromtext(name, &b, dns_rootname, ISC_FALSE, NULL);
345
	if (result != ISC_R_SUCCESS) {
346
		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
347
			    "bad domain name '%s'", str);
348
	} else {
349
		dns_name_format(name, namebuf, sizeof(namebuf));
350
		result = nameexist(secure, namebuf, 1, symtab,
351
				   "dnssec-must-be-secure '%s': already "
352
				   "exists previous definition: %s:%u",
353
				   logctx, mctx);
354
	}
355
	return (result);
356
}
357
358
static isc_result_t
359
checkacl(const char *aclname, cfg_aclconfctx_t *actx, const cfg_obj_t *zconfig,
360
	 const cfg_obj_t *voptions, const cfg_obj_t *config,
361
	 isc_log_t *logctx, isc_mem_t *mctx)
362
{
363
	isc_result_t result;
364
	const cfg_obj_t *aclobj = NULL;
365
	const cfg_obj_t *options;
366
	dns_acl_t *acl = NULL;
367
368
	if (zconfig != NULL) {
369
		options = cfg_tuple_get(zconfig, "options");
370
		cfg_map_get(options, aclname, &aclobj);
371
	}
372
	if (voptions != NULL && aclobj == NULL)
373
		cfg_map_get(voptions, aclname, &aclobj);
374
	if (config != NULL && aclobj == NULL) {
375
		options = NULL;
376
		cfg_map_get(config, "options", &options);
377
		if (options != NULL)
378
			cfg_map_get(options, aclname, &aclobj);
379
	}
380
	if (aclobj == NULL)
381
		return (ISC_R_SUCCESS);
382
	result = cfg_acl_fromconfig(aclobj, config, logctx, actx, mctx, &acl);
383
	if (acl != NULL)
384
		dns_acl_detach(&acl);
385
	return (result);
386
}
387
388
static isc_result_t
389
check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
390
	       const cfg_obj_t *config, isc_log_t *logctx, isc_mem_t *mctx)
391
{
392
	isc_result_t result = ISC_R_SUCCESS, tresult;
393
	int i = 0;
394
395
	static const char *acls[] = { "allow-query", "allow-query-cache",
396
		"allow-recursion", "blackhole", "match-clients",
397
		"match-destinations", "sortlist", NULL };
398
399
	while (acls[i] != NULL) {
400
		tresult = checkacl(acls[i++], actx, NULL, voptions, config,
401
				   logctx, mctx);
402
		if (tresult != ISC_R_SUCCESS)
403
			result = tresult;
404
	}
405
	return (result);
406
}
407
408
typedef struct {
409
	const char *name;
410
	unsigned int scale;
411
	unsigned int max;
412
} intervaltable;
413
414
static isc_result_t
415
check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx) {
416
	isc_result_t result = ISC_R_SUCCESS;
417
	isc_result_t tresult;
418
	unsigned int i;
419
	const cfg_obj_t *obj = NULL;
420
	const cfg_listelt_t *element;
421
	isc_symtab_t *symtab = NULL;
422
	dns_fixedname_t fixed;
423
	const char *str;
424
	dns_name_t *name;
425
	isc_buffer_t b;
426
427
	static intervaltable intervals[] = {
428
	{ "cleaning-interval", 60, 28 * 24 * 60 },	/* 28 days */
429
	{ "heartbeat-interval", 60, 28 * 24 * 60 },	/* 28 days */
430
	{ "interface-interval", 60, 28 * 24 * 60 },	/* 28 days */
431
	{ "max-transfer-idle-in", 60, 28 * 24 * 60 },	/* 28 days */
432
	{ "max-transfer-idle-out", 60, 28 * 24 * 60 },	/* 28 days */
433
	{ "max-transfer-time-in", 60, 28 * 24 * 60 },	/* 28 days */
434
	{ "max-transfer-time-out", 60, 28 * 24 * 60 },	/* 28 days */
435
	{ "sig-validity-interval", 86400, 10 * 366 },	/* 10 years */
436
	{ "statistics-interval", 60, 28 * 24 * 60 },	/* 28 days */
437
	};
438
439
	/*
440
	 * Check that fields specified in units of time other than seconds
441
	 * have reasonable values.
442
	 */
443
	for (i = 0; i < sizeof(intervals) / sizeof(intervals[0]); i++) {
444
		isc_uint32_t val;
445
		obj = NULL;
446
		(void)cfg_map_get(options, intervals[i].name, &obj);
447
		if (obj == NULL)
448
			continue;
449
		val = cfg_obj_asuint32(obj);
450
		if (val > intervals[i].max) {
451
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
452
				    "%s '%u' is out of range (0..%u)",
453
				    intervals[i].name, val,
454
				    intervals[i].max);
455
			result = ISC_R_RANGE;
456
		} else if (val > (ISC_UINT32_MAX / intervals[i].scale)) {
457
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
458
				    "%s '%d' is out of range",
459
				    intervals[i].name, val);
460
			result = ISC_R_RANGE;
461
		}
462
	}
463
	obj = NULL;
464
	(void)cfg_map_get(options, "preferred-glue", &obj);
465
	if (obj != NULL) {
466
		const char *str;
467
                str = cfg_obj_asstring(obj);
468
                if (strcasecmp(str, "a") != 0 &&
469
		    strcasecmp(str, "aaaa") != 0 &&
470
		    strcasecmp(str, "none") != 0)
471
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
472
				    "preferred-glue unexpected value '%s'",
473
				    str);
474
	}
475
	obj = NULL;
476
	(void)cfg_map_get(options, "root-delegation-only", &obj);
477
	if (obj != NULL) {
478
		if (!cfg_obj_isvoid(obj)) {
479
			const cfg_listelt_t *element;
480
			const cfg_obj_t *exclude;
481
			const char *str;
482
			dns_fixedname_t fixed;
483
			dns_name_t *name;
484
			isc_buffer_t b;
485
486
			dns_fixedname_init(&fixed);
487
			name = dns_fixedname_name(&fixed);
488
			for (element = cfg_list_first(obj);
489
			     element != NULL;
490
			     element = cfg_list_next(element)) {
491
				exclude = cfg_listelt_value(element);
492
				str = cfg_obj_asstring(exclude);
493
				isc_buffer_init(&b, str, strlen(str));
494
				isc_buffer_add(&b, strlen(str));
495
				tresult = dns_name_fromtext(name, &b,
496
							   dns_rootname,
497
                                                           ISC_FALSE, NULL);
498
				if (tresult != ISC_R_SUCCESS) {
499
					cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
500
						    "bad domain name '%s'",
501
						    str);
502
					result = tresult;
503
				}
504
			}
505
		}
506
	}
507
508
	/*
509
	 * Set supported DNSSEC algorithms.
510
	 */
511
	obj = NULL;
512
	(void)cfg_map_get(options, "disable-algorithms", &obj);
513
	if (obj != NULL) {
514
		for (element = cfg_list_first(obj);
515
		     element != NULL;
516
		     element = cfg_list_next(element))
517
		{
518
			obj = cfg_listelt_value(element);
519
			tresult = disabled_algorithms(obj, logctx);
520
			if (tresult != ISC_R_SUCCESS)
521
				result = tresult;
522
		}
523
	}
524
525
	dns_fixedname_init(&fixed);
526
	name = dns_fixedname_name(&fixed);
527
528
	/*
529
	 * Check the DLV zone name.
530
	 */
531
	obj = NULL;
532
	(void)cfg_map_get(options, "dnssec-lookaside", &obj);
533
	if (obj != NULL) {
534
		tresult = isc_symtab_create(mctx, 100, freekey, mctx,
535
					    ISC_TRUE, &symtab);
536
		if (tresult != ISC_R_SUCCESS)
537
			result = tresult;
538
		for (element = cfg_list_first(obj);
539
		     element != NULL;
540
		     element = cfg_list_next(element))
541
		{
542
			const char *dlv;
543
544
			obj = cfg_listelt_value(element);
545
546
			dlv = cfg_obj_asstring(cfg_tuple_get(obj, "domain"));
547
			isc_buffer_init(&b, dlv, strlen(dlv));
548
			isc_buffer_add(&b, strlen(dlv));
549
			tresult = dns_name_fromtext(name, &b, dns_rootname,
550
						    ISC_TRUE, NULL);
551
			if (tresult != ISC_R_SUCCESS) {
552
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
553
					    "bad domain name '%s'", dlv);
554
				result = tresult;
555
			}
556
			if (symtab != NULL) {
557
				tresult = nameexist(obj, dlv, 1, symtab,
558
						    "dnssec-lookaside '%s': "
559
						    "already exists previous "
560
						    "definition: %s:%u",
561
						    logctx, mctx);
562
				if (tresult != ISC_R_SUCCESS &&
563
				    result == ISC_R_SUCCESS)
564
					result = tresult;
565
			}
566
			/*
567
			 * XXXMPA to be removed when multiple lookaside
568
			 * namespaces are supported.
569
			 */
570
			if (!dns_name_equal(dns_rootname, name)) {
571
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
572
					    "dnssec-lookaside '%s': "
573
					    "non-root not yet supported", dlv);
574
				if (result == ISC_R_SUCCESS)
575
					result = ISC_R_FAILURE;
576
			}
577
			dlv = cfg_obj_asstring(cfg_tuple_get(obj,
578
					       "trust-anchor"));
579
			isc_buffer_init(&b, dlv, strlen(dlv));
580
			isc_buffer_add(&b, strlen(dlv));
581
			tresult = dns_name_fromtext(name, &b, dns_rootname,
582
						    ISC_TRUE, NULL);
583
			if (tresult != ISC_R_SUCCESS) {
584
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
585
					    "bad domain name '%s'", dlv);
586
				if (result == ISC_R_SUCCESS)
587
					result = tresult;
588
			}
589
		}
590
		if (symtab != NULL)
591
			isc_symtab_destroy(&symtab);
592
	}
593
594
	/*
595
	 * Check dnssec-must-be-secure.
596
	 */
597
	obj = NULL;
598
	(void)cfg_map_get(options, "dnssec-must-be-secure", &obj);
599
	if (obj != NULL) {
600
		isc_symtab_t *symtab = NULL;
601
		tresult = isc_symtab_create(mctx, 100, freekey, mctx,
602
					    ISC_FALSE, &symtab);
603
		if (tresult != ISC_R_SUCCESS)
604
			result = tresult;
605
		for (element = cfg_list_first(obj);
606
		     element != NULL;
607
		     element = cfg_list_next(element))
608
		{
609
			obj = cfg_listelt_value(element);
610
			tresult = mustbesecure(obj, symtab, logctx, mctx);
611
			if (tresult != ISC_R_SUCCESS)
612
				result = tresult;
613
		}
614
		if (symtab != NULL)
615
			isc_symtab_destroy(&symtab);
616
	}
617
618
	/*
619
	 * Check empty zone configuration.
620
	 */
621
	obj = NULL;
622
	(void)cfg_map_get(options, "empty-server", &obj);
623
	if (obj != NULL) {
624
		str = cfg_obj_asstring(obj);
625
		isc_buffer_init(&b, str, strlen(str));
626
		isc_buffer_add(&b, strlen(str));
627
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
628
					    dns_rootname, ISC_FALSE, NULL);
629
		if (tresult != ISC_R_SUCCESS) {
630
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
631
				    "empty-server: invalid name '%s'", str);
632
			result = ISC_R_FAILURE;
633
		}
634
	}
635
636
	obj = NULL;
637
	(void)cfg_map_get(options, "empty-contact", &obj);
638
	if (obj != NULL) {
639
		str = cfg_obj_asstring(obj);
640
		isc_buffer_init(&b, str, strlen(str));
641
		isc_buffer_add(&b, strlen(str));
642
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
643
					    dns_rootname, ISC_FALSE, NULL);
644
		if (tresult != ISC_R_SUCCESS) {
645
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
646
				    "empty-contact: invalid name '%s'", str);
647
			result = ISC_R_FAILURE;
648
		}
649
	}
650
651
	obj = NULL;
652
	(void)cfg_map_get(options, "disable-empty-zone", &obj);
653
	for (element = cfg_list_first(obj);
654
	     element != NULL;
655
	     element = cfg_list_next(element))
656
	{
657
		obj = cfg_listelt_value(element);
658
		str = cfg_obj_asstring(obj);
659
		isc_buffer_init(&b, str, strlen(str));
660
		isc_buffer_add(&b, strlen(str));
661
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
662
					    dns_rootname, ISC_FALSE, NULL);
663
		if (tresult != ISC_R_SUCCESS) {
664
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
665
				    "disable-empty-zone: invalid name '%s'",
666
				    str);
667
			result = ISC_R_FAILURE;
668
		}
669
	}
670
671
	return (result);
672
}
673
674
static isc_result_t
675
get_masters_def(const cfg_obj_t *cctx, const char *name, const cfg_obj_t **ret) {
676
	isc_result_t result;
677
	const cfg_obj_t *masters = NULL;
678
	const cfg_listelt_t *elt;
679
680
	result = cfg_map_get(cctx, "masters", &masters);
681
	if (result != ISC_R_SUCCESS)
682
		return (result);
683
	for (elt = cfg_list_first(masters);
684
	     elt != NULL;
685
	     elt = cfg_list_next(elt)) {
686
		const cfg_obj_t *list;
687
		const char *listname;
688
689
		list = cfg_listelt_value(elt);
690
		listname = cfg_obj_asstring(cfg_tuple_get(list, "name"));
691
692
		if (strcasecmp(listname, name) == 0) {
693
			*ret = list;
694
			return (ISC_R_SUCCESS);
695
		}
696
	}
697
	return (ISC_R_NOTFOUND);
698
}
699
700
static isc_result_t
701
validate_masters(const cfg_obj_t *obj, const cfg_obj_t *config,
702
	         isc_uint32_t *countp, isc_log_t *logctx, isc_mem_t *mctx)
703
{
704
	isc_result_t result = ISC_R_SUCCESS;
705
	isc_result_t tresult;
706
	isc_uint32_t count = 0;
707
	isc_symtab_t *symtab = NULL;
708
	isc_symvalue_t symvalue;
709
	const cfg_listelt_t *element;
710
	const cfg_listelt_t **stack = NULL;
711
	isc_uint32_t stackcount = 0, pushed = 0;
712
	const cfg_obj_t *list;
713
714
	REQUIRE(countp != NULL);
715
	result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
716
	if (result != ISC_R_SUCCESS) {
717
		*countp = count;
718
		return (result);
719
	}
720
721
 newlist:
722
	list = cfg_tuple_get(obj, "addresses");
723
	element = cfg_list_first(list);
724
 resume:
725
	for ( ;
726
	     element != NULL;
727
	     element = cfg_list_next(element))
728
	{
729
		const char *listname;
730
		const cfg_obj_t *addr;
731
		const cfg_obj_t *key;
732
733
		addr = cfg_tuple_get(cfg_listelt_value(element),
734
				     "masterselement");
735
		key = cfg_tuple_get(cfg_listelt_value(element), "key");
736
737
		if (cfg_obj_issockaddr(addr)) {
738
			count++;
739
			continue;
740
		}
741
		if (!cfg_obj_isvoid(key)) {
742
			cfg_obj_log(key, logctx, ISC_LOG_ERROR,
743
				    "unexpected token '%s'",
744
				    cfg_obj_asstring(key));
745
			if (result == ISC_R_SUCCESS)
746
				result = ISC_R_FAILURE;
747
		}
748
		listname = cfg_obj_asstring(addr);
749
		symvalue.as_cpointer = addr;
750
		tresult = isc_symtab_define(symtab, listname, 1, symvalue,
751
					    isc_symexists_reject);
752
		if (tresult == ISC_R_EXISTS)
753
			continue;
754
		tresult = get_masters_def(config, listname, &obj);
755
		if (tresult != ISC_R_SUCCESS) {
756
			if (result == ISC_R_SUCCESS)
757
				result = tresult;
758
			cfg_obj_log(addr, logctx, ISC_LOG_ERROR,
759
				    "unable to find masters list '%s'",
760
				    listname);
761
			continue;
762
		}
763
		/* Grow stack? */
764
		if (stackcount == pushed) {
765
			void * new;
766
			isc_uint32_t newlen = stackcount + 16;
767
			size_t newsize, oldsize;
768
769
			newsize = newlen * sizeof(*stack);
770
			oldsize = stackcount * sizeof(*stack);
771
			new = isc_mem_get(mctx, newsize);
772
			if (new == NULL)
773
				goto cleanup;
774
			if (stackcount != 0) {
775
				memcpy(new, stack, oldsize);
776
				isc_mem_put(mctx, stack, oldsize);
777
			}
778
			stack = new;
779
			stackcount = newlen;
780
		}
781
		stack[pushed++] = cfg_list_next(element);
782
		goto newlist;
783
	}
784
	if (pushed != 0) {
785
		element = stack[--pushed];
786
		goto resume;
787
	}
788
 cleanup:
789
	if (stack != NULL)
790
		isc_mem_put(mctx, stack, stackcount * sizeof(*stack));
791
	isc_symtab_destroy(&symtab);
792
	*countp = count;
793
	return (result);
794
}
795
796
static isc_result_t
797
check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
798
	isc_result_t result = ISC_R_SUCCESS;
799
	isc_result_t tresult;
800
	const cfg_listelt_t *element;
801
	const cfg_listelt_t *element2;
802
	dns_fixedname_t fixed;
803
	const char *str;
804
	isc_buffer_t b;
805
806
	for (element = cfg_list_first(policy);
807
	     element != NULL;
808
	     element = cfg_list_next(element))
809
	{
810
		const cfg_obj_t *stmt = cfg_listelt_value(element);
811
		const cfg_obj_t *identity = cfg_tuple_get(stmt, "identity");
812
		const cfg_obj_t *matchtype = cfg_tuple_get(stmt, "matchtype");
813
		const cfg_obj_t *dname = cfg_tuple_get(stmt, "name");
814
		const cfg_obj_t *typelist = cfg_tuple_get(stmt, "types");
815
816
		dns_fixedname_init(&fixed);
817
		str = cfg_obj_asstring(identity);
818
		isc_buffer_init(&b, str, strlen(str));
819
		isc_buffer_add(&b, strlen(str));
820
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
821
                                            dns_rootname, ISC_FALSE, NULL);
822
		if (tresult != ISC_R_SUCCESS) {
823
			cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
824
				    "'%s' is not a valid name", str);
825
			result = tresult;
826
		}
827
828
		dns_fixedname_init(&fixed);
829
		str = cfg_obj_asstring(dname);
830
		isc_buffer_init(&b, str, strlen(str));
831
		isc_buffer_add(&b, strlen(str));
832
		tresult = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
833
					    dns_rootname, ISC_FALSE, NULL);
834
		if (tresult != ISC_R_SUCCESS) {
835
			cfg_obj_log(dname, logctx, ISC_LOG_ERROR,
836
				    "'%s' is not a valid name", str);
837
			result = tresult;
838
		}
839
		if (tresult == ISC_R_SUCCESS &&
840
		    strcasecmp(cfg_obj_asstring(matchtype), "wildcard") == 0 &&
841
		    !dns_name_iswildcard(dns_fixedname_name(&fixed))) {
842
			cfg_obj_log(identity, logctx, ISC_LOG_ERROR,
843
				    "'%s' is not a wildcard", str);
844
			result = ISC_R_FAILURE;
845
		}
846
847
		for (element2 = cfg_list_first(typelist);
848
		     element2 != NULL;
849
		     element2 = cfg_list_next(element2))
850
		{
851
			const cfg_obj_t *typeobj;
852
			isc_textregion_t r;
853
			dns_rdatatype_t type;
854
855
			typeobj = cfg_listelt_value(element2);
856
			DE_CONST(cfg_obj_asstring(typeobj), r.base);
857
			r.length = strlen(r.base);
858
859
			tresult = dns_rdatatype_fromtext(&type, &r);
860
			if (tresult != ISC_R_SUCCESS) {
861
				cfg_obj_log(typeobj, logctx, ISC_LOG_ERROR,
862
                                            "'%s' is not a valid type", r.base);
863
				result = tresult;
864
			}
865
		}
866
	}
867
	return (result);
868
}
869
870
#define MASTERZONE	1
871
#define SLAVEZONE	2
872
#define STUBZONE	4
873
#define HINTZONE	8
874
#define FORWARDZONE	16
875
#define DELEGATIONZONE	32
876
#define CHECKACL	64
877
878
typedef struct {
879
	const char *name;
880
	int allowed;
881
} optionstable;
882
883
static isc_result_t
884
check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
885
	       const cfg_obj_t *config, isc_symtab_t *symtab,
886
	       dns_rdataclass_t defclass, cfg_aclconfctx_t *actx,
887
	       isc_log_t *logctx, isc_mem_t *mctx)
888
{
889
	const char *zname;
890
	const char *typestr;
891
	unsigned int ztype;
892
	const cfg_obj_t *zoptions;
893
	const cfg_obj_t *obj = NULL;
894
	isc_result_t result = ISC_R_SUCCESS;
895
	isc_result_t tresult;
896
	unsigned int i;
897
	dns_rdataclass_t zclass;
898
	dns_fixedname_t fixedname;
899
	isc_buffer_t b;
900
901
	static optionstable options[] = {
902
	{ "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | CHECKACL },
903
	{ "allow-notify", SLAVEZONE | CHECKACL },
904
	{ "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
905
	{ "notify", MASTERZONE | SLAVEZONE },
906
	{ "also-notify", MASTERZONE | SLAVEZONE },
907
	{ "dialup", MASTERZONE | SLAVEZONE | STUBZONE },
908
	{ "delegation-only", HINTZONE | STUBZONE },
909
	{ "forward", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
910
	{ "forwarders", MASTERZONE | SLAVEZONE | STUBZONE | FORWARDZONE},
911
	{ "maintain-ixfr-base", MASTERZONE | SLAVEZONE },
912
	{ "max-ixfr-log-size", MASTERZONE | SLAVEZONE },
913
	{ "notify-source", MASTERZONE | SLAVEZONE },
914
	{ "notify-source-v6", MASTERZONE | SLAVEZONE },
915
	{ "transfer-source", SLAVEZONE | STUBZONE },
916
	{ "transfer-source-v6", SLAVEZONE | STUBZONE },
917
	{ "max-transfer-time-in", SLAVEZONE | STUBZONE },
918
	{ "max-transfer-time-out", MASTERZONE | SLAVEZONE },
919
	{ "max-transfer-idle-in", SLAVEZONE | STUBZONE },
920
	{ "max-transfer-idle-out", MASTERZONE | SLAVEZONE },
921
	{ "max-retry-time", SLAVEZONE | STUBZONE },
922
	{ "min-retry-time", SLAVEZONE | STUBZONE },
923
	{ "max-refresh-time", SLAVEZONE | STUBZONE },
924
	{ "min-refresh-time", SLAVEZONE | STUBZONE },
925
	{ "sig-validity-interval", MASTERZONE },
926
	{ "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE },
927
	{ "allow-update", MASTERZONE | CHECKACL },
928
	{ "allow-update-forwarding", SLAVEZONE | CHECKACL },
929
	{ "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
930
	{ "journal", MASTERZONE | SLAVEZONE },
931
	{ "ixfr-base", MASTERZONE | SLAVEZONE },
932
	{ "ixfr-tmp-file", MASTERZONE | SLAVEZONE },
933
	{ "masters", SLAVEZONE | STUBZONE },
934
	{ "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
935
	{ "update-policy", MASTERZONE },
936
	{ "database", MASTERZONE | SLAVEZONE | STUBZONE },
937
	{ "key-directory", MASTERZONE },
938
	{ "check-wildcard", MASTERZONE },
939
	{ "check-mx", MASTERZONE },
940
	{ "integrity-check", MASTERZONE },
941
	{ "check-mx-cname", MASTERZONE },
942
	{ "check-srv-cname", MASTERZONE },
943
	{ "masterfile-format", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE },
944
	{ "update-check-ksk", MASTERZONE },
945
	};
946
947
	static optionstable dialups[] = {
948
	{ "notify", MASTERZONE | SLAVEZONE },
949
	{ "notify-passive", SLAVEZONE },
950
	{ "refresh", SLAVEZONE | STUBZONE },
951
	{ "passive", SLAVEZONE | STUBZONE },
952
	};
953
954
	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
955
956
	zoptions = cfg_tuple_get(zconfig, "options");
957
958
	obj = NULL;
959
	(void)cfg_map_get(zoptions, "type", &obj);
960
	if (obj == NULL) {
961
		cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
962
			    "zone '%s': type not present", zname);
963
		return (ISC_R_FAILURE);
964
	}
965
966
	typestr = cfg_obj_asstring(obj);
967
	if (strcasecmp(typestr, "master") == 0)
968
		ztype = MASTERZONE;
969
	else if (strcasecmp(typestr, "slave") == 0)
970
		ztype = SLAVEZONE;
971
	else if (strcasecmp(typestr, "stub") == 0)
972
		ztype = STUBZONE;
973
	else if (strcasecmp(typestr, "forward") == 0)
974
		ztype = FORWARDZONE;
975
	else if (strcasecmp(typestr, "hint") == 0)
976
		ztype = HINTZONE;
977
	else if (strcasecmp(typestr, "delegation-only") == 0)
978
		ztype = DELEGATIONZONE;
979
	else {
980
		cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
981
			    "zone '%s': invalid type %s",
982
			    zname, typestr);
983
		return (ISC_R_FAILURE);
984
	}
985
986
	obj = cfg_tuple_get(zconfig, "class");
987
	if (cfg_obj_isstring(obj)) {
988
		isc_textregion_t r;
989
990
		DE_CONST(cfg_obj_asstring(obj), r.base);
991
		r.length = strlen(r.base);
992
		result = dns_rdataclass_fromtext(&zclass, &r);
993
		if (result != ISC_R_SUCCESS) {
994
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
995
				    "zone '%s': invalid class %s",
996
				    zname, r.base);
997
			return (ISC_R_FAILURE);
998
		}
999
		if (zclass != defclass) {
1000
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1001
				    "zone '%s': class '%s' does not "
1002
				    "match view/default class",
1003
				    zname, r.base);
1004
			return (ISC_R_FAILURE);
1005
		}
1006
	}
1007
1008
	/*
1009
	 * Look for an already existing zone.
1010
	 * We need to make this cannonical as isc_symtab_define()
1011
	 * deals with strings.
1012
	 */
1013
	dns_fixedname_init(&fixedname);
1014
	isc_buffer_init(&b, zname, strlen(zname));
1015
	isc_buffer_add(&b, strlen(zname));
1016
	tresult = dns_name_fromtext(dns_fixedname_name(&fixedname), &b,
1017
				   dns_rootname, ISC_TRUE, NULL);
1018
	if (result != ISC_R_SUCCESS) {
1019
		cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1020
			    "zone '%s': is not a valid name", zname);
1021
		tresult = ISC_R_FAILURE;
1022
	} else {
1023
		char namebuf[DNS_NAME_FORMATSIZE];
1024
1025
		dns_name_format(dns_fixedname_name(&fixedname),
1026
				namebuf, sizeof(namebuf));
1027
		tresult = nameexist(zconfig, namebuf, ztype == HINTZONE ? 1 : 2,
1028
				   symtab, "zone '%s': already exists "
1029
				   "previous definition: %s:%u", logctx, mctx);
1030
		if (tresult != ISC_R_SUCCESS)
1031
			result = tresult;
1032
	}
1033
1034
	/*
1035
	 * Look for inappropriate options for the given zone type.
1036
	 * Check that ACLs expand correctly.
1037
	 */
1038
	for (i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
1039
		obj = NULL;
1040
		if ((options[i].allowed & ztype) == 0 &&
1041
		    cfg_map_get(zoptions, options[i].name, &obj) ==
1042
		    ISC_R_SUCCESS)
1043
		{
1044
			if (strcmp(options[i].name, "allow-update") != 0 ||
1045
			    ztype != SLAVEZONE) {
1046
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1047
					    "option '%s' is not allowed "
1048
					    "in '%s' zone '%s'",
1049
					    options[i].name, typestr, zname);
1050
					result = ISC_R_FAILURE;
1051
			} else
1052
				cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1053
					    "option '%s' is not allowed "
1054
					    "in '%s' zone '%s'",
1055
					    options[i].name, typestr, zname);
1056
		}
1057
		obj = NULL;
1058
		if ((options[i].allowed & ztype) != 0 &&
1059
		    (options[i].allowed & CHECKACL) != 0) {
1060
1061
			tresult = checkacl(options[i].name, actx, zconfig,
1062
				           voptions, config, logctx, mctx);
1063
			if (tresult != ISC_R_SUCCESS)
1064
				result = tresult;
1065
		}
1066
1067
	}
1068
1069
	/*
1070
	 * Slave & stub zones must have a "masters" field.
1071
	 */
1072
	if (ztype == SLAVEZONE || ztype == STUBZONE) {
1073
		obj = NULL;
1074
		if (cfg_map_get(zoptions, "masters", &obj) != ISC_R_SUCCESS) {
1075
			cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1076
				    "zone '%s': missing 'masters' entry",
1077
				    zname);
1078
			result = ISC_R_FAILURE;
1079
		} else {
1080
			isc_uint32_t count;
1081
			tresult = validate_masters(obj, config, &count,
1082
						   logctx, mctx);
1083
			if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1084
				result = tresult;
1085
			if (tresult == ISC_R_SUCCESS && count == 0) {
1086
				cfg_obj_log(zoptions, logctx, ISC_LOG_ERROR,
1087
					    "zone '%s': empty 'masters' entry",
1088
					    zname);
1089
				result = ISC_R_FAILURE;
1090
			}
1091
		}
1092
	}
1093
1094
	/*
1095
	 * Master zones can't have both "allow-update" and "update-policy".
1096
	 */
1097
	if (ztype == MASTERZONE) {
1098
		isc_result_t res1, res2;
1099
		obj = NULL;
1100
		res1 = cfg_map_get(zoptions, "allow-update", &obj);
1101
		obj = NULL;
1102
		res2 = cfg_map_get(zoptions, "update-policy", &obj);
1103
		if (res1 == ISC_R_SUCCESS && res2 == ISC_R_SUCCESS) {
1104
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1105
				    "zone '%s': 'allow-update' is ignored "
1106
				    "when 'update-policy' is present",
1107
				    zname);
1108
			result = ISC_R_FAILURE;
1109
		} else if (res2 == ISC_R_SUCCESS &&
1110
			   check_update_policy(obj, logctx) != ISC_R_SUCCESS)
1111
			result = ISC_R_FAILURE;
1112
	}
1113
1114
	/*
1115
	 * Check the excessively complicated "dialup" option.
1116
	 */
1117
	if (ztype == MASTERZONE || ztype == SLAVEZONE || ztype == STUBZONE) {
1118
		const cfg_obj_t *dialup = NULL;
1119
		(void)cfg_map_get(zoptions, "dialup", &dialup);
1120
		if (dialup != NULL && cfg_obj_isstring(dialup)) {
1121
			const char *str = cfg_obj_asstring(dialup);
1122
			for (i = 0;
1123
			     i < sizeof(dialups) / sizeof(dialups[0]);
1124
			     i++)
1125
			{
1126
				if (strcasecmp(dialups[i].name, str) != 0)
1127
					continue;
1128
				if ((dialups[i].allowed & ztype) == 0) {
1129
					cfg_obj_log(obj, logctx,
1130
						    ISC_LOG_ERROR,
1131
						    "dialup type '%s' is not "
1132
						    "allowed in '%s' "
1133
						    "zone '%s'",
1134
						    str, typestr, zname);
1135
					result = ISC_R_FAILURE;
1136
				}
1137
				break;
1138
			}
1139
			if (i == sizeof(dialups) / sizeof(dialups[0])) {
1140
				cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1141
					    "invalid dialup type '%s' in zone "
1142
					    "'%s'", str, zname);
1143
				result = ISC_R_FAILURE;
1144
			}
1145
		}
1146
	}
1147
1148
	/*
1149
	 * Check that forwarding is reasonable.
1150
	 */
1151
	if (check_forward(zoptions, logctx) != ISC_R_SUCCESS)
1152
		result = ISC_R_FAILURE;
1153
1154
	/*
1155
	 * Check various options.
1156
	 */
1157
	tresult = check_options(zoptions, logctx, mctx);
1158
	if (tresult != ISC_R_SUCCESS)
1159
		result = tresult;
1160
1161
	/*
1162
	 * If the zone type is rbt/rbt64 then master/hint zones
1163
	 * require file clauses.
1164
	 */
1165
	obj = NULL;
1166
	tresult = cfg_map_get(zoptions, "database", &obj);
1167
	if (tresult == ISC_R_NOTFOUND ||
1168
	    (tresult == ISC_R_SUCCESS &&
1169
	     (strcmp("rbt", cfg_obj_asstring(obj)) == 0 ||
1170
	      strcmp("rbt64", cfg_obj_asstring(obj)) == 0))) {
1171
		obj = NULL;
1172
		tresult = cfg_map_get(zoptions, "file", &obj);
1173
		if (tresult != ISC_R_SUCCESS &&
1174
		    (ztype == MASTERZONE || ztype == HINTZONE)) {
1175
			cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
1176
				    "zone '%s': missing 'file' entry",
1177
				    zname);
1178
			result = tresult;
1179
		}
1180
	}
1181
1182
	return (result);
1183
}
1184
1185
1186
typedef struct keyalgorithms {
1187
	const char *name;
1188
	isc_uint16_t size;
1189
} algorithmtable;
1190
1191
isc_result_t
1192
bind9_check_key(const cfg_obj_t *key, isc_log_t *logctx) {
1193
	const cfg_obj_t *algobj = NULL;
1194
	const cfg_obj_t *secretobj = NULL;
1195
	const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1196
	const char *algorithm;
1197
	int i;
1198
	size_t len = 0;
1199
	static const algorithmtable algorithms[] = {
1200
		{ "hmac-md5", 128 },
1201
		{ "hmac-md5.sig-alg.reg.int", 0 },
1202
		{ "hmac-md5.sig-alg.reg.int.", 0 },
1203
		{ "hmac-sha1", 160 },
1204
		{ "hmac-sha224", 224 },
1205
		{ "hmac-sha256", 256 },
1206
		{ "hmac-sha384", 384 },
1207
		{ "hmac-sha512", 512 },
1208
		{  NULL, 0 }
1209
	};
1210
1211
	(void)cfg_map_get(key, "algorithm", &algobj);
1212
	(void)cfg_map_get(key, "secret", &secretobj);
1213
	if (secretobj == NULL || algobj == NULL) {
1214
		cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1215
			    "key '%s' must have both 'secret' and "
1216
			    "'algorithm' defined",
1217
			    keyname);
1218
		return (ISC_R_FAILURE);
1219
	}
1220
1221
	algorithm = cfg_obj_asstring(algobj);
1222
	for (i = 0; algorithms[i].name != NULL; i++) {
1223
		len = strlen(algorithms[i].name);
1224
		if (strncasecmp(algorithms[i].name, algorithm, len) == 0 &&
1225
		    (algorithm[len] == '\0' ||
1226
		     (algorithms[i].size != 0 && algorithm[len] == '-')))
1227
			break;
1228
	}
1229
	if (algorithms[i].name == NULL) {
1230
		cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1231
			    "unknown algorithm '%s'", algorithm);
1232
		return (ISC_R_NOTFOUND);
1233
	}
1234
	if (algorithm[len] == '-') {
1235
		isc_uint16_t digestbits;
1236
		isc_result_t result;
1237
		result = isc_parse_uint16(&digestbits, algorithm + len + 1, 10);
1238
		if (result == ISC_R_SUCCESS || result == ISC_R_RANGE) {
1239
			if (result == ISC_R_RANGE ||
1240
			    digestbits > algorithms[i].size) {
1241
				cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1242
					    "key '%s' digest-bits too large "
1243
					    "[%u..%u]", keyname,
1244
					    algorithms[i].size / 2,
1245
					    algorithms[i].size);
1246
				return (ISC_R_RANGE);
1247
			}
1248
			if ((digestbits % 8) != 0) {
1249
				cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1250
					    "key '%s' digest-bits not multiple"
1251
					    " of 8", keyname);
1252
				return (ISC_R_RANGE);
1253
			}
1254
			/*
1255
			 * Recommended minima for hmac algorithms.
1256
			 */
1257
			if ((digestbits < (algorithms[i].size / 2U) ||
1258
			     (digestbits < 80U)))
1259
				cfg_obj_log(algobj, logctx, ISC_LOG_WARNING,
1260
					    "key '%s' digest-bits too small "
1261
					    "[<%u]", keyname,
1262
					    algorithms[i].size/2);
1263
		} else {
1264
			cfg_obj_log(algobj, logctx, ISC_LOG_ERROR,
1265
				    "key '%s': unable to parse digest-bits",
1266
				    keyname);
1267
			return (result);
1268
		}
1269
	}
1270
	return (ISC_R_SUCCESS);
1271
}
1272
1273
static isc_result_t
1274
check_keylist(const cfg_obj_t *keys, isc_symtab_t *symtab, isc_log_t *logctx) {
1275
	isc_result_t result = ISC_R_SUCCESS;
1276
	isc_result_t tresult;
1277
	const cfg_listelt_t *element;
1278
1279
	for (element = cfg_list_first(keys);
1280
	     element != NULL;
1281
	     element = cfg_list_next(element))
1282
	{
1283
		const cfg_obj_t *key = cfg_listelt_value(element);
1284
		const char *keyname = cfg_obj_asstring(cfg_map_getname(key));
1285
		isc_symvalue_t symvalue;
1286
1287
		tresult = bind9_check_key(key, logctx);
1288
		if (tresult != ISC_R_SUCCESS)
1289
			return (tresult);
1290
1291
		symvalue.as_cpointer = key;
1292
		tresult = isc_symtab_define(symtab, keyname, 1,
1293
					    symvalue, isc_symexists_reject);
1294
		if (tresult == ISC_R_EXISTS) {
1295
			const char *file;
1296
			unsigned int line;
1297
1298
			RUNTIME_CHECK(isc_symtab_lookup(symtab, keyname,
1299
					    1, &symvalue) == ISC_R_SUCCESS);
1300
			file = cfg_obj_file(symvalue.as_cpointer);
1301
			line = cfg_obj_line(symvalue.as_cpointer);
1302
1303
			if (file == NULL)
1304
				file = "<unknown file>";
1305
			cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1306
				    "key '%s': already exists "
1307
				    "previous definition: %s:%u",
1308
				    keyname, file, line);
1309
			result = tresult;
1310
		} else if (tresult != ISC_R_SUCCESS)
1311
			return (tresult);
1312
	}
1313
	return (result);
1314
}
1315
1316
static struct {
1317
	const char *v4;
1318
	const char *v6;
1319
} sources[] = {
1320
	{ "transfer-source", "transfer-source-v6" },
1321
	{ "notify-source", "notify-source-v6" },
1322
	{ "query-source", "query-source-v6" },
1323
	{ NULL, NULL }
1324
};
1325
1326
static isc_result_t
1327
check_servers(const cfg_obj_t *servers, isc_log_t *logctx) {
1328
	isc_result_t result = ISC_R_SUCCESS;
1329
	isc_result_t tresult;
1330
	const cfg_listelt_t *e1, *e2;
1331
	const cfg_obj_t *v1, *v2;
1332
	isc_netaddr_t n1, n2;
1333
	unsigned int p1, p2;
1334
	const cfg_obj_t *obj;
1335
	char buf[ISC_NETADDR_FORMATSIZE];
1336
	const char *xfr;
1337
	int source;
1338
1339
	for (e1 = cfg_list_first(servers); e1 != NULL; e1 = cfg_list_next(e1)) {
1340
		v1 = cfg_listelt_value(e1);
1341
		cfg_obj_asnetprefix(cfg_map_getname(v1), &n1, &p1);
1342
		/*
1343
		 * Check that unused bits are zero.
1344
		 */
1345
		tresult = isc_netaddr_prefixok(&n1, p1);
1346
		if (tresult != ISC_R_SUCCESS) {
1347
			INSIST(tresult == ISC_R_FAILURE);
1348
			isc_netaddr_format(&n1, buf, sizeof(buf));
1349
			cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1350
				    "server '%s/%u': invalid prefix "
1351
				    "(extra bits specified)", buf, p1);
1352
			result = tresult;
1353
		}
1354
		source = 0;
1355
		do {
1356
			obj = NULL;
1357
			if (n1.family == AF_INET)
1358
				xfr = sources[source].v6;
1359
			else
1360
				xfr = sources[source].v4;
1361
			(void)cfg_map_get(v1, xfr, &obj);
1362
			if (obj != NULL) {
1363
				isc_netaddr_format(&n1, buf, sizeof(buf));
1364
				cfg_obj_log(v1, logctx, ISC_LOG_ERROR,
1365
					    "server '%s': %s not legal",
1366
					    buf, xfr);
1367
				result = ISC_R_FAILURE;
1368
			}
1369
		} while (sources[++source].v4 != NULL);
1370
		e2 = e1;
1371
		while ((e2 = cfg_list_next(e2)) != NULL) {
1372
			v2 = cfg_listelt_value(e2);
1373
			cfg_obj_asnetprefix(cfg_map_getname(v2), &n2, &p2);
1374
			if (p1 == p2 && isc_netaddr_equal(&n1, &n2)) {
1375
				const char *file = cfg_obj_file(v1);
1376
				unsigned int line = cfg_obj_line(v1);
1377
1378
				if (file == NULL)
1379
					file = "<unknown file>";
1380
1381
				isc_netaddr_format(&n2, buf, sizeof(buf));
1382
				cfg_obj_log(v2, logctx, ISC_LOG_ERROR,
1383
					    "server '%s/%u': already exists "
1384
					    "previous definition: %s:%u",
1385
					    buf, p2, file, line);
1386
				result = ISC_R_FAILURE;
1387
			}
1388
		}
1389
	}
1390
	return (result);
1391
}
1392
1393
static isc_result_t
1394
check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
1395
	       dns_rdataclass_t vclass, isc_log_t *logctx, isc_mem_t *mctx)
1396
{
1397
	const cfg_obj_t *servers = NULL;
1398
	const cfg_obj_t *zones = NULL;
1399
	const cfg_obj_t *keys = NULL;
1400
	const cfg_listelt_t *element;
1401
	isc_symtab_t *symtab = NULL;
1402
	isc_result_t result = ISC_R_SUCCESS;
1403
	isc_result_t tresult = ISC_R_SUCCESS;
1404
	cfg_aclconfctx_t actx;
1405
	const cfg_obj_t *obj;
1406
	isc_boolean_t enablednssec, enablevalidation;
1407
1408
	/*
1409
	 * Check that all zone statements are syntactically correct and
1410
	 * there are no duplicate zones.
1411
	 */
1412
	tresult = isc_symtab_create(mctx, 100, freekey, mctx,
1413
				    ISC_FALSE, &symtab);
1414
	if (tresult != ISC_R_SUCCESS)
1415
		return (ISC_R_NOMEMORY);
1416
1417
	cfg_aclconfctx_init(&actx);
1418
1419
	if (voptions != NULL)
1420
		(void)cfg_map_get(voptions, "zone", &zones);
1421
	else
1422
		(void)cfg_map_get(config, "zone", &zones);
1423
1424
	for (element = cfg_list_first(zones);
1425
	     element != NULL;
1426
	     element = cfg_list_next(element))
1427
	{
1428
		isc_result_t tresult;
1429
		const cfg_obj_t *zone = cfg_listelt_value(element);
1430
1431
		tresult = check_zoneconf(zone, voptions, config, symtab,
1432
					 vclass, &actx, logctx, mctx);
1433
		if (tresult != ISC_R_SUCCESS)
1434
			result = ISC_R_FAILURE;
1435
	}
1436
1437
	isc_symtab_destroy(&symtab);
1438
1439
	/*
1440
	 * Check that all key statements are syntactically correct and
1441
	 * there are no duplicate keys.
1442
	 */
1443
	tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1444
	if (tresult != ISC_R_SUCCESS)
1445
		return (ISC_R_NOMEMORY);
1446
1447
	(void)cfg_map_get(config, "key", &keys);
1448
	tresult = check_keylist(keys, symtab, logctx);
1449
	if (tresult == ISC_R_EXISTS)
1450
		result = ISC_R_FAILURE;
1451
	else if (tresult != ISC_R_SUCCESS) {
1452
		isc_symtab_destroy(&symtab);
1453
		return (tresult);
1454
	}
1455
1456
	if (voptions != NULL) {
1457
		keys = NULL;
1458
		(void)cfg_map_get(voptions, "key", &keys);
1459
		tresult = check_keylist(keys, symtab, logctx);
1460
		if (tresult == ISC_R_EXISTS)
1461
			result = ISC_R_FAILURE;
1462
		else if (tresult != ISC_R_SUCCESS) {
1463
			isc_symtab_destroy(&symtab);
1464
			return (tresult);
1465
		}
1466
	}
1467
1468
	isc_symtab_destroy(&symtab);
1469
1470
	/*
1471
	 * Check that forwarding is reasonable.
1472
	 */
1473
	if (voptions == NULL) {
1474
		const cfg_obj_t *options = NULL;
1475
		(void)cfg_map_get(config, "options", &options);
1476
		if (options != NULL)
1477
			if (check_forward(options, logctx) != ISC_R_SUCCESS)
1478
				result = ISC_R_FAILURE;
1479
	} else {
1480
		if (check_forward(voptions, logctx) != ISC_R_SUCCESS)
1481
			result = ISC_R_FAILURE;
1482
	}
1483
	/*
1484
	 * Check that dual-stack-servers is reasonable.
1485
	 */
1486
	if (voptions == NULL) {
1487
		const cfg_obj_t *options = NULL;
1488
		(void)cfg_map_get(config, "options", &options);
1489
		if (options != NULL)
1490
			if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1491
				result = ISC_R_FAILURE;
1492
	} else {
1493
		if (check_dual_stack(voptions, logctx) != ISC_R_SUCCESS)
1494
			result = ISC_R_FAILURE;
1495
	}
1496
1497
	/*
1498
	 * Check that rrset-order is reasonable.
1499
	 */
1500
	if (voptions != NULL) {
1501
		if (check_order(voptions, logctx) != ISC_R_SUCCESS)
1502
			result = ISC_R_FAILURE;
1503
	}
1504
1505
	if (voptions != NULL) {
1506
		(void)cfg_map_get(voptions, "server", &servers);
1507
		if (servers != NULL &&
1508
		    check_servers(servers, logctx) != ISC_R_SUCCESS)
1509
			result = ISC_R_FAILURE;
1510
	}
1511
1512
	/*
1513
	 * Check that dnssec-enable/dnssec-validation are sensible.
1514
	 */
1515
	obj = NULL;
1516
	if (voptions != NULL)
1517
		(void)cfg_map_get(voptions, "dnssec-enable", &obj);
1518
	if (obj == NULL)
1519
		(void)cfg_map_get(config, "dnssec-enable", &obj);
1520
	if (obj == NULL)
1521
		enablednssec = ISC_TRUE;
1522
	else
1523
		enablednssec = cfg_obj_asboolean(obj);
1524
1525
	obj = NULL;
1526
	if (voptions != NULL)
1527
		(void)cfg_map_get(voptions, "dnssec-validation", &obj);
1528
	if (obj == NULL)
1529
		(void)cfg_map_get(config, "dnssec-validation", &obj);
1530
	if (obj == NULL)
1531
		enablevalidation = ISC_FALSE;	/* XXXMPA Change for 9.5. */
1532
	else
1533
		enablevalidation = cfg_obj_asboolean(obj);
1534
1535
	if (enablevalidation && !enablednssec)
1536
		cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
1537
			    "'dnssec-validation yes;' and 'dnssec-enable no;'");
1538
1539
	if (voptions != NULL)
1540
		tresult = check_options(voptions, logctx, mctx);
1541
	else
1542
		tresult = check_options(config, logctx, mctx);
1543
	if (tresult != ISC_R_SUCCESS)
1544
		result = tresult;
1545
1546
	tresult = check_viewacls(&actx, voptions, config, logctx, mctx);
1547
	if (tresult != ISC_R_SUCCESS)
1548
		result = tresult;
1549
1550
	cfg_aclconfctx_destroy(&actx);
1551
1552
	return (result);
1553
}
1554
1555
static const char *
1556
default_channels[] = {
1557
	"default_syslog",
1558
	"default_stderr",
1559
	"default_debug",
1560
	"null",
1561
	NULL
1562
};
1563
1564
static isc_result_t
1565
bind9_check_logging(const cfg_obj_t *config, isc_log_t *logctx,
1566
		    isc_mem_t *mctx)
1567
{
1568
	const cfg_obj_t *categories = NULL;
1569
	const cfg_obj_t *category;
1570
	const cfg_obj_t *channels = NULL;
1571
	const cfg_obj_t *channel;
1572
	const cfg_listelt_t *element;
1573
	const cfg_listelt_t *delement;
1574
	const char *channelname;
1575
	const char *catname;
1576
	const cfg_obj_t *fileobj = NULL;
1577
        const cfg_obj_t *syslogobj = NULL;
1578
        const cfg_obj_t *nullobj = NULL;
1579
        const cfg_obj_t *stderrobj = NULL;
1580
        const cfg_obj_t *logobj = NULL;
1581
	isc_result_t result = ISC_R_SUCCESS;
1582
	isc_result_t tresult;
1583
	isc_symtab_t *symtab = NULL;
1584
	isc_symvalue_t symvalue;
1585
	int i;
1586
1587
	(void)cfg_map_get(config, "logging", &logobj);
1588
	if (logobj == NULL)
1589
		return (ISC_R_SUCCESS);
1590
1591
	result = isc_symtab_create(mctx, 100, NULL, NULL, ISC_FALSE, &symtab);
1592
	if (result != ISC_R_SUCCESS)
1593
		return (result);
1594
1595
	symvalue.as_cpointer = NULL;
1596
	for (i = 0; default_channels[i] != NULL; i++) {
1597
		tresult = isc_symtab_define(symtab, default_channels[i], 1,
1598
					    symvalue, isc_symexists_replace);
1599
		if (tresult != ISC_R_SUCCESS)
1600
			result = tresult;
1601
	}
1602
1603
	cfg_map_get(logobj, "channel", &channels);
1604
1605
	for (element = cfg_list_first(channels);
1606
	     element != NULL;
1607
	     element = cfg_list_next(element))
1608
	{
1609
		channel = cfg_listelt_value(element);
1610
		channelname = cfg_obj_asstring(cfg_map_getname(channel));
1611
		fileobj = syslogobj = nullobj = stderrobj = NULL;
1612
		(void)cfg_map_get(channel, "file", &fileobj);
1613
		(void)cfg_map_get(channel, "syslog", &syslogobj);
1614
		(void)cfg_map_get(channel, "null", &nullobj);
1615
		(void)cfg_map_get(channel, "stderr", &stderrobj);
1616
		i = 0;
1617
		if (fileobj != NULL)
1618
			i++;
1619
		if (syslogobj != NULL)
1620
			i++;
1621
		if (nullobj != NULL)
1622
			i++;
1623
		if (stderrobj != NULL)
1624
			i++;
1625
		if (i != 1) {
1626
			cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1627
				    "channel '%s': exactly one of file, syslog, "
1628
				    "null, and stderr must be present",
1629
				     channelname);
1630
			result = ISC_R_FAILURE;
1631
		}
1632
		tresult = isc_symtab_define(symtab, channelname, 1,
1633
					    symvalue, isc_symexists_replace);
1634
		if (tresult != ISC_R_SUCCESS)
1635
			result = tresult;
1636
	}
1637
1638
	cfg_map_get(logobj, "category", &categories);
1639
1640
	for (element = cfg_list_first(categories);
1641
             element != NULL;
1642
             element = cfg_list_next(element))
1643
        {
1644
		category = cfg_listelt_value(element);
1645
		catname = cfg_obj_asstring(cfg_tuple_get(category, "name"));
1646
		if (isc_log_categorybyname(logctx, catname) == NULL) {
1647
			cfg_obj_log(category, logctx, ISC_LOG_ERROR,
1648
				    "undefined category: '%s'", catname);
1649
			result = ISC_R_FAILURE;
1650
		}
1651
		channels = cfg_tuple_get(category, "destinations");
1652
		for (delement = cfg_list_first(channels);
1653
		     delement != NULL;
1654
		     delement = cfg_list_next(delement))
1655
		{
1656
			channel = cfg_listelt_value(delement);
1657
			channelname = cfg_obj_asstring(channel);
1658
			tresult = isc_symtab_lookup(symtab, channelname, 1,
1659
                                          	    &symvalue);
1660
			if (tresult != ISC_R_SUCCESS) {
1661
				cfg_obj_log(channel, logctx, ISC_LOG_ERROR,
1662
					    "undefined channel: '%s'",
1663
					    channelname);
1664
				result = tresult;
1665
			}
1666
		}
1667
	}
1668
	isc_symtab_destroy(&symtab);
1669
	return (result);
1670
}
1671
1672
static isc_result_t
1673
key_exists(const cfg_obj_t *keylist, const char *keyname) {
1674
	const cfg_listelt_t *element;
1675
	const char *str;
1676
	const cfg_obj_t *obj;
1677
1678
	if (keylist == NULL)
1679
		return (ISC_R_NOTFOUND);
1680
	for (element = cfg_list_first(keylist);
1681
	     element != NULL;
1682
	     element = cfg_list_next(element))
1683
	{
1684
		obj = cfg_listelt_value(element);
1685
		str = cfg_obj_asstring(cfg_map_getname(obj));
1686
		if (strcasecmp(str, keyname) == 0)
1687
			return (ISC_R_SUCCESS);
1688
	}
1689
	return (ISC_R_NOTFOUND);
1690
}
1691
1692
static isc_result_t
1693
bind9_check_controlskeys(const cfg_obj_t *control, const cfg_obj_t *keylist,
1694
			 isc_log_t *logctx)
1695
{
1696
	isc_result_t result = ISC_R_SUCCESS, tresult;
1697
	const cfg_obj_t *control_keylist;
1698
	const cfg_listelt_t *element;
1699
	const cfg_obj_t *key;
1700
1701
	control_keylist = cfg_tuple_get(control, "keys");
1702
	if (cfg_obj_isvoid(control_keylist))
1703
		return (ISC_R_SUCCESS);
1704
1705
	for (element = cfg_list_first(control_keylist);
1706
	     element != NULL;
1707
	     element = cfg_list_next(element))
1708
	{
1709
		key = cfg_listelt_value(element);
1710
		tresult = key_exists(keylist, cfg_obj_asstring(key));
1711
		if (tresult != ISC_R_SUCCESS) {
1712
			cfg_obj_log(key, logctx, ISC_LOG_ERROR,
1713
				    "unknown key '%s'", cfg_obj_asstring(key));
1714
			result = tresult;
1715
		}
1716
	}
1717
	return (result);
1718
}
1719
1720
static isc_result_t
1721
bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx,
1722
		     isc_mem_t *mctx)
1723
{
1724
	isc_result_t result = ISC_R_SUCCESS, tresult;
1725
	cfg_aclconfctx_t actx;
1726
	const cfg_listelt_t *element, *element2;
1727
	const cfg_obj_t *allow;
1728
	const cfg_obj_t *control;
1729
	const cfg_obj_t *controls;
1730
	const cfg_obj_t *controlslist = NULL;
1731
	const cfg_obj_t *inetcontrols;
1732
	const cfg_obj_t *unixcontrols;
1733
	const cfg_obj_t *keylist = NULL;
1734
	const char *path;
1735
	isc_uint32_t perm, mask;
1736
	dns_acl_t *acl = NULL;
1737
	isc_sockaddr_t addr;
1738
	int i;
1739
1740
	(void)cfg_map_get(config, "controls", &controlslist);
1741
	if (controlslist == NULL)
1742
		return (ISC_R_SUCCESS);
1743
1744
	(void)cfg_map_get(config, "key", &keylist);
1745
1746
	cfg_aclconfctx_init(&actx);
1747
1748
	/*
1749
	 * INET: Check allow clause.
1750
	 * UNIX: Check "perm" for sanity, check path length.
1751
	 */
1752
	for (element = cfg_list_first(controlslist);
1753
	     element != NULL;
1754
	     element = cfg_list_next(element)) {
1755
		controls = cfg_listelt_value(element);
1756
		unixcontrols = NULL;
1757
		inetcontrols = NULL;
1758
		(void)cfg_map_get(controls, "unix", &unixcontrols);
1759
		(void)cfg_map_get(controls, "inet", &inetcontrols);
1760
		for (element2 = cfg_list_first(inetcontrols);
1761
		     element2 != NULL;
1762
		     element2 = cfg_list_next(element2)) {
1763
			control = cfg_listelt_value(element2);
1764
			allow = cfg_tuple_get(control, "allow");
1765
			tresult = cfg_acl_fromconfig(allow, config, logctx,
1766
						     &actx, mctx, &acl);
1767
			if (acl != NULL)
1768
				dns_acl_detach(&acl);
1769
			if (tresult != ISC_R_SUCCESS)
1770
				result = tresult;
1771
			tresult = bind9_check_controlskeys(control, keylist,
1772
							   logctx);
1773
			if (tresult != ISC_R_SUCCESS)
1774
				result = tresult;
1775
		}
1776
		for (element2 = cfg_list_first(unixcontrols);
1777
		     element2 != NULL;
1778
		     element2 = cfg_list_next(element2)) {
1779
			control = cfg_listelt_value(element2);
1780
			path = cfg_obj_asstring(cfg_tuple_get(control, "path"));
1781
			tresult = isc_sockaddr_frompath(&addr, path);
1782
			if (tresult == ISC_R_NOSPACE) {
1783
				cfg_obj_log(control, logctx, ISC_LOG_ERROR,
1784
					    "unix control '%s': path too long",
1785
					    path);
1786
				result = ISC_R_NOSPACE;
1787
			}
1788
			perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm"));
1789
			for (i = 0; i < 3; i++) {
1790
#ifdef NEED_SECURE_DIRECTORY
1791
				mask = (0x1 << (i*3));	/* SEARCH */
1792
#else
1793
				mask = (0x6 << (i*3)); 	/* READ + WRITE */
1794
#endif
1795
				if ((perm & mask) == mask)
1796
					break;
1797
			}
1798
			if (i == 0) {
1799
				cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1800
					    "unix control '%s' allows access "
1801
					    "to everyone", path);
1802
			} else if (i == 3) {
1803
				cfg_obj_log(control, logctx, ISC_LOG_WARNING,
1804
					    "unix control '%s' allows access "
1805
					    "to nobody", path);
1806
			}
1807
			tresult = bind9_check_controlskeys(control, keylist,
1808
							   logctx);
1809
			if (tresult != ISC_R_SUCCESS)
1810
				result = tresult;
1811
		}
1812
	}
1813
	cfg_aclconfctx_destroy(&actx);
1814
	return (result);
1815
}
1816
1817
isc_result_t
1818
bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx,
1819
		      isc_mem_t *mctx)
1820
{
1821
	const cfg_obj_t *options = NULL;
1822
	const cfg_obj_t *servers = NULL;
1823
	const cfg_obj_t *views = NULL;
1824
	const cfg_obj_t *acls = NULL;
1825
	const cfg_obj_t *kals = NULL;
1826
	const cfg_obj_t *obj;
1827
	const cfg_listelt_t *velement;
1828
	isc_result_t result = ISC_R_SUCCESS;
1829
	isc_result_t tresult;
1830
	isc_symtab_t *symtab = NULL;
1831
1832
	static const char *builtin[] = { "localhost", "localnets",
1833
					 "any", "none"};
1834
1835
	(void)cfg_map_get(config, "options", &options);
1836
1837
	if (options != NULL &&
1838
	    check_options(options, logctx, mctx) != ISC_R_SUCCESS)
1839
		result = ISC_R_FAILURE;
1840
1841
	(void)cfg_map_get(config, "server", &servers);
1842
	if (servers != NULL &&
1843
	    check_servers(servers, logctx) != ISC_R_SUCCESS)
1844
		result = ISC_R_FAILURE;
1845
1846
	if (bind9_check_logging(config, logctx, mctx) != ISC_R_SUCCESS)
1847
		result = ISC_R_FAILURE;
1848
1849
	if (bind9_check_controls(config, logctx, mctx) != ISC_R_SUCCESS)
1850
		result = ISC_R_FAILURE;
1851
1852
	if (options != NULL &&
1853
	    check_order(options, logctx) != ISC_R_SUCCESS)
1854
		result = ISC_R_FAILURE;
1855
1856
	(void)cfg_map_get(config, "view", &views);
1857
1858
	if (views != NULL && options != NULL)
1859
		if (check_dual_stack(options, logctx) != ISC_R_SUCCESS)
1860
			result = ISC_R_FAILURE;
1861
1862
	if (views == NULL) {
1863
		if (check_viewconf(config, NULL, dns_rdataclass_in,
1864
				   logctx, mctx) != ISC_R_SUCCESS)
1865
			result = ISC_R_FAILURE;
1866
	} else {
1867
		const cfg_obj_t *zones = NULL;
1868
1869
		(void)cfg_map_get(config, "zone", &zones);
1870
		if (zones != NULL) {
1871
			cfg_obj_log(zones, logctx, ISC_LOG_ERROR,
1872
				    "when using 'view' statements, "
1873
				    "all zones must be in views");
1874
			result = ISC_R_FAILURE;
1875
		}
1876
	}
1877
1878
	tresult = isc_symtab_create(mctx, 100, NULL, NULL, ISC_TRUE, &symtab);
1879
	if (tresult != ISC_R_SUCCESS)
1880
		result = tresult;
1881
	for (velement = cfg_list_first(views);
1882
	     velement != NULL;
1883
	     velement = cfg_list_next(velement))
1884
	{
1885
		const cfg_obj_t *view = cfg_listelt_value(velement);
1886
		const cfg_obj_t *vname = cfg_tuple_get(view, "name");
1887
		const cfg_obj_t *voptions = cfg_tuple_get(view, "options");
1888
		const cfg_obj_t *vclassobj = cfg_tuple_get(view, "class");
1889
		dns_rdataclass_t vclass = dns_rdataclass_in;
1890
		isc_result_t tresult = ISC_R_SUCCESS;
1891
		const char *key = cfg_obj_asstring(vname);
1892
		isc_symvalue_t symvalue;
1893
1894
		if (cfg_obj_isstring(vclassobj)) {
1895
			isc_textregion_t r;
1896
1897
			DE_CONST(cfg_obj_asstring(vclassobj), r.base);
1898
			r.length = strlen(r.base);
1899
			tresult = dns_rdataclass_fromtext(&vclass, &r);
1900
			if (tresult != ISC_R_SUCCESS)
1901
				cfg_obj_log(vclassobj, logctx, ISC_LOG_ERROR,
1902
					    "view '%s': invalid class %s",
1903
					    cfg_obj_asstring(vname), r.base);
1904
		}
1905
		if (tresult == ISC_R_SUCCESS && symtab != NULL) {
1906
			symvalue.as_cpointer = view;
1907
			tresult = isc_symtab_define(symtab, key, vclass,
1908
						    symvalue,
1909
						    isc_symexists_reject);
1910
			if (tresult == ISC_R_EXISTS) {
1911
				const char *file;
1912
				unsigned int line;
1913
				RUNTIME_CHECK(isc_symtab_lookup(symtab, key,
1914
				           vclass, &symvalue) == ISC_R_SUCCESS);
1915
				file = cfg_obj_file(symvalue.as_cpointer);
1916
				line = cfg_obj_line(symvalue.as_cpointer);
1917
				cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1918
					    "view '%s': already exists "
1919
					    "previous definition: %s:%u",
1920
					    key, file, line);
1921
				result = tresult;
1922
			} else if (result != ISC_R_SUCCESS) {
1923
				result = tresult;
1924
			} else if ((strcasecmp(key, "_bind") == 0 &&
1925
				    vclass == dns_rdataclass_ch) ||
1926
				   (strcasecmp(key, "_default") == 0 &&
1927
				    vclass == dns_rdataclass_in)) {
1928
				cfg_obj_log(view, logctx, ISC_LOG_ERROR,
1929
					    "attempt to redefine builtin view "
1930
					    "'%s'", key);
1931
				result = ISC_R_EXISTS;
1932
			}
1933
		}
1934
		if (tresult == ISC_R_SUCCESS)
1935
			tresult = check_viewconf(config, voptions,
1936
						 vclass, logctx, mctx);
1937
		if (tresult != ISC_R_SUCCESS)
1938
			result = ISC_R_FAILURE;
1939
	}
1940
	if (symtab != NULL)
1941
		isc_symtab_destroy(&symtab);
1942
1943
	if (views != NULL && options != NULL) {
1944
		obj = NULL;
1945
		tresult = cfg_map_get(options, "cache-file", &obj);
1946
		if (tresult == ISC_R_SUCCESS) {
1947
			cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
1948
				    "'cache-file' cannot be a global "
1949
				    "option if views are present");
1950
			result = ISC_R_FAILURE;
1951
		}
1952
	}
1953
1954
        tresult = cfg_map_get(config, "acl", &acls);
1955
        if (tresult == ISC_R_SUCCESS) {
1956
		const cfg_listelt_t *elt;
1957
		const cfg_listelt_t *elt2;
1958
		const char *aclname;
1959
1960
		for (elt = cfg_list_first(acls);
1961
		     elt != NULL;
1962
		     elt = cfg_list_next(elt)) {
1963
			const cfg_obj_t *acl = cfg_listelt_value(elt);
1964
			unsigned int i;
1965
1966
			aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
1967
			for (i = 0;
1968
			     i < sizeof(builtin) / sizeof(builtin[0]);
1969
			     i++)
1970
				if (strcasecmp(aclname, builtin[i]) == 0) {
1971
					cfg_obj_log(acl, logctx, ISC_LOG_ERROR,
1972
						    "attempt to redefine "
1973
						    "builtin acl '%s'",
1974
				    		    aclname);
1975
					result = ISC_R_FAILURE;
1976
					break;
1977
				}
1978
1979
			for (elt2 = cfg_list_next(elt);
1980
			     elt2 != NULL;
1981
			     elt2 = cfg_list_next(elt2)) {
1982
				const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
1983
				const char *name;
1984
				name = cfg_obj_asstring(cfg_tuple_get(acl2,
1985
								      "name"));
1986
				if (strcasecmp(aclname, name) == 0) {
1987
					const char *file = cfg_obj_file(acl);
1988
					unsigned int line = cfg_obj_line(acl);
1989
1990
					if (file == NULL)
1991
						file = "<unknown file>";
1992
1993
					cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
1994
						    "attempt to redefine "
1995
						    "acl '%s' previous "
1996
						    "definition: %s:%u",
1997
						     name, file, line);
1998
					result = ISC_R_FAILURE;
1999
				}
2000
			}
2001
		}
2002
	}
2003
2004
        tresult = cfg_map_get(config, "kal", &kals);
2005
        if (tresult == ISC_R_SUCCESS) {
2006
		const cfg_listelt_t *elt;
2007
		const cfg_listelt_t *elt2;
2008
		const char *aclname;
2009
2010
		for (elt = cfg_list_first(kals);
2011
		     elt != NULL;
2012
		     elt = cfg_list_next(elt)) {
2013
			const cfg_obj_t *acl = cfg_listelt_value(elt);
2014
2015
			aclname = cfg_obj_asstring(cfg_tuple_get(acl, "name"));
2016
2017
			for (elt2 = cfg_list_next(elt);
2018
			     elt2 != NULL;
2019
			     elt2 = cfg_list_next(elt2)) {
2020
				const cfg_obj_t *acl2 = cfg_listelt_value(elt2);
2021
				const char *name;
2022
				name = cfg_obj_asstring(cfg_tuple_get(acl2,
2023
								      "name"));
2024
				if (strcasecmp(aclname, name) == 0) {
2025
					const char *file = cfg_obj_file(acl);
2026
					unsigned int line = cfg_obj_line(acl);
2027
2028
					if (file == NULL)
2029
						file = "<unknown file>";
2030
2031
					cfg_obj_log(acl2, logctx, ISC_LOG_ERROR,
2032
						    "attempt to redefine "
2033
						    "kal '%s' previous "
2034
						    "definition: %s:%u",
2035
						     name, file, line);
2036
					result = ISC_R_FAILURE;
2037
				}
2038
			}
2039
		}
2040
	}
2041
2042
	return (result);
2043
}