]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - contrib/bind9/bin/check/named-checkconf.c
Update to version 9.6-ESV-R6, the latest from ISC, which contains numerous
[FreeBSD/stable/8.git] / contrib / bind9 / bin / check / named-checkconf.c
1 /*
2  * Copyright (C) 2004-2007, 2009-2012  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  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 /* $Id$ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 #include <isc/commandline.h>
29 #include <isc/dir.h>
30 #include <isc/entropy.h>
31 #include <isc/hash.h>
32 #include <isc/log.h>
33 #include <isc/mem.h>
34 #include <isc/result.h>
35 #include <isc/string.h>
36 #include <isc/util.h>
37
38 #include <isccfg/namedconf.h>
39
40 #include <bind9/check.h>
41
42 #include <dns/fixedname.h>
43 #include <dns/log.h>
44 #include <dns/name.h>
45 #include <dns/result.h>
46 #include <dns/zone.h>
47
48 #include "check-tool.h"
49
50 static const char *program = "named-checkconf";
51
52 isc_log_t *logc = NULL;
53
54 #define CHECK(r)\
55         do { \
56                 result = (r); \
57                 if (result != ISC_R_SUCCESS) \
58                         goto cleanup; \
59         } while (0)
60
61 /*% usage */
62 ISC_PLATFORM_NORETURN_PRE static void
63 usage(void) ISC_PLATFORM_NORETURN_POST;
64
65 static void
66 usage(void) {
67         fprintf(stderr, "usage: %s [-h] [-j] [-v] [-z] [-t directory] "
68                 "[named.conf]\n", program);
69         exit(1);
70 }
71
72 /*% directory callback */
73 static isc_result_t
74 directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
75         isc_result_t result;
76         const char *directory;
77
78         REQUIRE(strcasecmp("directory", clausename) == 0);
79
80         UNUSED(arg);
81         UNUSED(clausename);
82
83         /*
84          * Change directory.
85          */
86         directory = cfg_obj_asstring(obj);
87         result = isc_dir_chdir(directory);
88         if (result != ISC_R_SUCCESS) {
89                 cfg_obj_log(obj, logc, ISC_LOG_ERROR,
90                             "change directory to '%s' failed: %s\n",
91                             directory, isc_result_totext(result));
92                 return (result);
93         }
94
95         return (ISC_R_SUCCESS);
96 }
97
98 static isc_boolean_t
99 get_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
100         int i;
101         for (i = 0;; i++) {
102                 if (maps[i] == NULL)
103                         return (ISC_FALSE);
104                 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
105                         return (ISC_TRUE);
106         }
107 }
108
109 static isc_boolean_t
110 get_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
111         const cfg_listelt_t *element;
112         const cfg_obj_t *checknames;
113         const cfg_obj_t *type;
114         const cfg_obj_t *value;
115         isc_result_t result;
116         int i;
117
118         for (i = 0;; i++) {
119                 if (maps[i] == NULL)
120                         return (ISC_FALSE);
121                 checknames = NULL;
122                 result = cfg_map_get(maps[i], "check-names", &checknames);
123                 if (result != ISC_R_SUCCESS)
124                         continue;
125                 if (checknames != NULL && !cfg_obj_islist(checknames)) {
126                         *obj = checknames;
127                         return (ISC_TRUE);
128                 }
129                 for (element = cfg_list_first(checknames);
130                      element != NULL;
131                      element = cfg_list_next(element)) {
132                         value = cfg_listelt_value(element);
133                         type = cfg_tuple_get(value, "type");
134                         if (strcasecmp(cfg_obj_asstring(type), "master") != 0)
135                                 continue;
136                         *obj = cfg_tuple_get(value, "mode");
137                         return (ISC_TRUE);
138                 }
139         }
140 }
141
142 static isc_result_t
143 config_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
144         int i;
145
146         for (i = 0;; i++) {
147                 if (maps[i] == NULL)
148                         return (ISC_R_NOTFOUND);
149                 if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
150                         return (ISC_R_SUCCESS);
151         }
152 }
153
154 /*% configure the zone */
155 static isc_result_t
156 configure_zone(const char *vclass, const char *view,
157                const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
158                const cfg_obj_t *config, isc_mem_t *mctx)
159 {
160         int i = 0;
161         isc_result_t result;
162         const char *zclass;
163         const char *zname;
164         const char *zfile;
165         const cfg_obj_t *maps[4];
166         const cfg_obj_t *zoptions = NULL;
167         const cfg_obj_t *classobj = NULL;
168         const cfg_obj_t *typeobj = NULL;
169         const cfg_obj_t *fileobj = NULL;
170         const cfg_obj_t *dbobj = NULL;
171         const cfg_obj_t *obj = NULL;
172         const cfg_obj_t *fmtobj = NULL;
173         dns_masterformat_t masterformat;
174
175         zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
176
177         zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
178         classobj = cfg_tuple_get(zconfig, "class");
179         if (!cfg_obj_isstring(classobj))
180                 zclass = vclass;
181         else
182                 zclass = cfg_obj_asstring(classobj);
183
184         zoptions = cfg_tuple_get(zconfig, "options");
185         maps[i++] = zoptions;
186         if (vconfig != NULL)
187                 maps[i++] = cfg_tuple_get(vconfig, "options");
188         if (config != NULL) {
189                 cfg_map_get(config, "options", &obj);
190                 if (obj != NULL)
191                         maps[i++] = obj;
192         }
193         maps[i] = NULL;
194
195         cfg_map_get(zoptions, "type", &typeobj);
196         if (typeobj == NULL)
197                 return (ISC_R_FAILURE);
198         if (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0)
199                 return (ISC_R_SUCCESS);
200         cfg_map_get(zoptions, "database", &dbobj);
201         if (dbobj != NULL)
202                 return (ISC_R_SUCCESS);
203         cfg_map_get(zoptions, "file", &fileobj);
204         if (fileobj == NULL)
205                 return (ISC_R_FAILURE);
206         zfile = cfg_obj_asstring(fileobj);
207
208         obj = NULL;
209         if (get_maps(maps, "check-mx", &obj)) {
210                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
211                         zone_options |= DNS_ZONEOPT_CHECKMX;
212                         zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
213                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
214                         zone_options |= DNS_ZONEOPT_CHECKMX;
215                         zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
216                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
217                         zone_options &= ~DNS_ZONEOPT_CHECKMX;
218                         zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
219                 } else
220                         INSIST(0);
221         } else {
222                 zone_options |= DNS_ZONEOPT_CHECKMX;
223                 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
224         }
225
226         obj = NULL;
227         if (get_maps(maps, "check-integrity", &obj)) {
228                 if (cfg_obj_asboolean(obj))
229                         zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
230                 else
231                         zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
232         } else
233                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
234
235         obj = NULL;
236         if (get_maps(maps, "check-mx-cname", &obj)) {
237                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
238                         zone_options |= DNS_ZONEOPT_WARNMXCNAME;
239                         zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
240                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
241                         zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
242                         zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
243                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
244                         zone_options |= DNS_ZONEOPT_WARNMXCNAME;
245                         zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
246                 } else
247                         INSIST(0);
248         } else {
249                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
250                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
251         }
252
253         obj = NULL;
254         if (get_maps(maps, "check-srv-cname", &obj)) {
255                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
256                         zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
257                         zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
258                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
259                         zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
260                         zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
261                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
262                         zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
263                         zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
264                 } else
265                         INSIST(0);
266         } else {
267                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
268                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
269         }
270
271         obj = NULL;
272         if (get_maps(maps, "check-sibling", &obj)) {
273                 if (cfg_obj_asboolean(obj))
274                         zone_options |= DNS_ZONEOPT_CHECKSIBLING;
275                 else
276                         zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
277         }
278
279         obj = NULL;
280         if (get_checknames(maps, &obj)) {
281                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
282                         zone_options |= DNS_ZONEOPT_CHECKNAMES;
283                         zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
284                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
285                         zone_options |= DNS_ZONEOPT_CHECKNAMES;
286                         zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
287                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
288                         zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
289                         zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
290                 } else
291                         INSIST(0);
292         } else {
293                zone_options |= DNS_ZONEOPT_CHECKNAMES;
294                zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
295         }
296
297         masterformat = dns_masterformat_text;
298         fmtobj = NULL;
299         result = config_get(maps, "masterfile-format", &fmtobj);
300         if (result == ISC_R_SUCCESS) {
301                 const char *masterformatstr = cfg_obj_asstring(fmtobj);
302                 if (strcasecmp(masterformatstr, "text") == 0)
303                         masterformat = dns_masterformat_text;
304                 else if (strcasecmp(masterformatstr, "raw") == 0)
305                         masterformat = dns_masterformat_raw;
306                 else
307                         INSIST(0);
308         }
309
310         result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL);
311         if (result != ISC_R_SUCCESS)
312                 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
313                         dns_result_totext(result));
314         return(result);
315 }
316
317 /*% configure a view */
318 static isc_result_t
319 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
320                const cfg_obj_t *vconfig, isc_mem_t *mctx)
321 {
322         const cfg_listelt_t *element;
323         const cfg_obj_t *voptions;
324         const cfg_obj_t *zonelist;
325         isc_result_t result = ISC_R_SUCCESS;
326         isc_result_t tresult;
327
328         voptions = NULL;
329         if (vconfig != NULL)
330                 voptions = cfg_tuple_get(vconfig, "options");
331
332         zonelist = NULL;
333         if (voptions != NULL)
334                 (void)cfg_map_get(voptions, "zone", &zonelist);
335         else
336                 (void)cfg_map_get(config, "zone", &zonelist);
337
338         for (element = cfg_list_first(zonelist);
339              element != NULL;
340              element = cfg_list_next(element))
341         {
342                 const cfg_obj_t *zconfig = cfg_listelt_value(element);
343                 tresult = configure_zone(vclass, view, zconfig, vconfig,
344                                          config, mctx);
345                 if (tresult != ISC_R_SUCCESS)
346                         result = tresult;
347         }
348         return (result);
349 }
350
351
352 /*% load zones from the configuration */
353 static isc_result_t
354 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
355         const cfg_listelt_t *element;
356         const cfg_obj_t *classobj;
357         const cfg_obj_t *views;
358         const cfg_obj_t *vconfig;
359         const char *vclass;
360         isc_result_t result = ISC_R_SUCCESS;
361         isc_result_t tresult;
362
363         views = NULL;
364
365         (void)cfg_map_get(config, "view", &views);
366         for (element = cfg_list_first(views);
367              element != NULL;
368              element = cfg_list_next(element))
369         {
370                 const char *vname;
371
372                 vclass = "IN";
373                 vconfig = cfg_listelt_value(element);
374                 if (vconfig != NULL) {
375                         classobj = cfg_tuple_get(vconfig, "class");
376                         if (cfg_obj_isstring(classobj))
377                                 vclass = cfg_obj_asstring(classobj);
378                 }
379                 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
380                 tresult = configure_view(vclass, vname, config, vconfig, mctx);
381                 if (tresult != ISC_R_SUCCESS)
382                         result = tresult;
383         }
384
385         if (views == NULL) {
386                 tresult = configure_view("IN", "_default", config, NULL, mctx);
387                 if (tresult != ISC_R_SUCCESS)
388                         result = tresult;
389         }
390         return (result);
391 }
392
393 /*% The main processing routine */
394 int
395 main(int argc, char **argv) {
396         int c;
397         cfg_parser_t *parser = NULL;
398         cfg_obj_t *config = NULL;
399         const char *conffile = NULL;
400         isc_mem_t *mctx = NULL;
401         isc_result_t result;
402         int exit_status = 0;
403         isc_entropy_t *ectx = NULL;
404         isc_boolean_t load_zones = ISC_FALSE;
405
406         isc_commandline_errprint = ISC_FALSE;
407
408         while ((c = isc_commandline_parse(argc, argv, "dhjt:vz")) != EOF) {
409                 switch (c) {
410                 case 'd':
411                         debug++;
412                         break;
413
414                 case 'j':
415                         nomerge = ISC_FALSE;
416                         break;
417
418                 case 't':
419                         result = isc_dir_chroot(isc_commandline_argument);
420                         if (result != ISC_R_SUCCESS) {
421                                 fprintf(stderr, "isc_dir_chroot: %s\n",
422                                         isc_result_totext(result));
423                                 exit(1);
424                         }
425                         break;
426
427                 case 'v':
428                         printf(VERSION "\n");
429                         exit(0);
430
431                 case 'z':
432                         load_zones = ISC_TRUE;
433                         docheckmx = ISC_FALSE;
434                         docheckns = ISC_FALSE;
435                         dochecksrv = ISC_FALSE;
436                         break;
437
438                 case '?':
439                         if (isc_commandline_option != '?')
440                                 fprintf(stderr, "%s: invalid argument -%c\n",
441                                         program, isc_commandline_option);
442                 case 'h':
443                         usage();
444
445                 default:
446                         fprintf(stderr, "%s: unhandled option -%c\n",
447                                 program, isc_commandline_option);
448                         exit(1);
449                 }
450         }
451
452         if (isc_commandline_index + 1 < argc)
453                 usage();
454         if (argv[isc_commandline_index] != NULL)
455                 conffile = argv[isc_commandline_index];
456         if (conffile == NULL || conffile[0] == '\0')
457                 conffile = NAMED_CONFFILE;
458
459 #ifdef _WIN32
460         InitSockets();
461 #endif
462
463         RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
464
465         RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
466
467         RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
468         RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
469                       == ISC_R_SUCCESS);
470
471         dns_result_register();
472
473         RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
474
475         cfg_parser_setcallback(parser, directory_callback, NULL);
476
477         if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
478             ISC_R_SUCCESS)
479                 exit(1);
480
481         result = bind9_check_namedconf(config, logc, mctx);
482         if (result != ISC_R_SUCCESS)
483                 exit_status = 1;
484
485         if (result == ISC_R_SUCCESS && load_zones) {
486                 result = load_zones_fromconfig(config, mctx);
487                 if (result != ISC_R_SUCCESS)
488                         exit_status = 1;
489         }
490
491         cfg_obj_destroy(parser, &config);
492
493         cfg_parser_destroy(&parser);
494
495         dns_name_destroy();
496
497         isc_log_destroy(&logc);
498
499         isc_hash_destroy();
500         isc_entropy_detach(&ectx);
501
502         isc_mem_destroy(&mctx);
503
504 #ifdef _WIN32
505         DestroySockets();
506 #endif
507
508         return (exit_status);
509 }