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