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