]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/bin/check/named-checkconf.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / bin / check / named-checkconf.c
1 /*
2  * Copyright (C) 2004-2007, 2009-2011  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: named-checkconf.c,v 1.54.62.2 2011/03/12 04:59:13 tbox Exp $ */
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] [-p] [-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-dup-records", &obj)) {
210                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
211                         zone_options |= DNS_ZONEOPT_CHECKDUPRR;
212                         zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
213                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
214                         zone_options |= DNS_ZONEOPT_CHECKDUPRR;
215                         zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
216                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
217                         zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
218                         zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
219                 } else
220                         INSIST(0);
221         } else {
222                 zone_options |= DNS_ZONEOPT_CHECKDUPRR;
223                 zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
224         }
225
226         obj = NULL;
227         if (get_maps(maps, "check-mx", &obj)) {
228                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
229                         zone_options |= DNS_ZONEOPT_CHECKMX;
230                         zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
231                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
232                         zone_options |= DNS_ZONEOPT_CHECKMX;
233                         zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
234                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
235                         zone_options &= ~DNS_ZONEOPT_CHECKMX;
236                         zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
237                 } else
238                         INSIST(0);
239         } else {
240                 zone_options |= DNS_ZONEOPT_CHECKMX;
241                 zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
242         }
243
244         obj = NULL;
245         if (get_maps(maps, "check-integrity", &obj)) {
246                 if (cfg_obj_asboolean(obj))
247                         zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
248                 else
249                         zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
250         } else
251                 zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
252
253         obj = NULL;
254         if (get_maps(maps, "check-mx-cname", &obj)) {
255                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
256                         zone_options |= DNS_ZONEOPT_WARNMXCNAME;
257                         zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
258                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
259                         zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
260                         zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
261                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
262                         zone_options |= DNS_ZONEOPT_WARNMXCNAME;
263                         zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
264                 } else
265                         INSIST(0);
266         } else {
267                 zone_options |= DNS_ZONEOPT_WARNMXCNAME;
268                 zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
269         }
270
271         obj = NULL;
272         if (get_maps(maps, "check-srv-cname", &obj)) {
273                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
274                         zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
275                         zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
276                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
277                         zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
278                         zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
279                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
280                         zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
281                         zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
282                 } else
283                         INSIST(0);
284         } else {
285                 zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
286                 zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
287         }
288
289         obj = NULL;
290         if (get_maps(maps, "check-sibling", &obj)) {
291                 if (cfg_obj_asboolean(obj))
292                         zone_options |= DNS_ZONEOPT_CHECKSIBLING;
293                 else
294                         zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
295         }
296
297         obj = NULL;
298         if (get_checknames(maps, &obj)) {
299                 if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
300                         zone_options |= DNS_ZONEOPT_CHECKNAMES;
301                         zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
302                 } else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
303                         zone_options |= DNS_ZONEOPT_CHECKNAMES;
304                         zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
305                 } else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
306                         zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
307                         zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
308                 } else
309                         INSIST(0);
310         } else {
311                zone_options |= DNS_ZONEOPT_CHECKNAMES;
312                zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
313         }
314
315         masterformat = dns_masterformat_text;
316         fmtobj = NULL;
317         result = config_get(maps, "masterfile-format", &fmtobj);
318         if (result == ISC_R_SUCCESS) {
319                 const char *masterformatstr = cfg_obj_asstring(fmtobj);
320                 if (strcasecmp(masterformatstr, "text") == 0)
321                         masterformat = dns_masterformat_text;
322                 else if (strcasecmp(masterformatstr, "raw") == 0)
323                         masterformat = dns_masterformat_raw;
324                 else
325                         INSIST(0);
326         }
327
328         result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL);
329         if (result != ISC_R_SUCCESS)
330                 fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
331                         dns_result_totext(result));
332         return(result);
333 }
334
335 /*% configure a view */
336 static isc_result_t
337 configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
338                const cfg_obj_t *vconfig, isc_mem_t *mctx)
339 {
340         const cfg_listelt_t *element;
341         const cfg_obj_t *voptions;
342         const cfg_obj_t *zonelist;
343         isc_result_t result = ISC_R_SUCCESS;
344         isc_result_t tresult;
345
346         voptions = NULL;
347         if (vconfig != NULL)
348                 voptions = cfg_tuple_get(vconfig, "options");
349
350         zonelist = NULL;
351         if (voptions != NULL)
352                 (void)cfg_map_get(voptions, "zone", &zonelist);
353         else
354                 (void)cfg_map_get(config, "zone", &zonelist);
355
356         for (element = cfg_list_first(zonelist);
357              element != NULL;
358              element = cfg_list_next(element))
359         {
360                 const cfg_obj_t *zconfig = cfg_listelt_value(element);
361                 tresult = configure_zone(vclass, view, zconfig, vconfig,
362                                          config, mctx);
363                 if (tresult != ISC_R_SUCCESS)
364                         result = tresult;
365         }
366         return (result);
367 }
368
369
370 /*% load zones from the configuration */
371 static isc_result_t
372 load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
373         const cfg_listelt_t *element;
374         const cfg_obj_t *classobj;
375         const cfg_obj_t *views;
376         const cfg_obj_t *vconfig;
377         const char *vclass;
378         isc_result_t result = ISC_R_SUCCESS;
379         isc_result_t tresult;
380
381         views = NULL;
382
383         (void)cfg_map_get(config, "view", &views);
384         for (element = cfg_list_first(views);
385              element != NULL;
386              element = cfg_list_next(element))
387         {
388                 const char *vname;
389
390                 vclass = "IN";
391                 vconfig = cfg_listelt_value(element);
392                 if (vconfig != NULL) {
393                         classobj = cfg_tuple_get(vconfig, "class");
394                         if (cfg_obj_isstring(classobj))
395                                 vclass = cfg_obj_asstring(classobj);
396                 }
397                 vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
398                 tresult = configure_view(vclass, vname, config, vconfig, mctx);
399                 if (tresult != ISC_R_SUCCESS)
400                         result = tresult;
401         }
402
403         if (views == NULL) {
404                 tresult = configure_view("IN", "_default", config, NULL, mctx);
405                 if (tresult != ISC_R_SUCCESS)
406                         result = tresult;
407         }
408         return (result);
409 }
410
411 static void
412 output(void *closure, const char *text, int textlen) {
413         UNUSED(closure);
414         if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
415                 perror("fwrite");
416                 exit(1);
417         }
418 }
419
420 /*% The main processing routine */
421 int
422 main(int argc, char **argv) {
423         int c;
424         cfg_parser_t *parser = NULL;
425         cfg_obj_t *config = NULL;
426         const char *conffile = NULL;
427         isc_mem_t *mctx = NULL;
428         isc_result_t result;
429         int exit_status = 0;
430         isc_entropy_t *ectx = NULL;
431         isc_boolean_t load_zones = ISC_FALSE;
432         isc_boolean_t print = ISC_FALSE;
433
434         isc_commandline_errprint = ISC_FALSE;
435
436         while ((c = isc_commandline_parse(argc, argv, "dhjt:pvz")) != EOF) {
437                 switch (c) {
438                 case 'd':
439                         debug++;
440                         break;
441
442                 case 'j':
443                         nomerge = ISC_FALSE;
444                         break;
445
446                 case 't':
447                         result = isc_dir_chroot(isc_commandline_argument);
448                         if (result != ISC_R_SUCCESS) {
449                                 fprintf(stderr, "isc_dir_chroot: %s\n",
450                                         isc_result_totext(result));
451                                 exit(1);
452                         }
453                         break;
454
455                 case 'p':
456                         print = ISC_TRUE;
457                         break;
458
459                 case 'v':
460                         printf(VERSION "\n");
461                         exit(0);
462
463                 case 'z':
464                         load_zones = ISC_TRUE;
465                         docheckmx = ISC_FALSE;
466                         docheckns = ISC_FALSE;
467                         dochecksrv = ISC_FALSE;
468                         break;
469
470                 case '?':
471                         if (isc_commandline_option != '?')
472                                 fprintf(stderr, "%s: invalid argument -%c\n",
473                                         program, isc_commandline_option);
474                 case 'h':
475                         usage();
476
477                 default:
478                         fprintf(stderr, "%s: unhandled option -%c\n",
479                                 program, isc_commandline_option);
480                         exit(1);
481                 }
482         }
483
484         if (isc_commandline_index + 1 < argc)
485                 usage();
486         if (argv[isc_commandline_index] != NULL)
487                 conffile = argv[isc_commandline_index];
488         if (conffile == NULL || conffile[0] == '\0')
489                 conffile = NAMED_CONFFILE;
490
491 #ifdef _WIN32
492         InitSockets();
493 #endif
494
495         RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
496
497         RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
498
499         RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
500         RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
501                       == ISC_R_SUCCESS);
502
503         dns_result_register();
504
505         RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
506
507         cfg_parser_setcallback(parser, directory_callback, NULL);
508
509         if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
510             ISC_R_SUCCESS)
511                 exit(1);
512
513         result = bind9_check_namedconf(config, logc, mctx);
514         if (result != ISC_R_SUCCESS)
515                 exit_status = 1;
516
517         if (result == ISC_R_SUCCESS && load_zones) {
518                 result = load_zones_fromconfig(config, mctx);
519                 if (result != ISC_R_SUCCESS)
520                         exit_status = 1;
521         }
522
523         if (print && exit_status == 0)
524                 cfg_print(config, output, NULL);
525         cfg_obj_destroy(parser, &config);
526
527         cfg_parser_destroy(&parser);
528
529         dns_name_destroy();
530
531         isc_log_destroy(&logc);
532
533         isc_hash_destroy();
534         isc_entropy_detach(&ectx);
535
536         isc_mem_destroy(&mctx);
537
538 #ifdef _WIN32
539         DestroySockets();
540 #endif
541
542         return (exit_status);
543 }