No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / bin / check / named-checkconf.c
blob10195f823f87f77f5631c3ac5912269d2c0d8c22
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: named-checkconf.c,v 1.51 2009/12/04 21:09:32 marka Exp */
22 /*! \file */
24 #include <config.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdio.h>
30 #include <isc/commandline.h>
31 #include <isc/dir.h>
32 #include <isc/entropy.h>
33 #include <isc/hash.h>
34 #include <isc/log.h>
35 #include <isc/mem.h>
36 #include <isc/result.h>
37 #include <isc/string.h>
38 #include <isc/util.h>
40 #include <isccfg/namedconf.h>
42 #include <bind9/check.h>
44 #include <dns/fixedname.h>
45 #include <dns/log.h>
46 #include <dns/name.h>
47 #include <dns/result.h>
48 #include <dns/zone.h>
50 #include "check-tool.h"
52 static const char *program = "named-checkconf";
54 isc_log_t *logc = NULL;
56 #define CHECK(r)\
57 do { \
58 result = (r); \
59 if (result != ISC_R_SUCCESS) \
60 goto cleanup; \
61 } while (0)
63 /*% usage */
64 ISC_PLATFORM_NORETURN_PRE static void
65 usage(void) ISC_PLATFORM_NORETURN_POST;
67 static void
68 usage(void) {
69 fprintf(stderr, "usage: %s [-h] [-j] [-v] [-z] [-t directory] "
70 "[named.conf]\n", program);
71 exit(1);
74 /*% directory callback */
75 static isc_result_t
76 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
77 isc_result_t result;
78 const char *directory;
80 REQUIRE(strcasecmp("directory", clausename) == 0);
82 UNUSED(arg);
83 UNUSED(clausename);
86 * Change directory.
88 directory = cfg_obj_asstring(obj);
89 result = isc_dir_chdir(directory);
90 if (result != ISC_R_SUCCESS) {
91 cfg_obj_log(obj, logc, ISC_LOG_ERROR,
92 "change directory to '%s' failed: %s\n",
93 directory, isc_result_totext(result));
94 return (result);
97 return (ISC_R_SUCCESS);
100 static isc_boolean_t
101 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
102 int i;
103 for (i = 0;; i++) {
104 if (maps[i] == NULL)
105 return (ISC_FALSE);
106 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
107 return (ISC_TRUE);
111 static isc_boolean_t
112 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
113 const cfg_listelt_t *element;
114 const cfg_obj_t *checknames;
115 const cfg_obj_t *type;
116 const cfg_obj_t *value;
117 isc_result_t result;
118 int i;
120 for (i = 0;; i++) {
121 if (maps[i] == NULL)
122 return (ISC_FALSE);
123 checknames = NULL;
124 result = cfg_map_get(maps[i], "check-names", &checknames);
125 if (result != ISC_R_SUCCESS)
126 continue;
127 if (checknames != NULL && !cfg_obj_islist(checknames)) {
128 *obj = checknames;
129 return (ISC_TRUE);
131 for (element = cfg_list_first(checknames);
132 element != NULL;
133 element = cfg_list_next(element)) {
134 value = cfg_listelt_value(element);
135 type = cfg_tuple_get(value, "type");
136 if (strcasecmp(cfg_obj_asstring(type), "master") != 0)
137 continue;
138 *obj = cfg_tuple_get(value, "mode");
139 return (ISC_TRUE);
144 static isc_result_t
145 config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
146 int i;
148 for (i = 0;; i++) {
149 if (maps[i] == NULL)
150 return (ISC_R_NOTFOUND);
151 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
152 return (ISC_R_SUCCESS);
156 /*% configure the zone */
157 static isc_result_t
158 configure_zone(const char *vclass, const char *view,
159 const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
160 const cfg_obj_t *config, isc_mem_t *mctx)
162 int i = 0;
163 isc_result_t result;
164 const char *zclass;
165 const char *zname;
166 const char *zfile;
167 const cfg_obj_t *maps[4];
168 const cfg_obj_t *zoptions = NULL;
169 const cfg_obj_t *classobj = NULL;
170 const cfg_obj_t *typeobj = NULL;
171 const cfg_obj_t *fileobj = NULL;
172 const cfg_obj_t *dbobj = NULL;
173 const cfg_obj_t *obj = NULL;
174 const cfg_obj_t *fmtobj = NULL;
175 dns_masterformat_t masterformat;
177 zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
179 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
180 classobj = cfg_tuple_get(zconfig, "class");
181 if (!cfg_obj_isstring(classobj))
182 zclass = vclass;
183 else
184 zclass = cfg_obj_asstring(classobj);
186 zoptions = cfg_tuple_get(zconfig, "options");
187 maps[i++] = zoptions;
188 if (vconfig != NULL)
189 maps[i++] = cfg_tuple_get(vconfig, "options");
190 if (config != NULL) {
191 cfg_map_get(config, "options", &obj);
192 if (obj != NULL)
193 maps[i++] = obj;
195 maps[i++] = NULL;
197 cfg_map_get(zoptions, "type", &typeobj);
198 if (typeobj == NULL)
199 return (ISC_R_FAILURE);
200 if (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0)
201 return (ISC_R_SUCCESS);
202 cfg_map_get(zoptions, "database", &dbobj);
203 if (dbobj != NULL)
204 return (ISC_R_SUCCESS);
205 cfg_map_get(zoptions, "file", &fileobj);
206 if (fileobj == NULL)
207 return (ISC_R_FAILURE);
208 zfile = cfg_obj_asstring(fileobj);
210 obj = NULL;
211 if (get_maps(maps, "check-dup-records", &obj)) {
212 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
213 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
214 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
215 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
216 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
217 zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
218 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
219 zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
220 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
221 } else
222 INSIST(0);
223 } else {
224 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
225 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
228 obj = NULL;
229 if (get_maps(maps, "check-mx", &obj)) {
230 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
231 zone_options |= DNS_ZONEOPT_CHECKMX;
232 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
233 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
234 zone_options |= DNS_ZONEOPT_CHECKMX;
235 zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
236 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
237 zone_options &= ~DNS_ZONEOPT_CHECKMX;
238 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
239 } else
240 INSIST(0);
241 } else {
242 zone_options |= DNS_ZONEOPT_CHECKMX;
243 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
246 obj = NULL;
247 if (get_maps(maps, "check-integrity", &obj)) {
248 if (cfg_obj_asboolean(obj))
249 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
250 else
251 zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
252 } else
253 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
255 obj = NULL;
256 if (get_maps(maps, "check-mx-cname", &obj)) {
257 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
258 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
259 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
260 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
261 zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
262 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
263 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
264 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
265 zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
266 } else
267 INSIST(0);
268 } else {
269 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
270 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
273 obj = NULL;
274 if (get_maps(maps, "check-srv-cname", &obj)) {
275 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
276 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
277 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
278 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
279 zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
280 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
281 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
282 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
283 zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
284 } else
285 INSIST(0);
286 } else {
287 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
288 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
291 obj = NULL;
292 if (get_maps(maps, "check-sibling", &obj)) {
293 if (cfg_obj_asboolean(obj))
294 zone_options |= DNS_ZONEOPT_CHECKSIBLING;
295 else
296 zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
299 obj = NULL;
300 if (get_checknames(maps, &obj)) {
301 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
302 zone_options |= DNS_ZONEOPT_CHECKNAMES;
303 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
304 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
305 zone_options |= DNS_ZONEOPT_CHECKNAMES;
306 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
307 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
308 zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
309 zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
310 } else
311 INSIST(0);
312 } else {
313 zone_options |= DNS_ZONEOPT_CHECKNAMES;
314 zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
317 masterformat = dns_masterformat_text;
318 fmtobj = NULL;
319 result = config_get(maps, "masterfile-format", &fmtobj);
320 if (result == ISC_R_SUCCESS) {
321 const char *masterformatstr = cfg_obj_asstring(fmtobj);
322 if (strcasecmp(masterformatstr, "text") == 0)
323 masterformat = dns_masterformat_text;
324 else if (strcasecmp(masterformatstr, "raw") == 0)
325 masterformat = dns_masterformat_raw;
326 else
327 INSIST(0);
330 result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL);
331 if (result != ISC_R_SUCCESS)
332 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
333 dns_result_totext(result));
334 return(result);
337 /*% configure a view */
338 static isc_result_t
339 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
340 const cfg_obj_t *vconfig, isc_mem_t *mctx)
342 const cfg_listelt_t *element;
343 const cfg_obj_t *voptions;
344 const cfg_obj_t *zonelist;
345 isc_result_t result = ISC_R_SUCCESS;
346 isc_result_t tresult;
348 voptions = NULL;
349 if (vconfig != NULL)
350 voptions = cfg_tuple_get(vconfig, "options");
352 zonelist = NULL;
353 if (voptions != NULL)
354 (void)cfg_map_get(voptions, "zone", &zonelist);
355 else
356 (void)cfg_map_get(config, "zone", &zonelist);
358 for (element = cfg_list_first(zonelist);
359 element != NULL;
360 element = cfg_list_next(element))
362 const cfg_obj_t *zconfig = cfg_listelt_value(element);
363 tresult = configure_zone(vclass, view, zconfig, vconfig,
364 config, mctx);
365 if (tresult != ISC_R_SUCCESS)
366 result = tresult;
368 return (result);
372 /*% load zones from the configuration */
373 static isc_result_t
374 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
375 const cfg_listelt_t *element;
376 const cfg_obj_t *classobj;
377 const cfg_obj_t *views;
378 const cfg_obj_t *vconfig;
379 const char *vclass;
380 isc_result_t result = ISC_R_SUCCESS;
381 isc_result_t tresult;
383 views = NULL;
385 (void)cfg_map_get(config, "view", &views);
386 for (element = cfg_list_first(views);
387 element != NULL;
388 element = cfg_list_next(element))
390 const char *vname;
392 vclass = "IN";
393 vconfig = cfg_listelt_value(element);
394 if (vconfig != NULL) {
395 classobj = cfg_tuple_get(vconfig, "class");
396 if (cfg_obj_isstring(classobj))
397 vclass = cfg_obj_asstring(classobj);
399 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
400 tresult = configure_view(vclass, vname, config, vconfig, mctx);
401 if (tresult != ISC_R_SUCCESS)
402 result = tresult;
405 if (views == NULL) {
406 tresult = configure_view("IN", "_default", config, NULL, mctx);
407 if (tresult != ISC_R_SUCCESS)
408 result = tresult;
410 return (result);
413 static void
414 output(void *closure, const char *text, int textlen) {
415 UNUSED(closure);
416 if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
417 perror("fwrite");
418 exit(1);
422 /*% The main processing routine */
424 main(int argc, char **argv) {
425 int c;
426 cfg_parser_t *parser = NULL;
427 cfg_obj_t *config = NULL;
428 const char *conffile = NULL;
429 isc_mem_t *mctx = NULL;
430 isc_result_t result;
431 int exit_status = 0;
432 isc_entropy_t *ectx = NULL;
433 isc_boolean_t load_zones = ISC_FALSE;
434 isc_boolean_t print = ISC_FALSE;
436 isc_commandline_errprint = ISC_FALSE;
438 while ((c = isc_commandline_parse(argc, argv, "dhjt:pvz")) != EOF) {
439 switch (c) {
440 case 'd':
441 debug++;
442 break;
444 case 'j':
445 nomerge = ISC_FALSE;
446 break;
448 case 't':
449 result = isc_dir_chroot(isc_commandline_argument);
450 if (result != ISC_R_SUCCESS) {
451 fprintf(stderr, "isc_dir_chroot: %s\n",
452 isc_result_totext(result));
453 exit(1);
455 break;
457 case 'p':
458 print = ISC_TRUE;
459 break;
461 case 'v':
462 printf(VERSION "\n");
463 exit(0);
465 case 'z':
466 load_zones = ISC_TRUE;
467 docheckmx = ISC_FALSE;
468 docheckns = ISC_FALSE;
469 dochecksrv = ISC_FALSE;
470 break;
472 case '?':
473 if (isc_commandline_option != '?')
474 fprintf(stderr, "%s: invalid argument -%c\n",
475 program, isc_commandline_option);
476 case 'h':
477 usage();
479 default:
480 fprintf(stderr, "%s: unhandled option -%c\n",
481 program, isc_commandline_option);
482 exit(1);
486 if (isc_commandline_index + 1 < argc)
487 usage();
488 if (argv[isc_commandline_index] != NULL)
489 conffile = argv[isc_commandline_index];
490 if (conffile == NULL || conffile[0] == '\0')
491 conffile = NAMED_CONFFILE;
493 RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
495 RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
497 RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
498 RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
499 == ISC_R_SUCCESS);
501 dns_result_register();
503 RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
505 cfg_parser_setcallback(parser, directory_callback, NULL);
507 if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
508 ISC_R_SUCCESS)
509 exit(1);
511 result = bind9_check_namedconf(config, logc, mctx);
512 if (result != ISC_R_SUCCESS)
513 exit_status = 1;
515 if (result == ISC_R_SUCCESS && load_zones) {
516 result = load_zones_fromconfig(config, mctx);
517 if (result != ISC_R_SUCCESS)
518 exit_status = 1;
521 if (print && exit_status == 0)
522 cfg_print(config, output, NULL);
523 cfg_obj_destroy(parser, &config);
525 cfg_parser_destroy(&parser);
527 dns_name_destroy();
529 isc_log_destroy(&logc);
531 isc_hash_destroy();
532 isc_entropy_detach(&ectx);
534 isc_mem_destroy(&mctx);
536 return (exit_status);