named-checkconf.c revision 165071
1/*
2 * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and 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.12.12.11 2006/03/02 00:37:20 marka Exp $ */
19
20#include <config.h>
21
22#include <errno.h>
23#include <stdlib.h>
24#include <stdio.h>
25
26#include <isc/commandline.h>
27#include <isc/dir.h>
28#include <isc/entropy.h>
29#include <isc/hash.h>
30#include <isc/log.h>
31#include <isc/mem.h>
32#include <isc/result.h>
33#include <isc/string.h>
34#include <isc/util.h>
35
36#include <isccfg/namedconf.h>
37
38#include <bind9/check.h>
39
40#include <dns/fixedname.h>
41#include <dns/log.h>
42#include <dns/result.h>
43
44#include "check-tool.h"
45
46isc_log_t *logc = NULL;
47
48#define CHECK(r)\
49	do { \
50		result = (r); \
51		if (result != ISC_R_SUCCESS) \
52			goto cleanup; \
53	} while (0)
54
55static void
56usage(void) {
57        fprintf(stderr, "usage: named-checkconf [-j] [-v] [-z] [-t directory] "
58		"[named.conf]\n");
59        exit(1);
60}
61
62static isc_result_t
63directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
64	isc_result_t result;
65	const char *directory;
66
67	REQUIRE(strcasecmp("directory", clausename) == 0);
68
69	UNUSED(arg);
70	UNUSED(clausename);
71
72	/*
73	 * Change directory.
74	 */
75	directory = cfg_obj_asstring(obj);
76	result = isc_dir_chdir(directory);
77	if (result != ISC_R_SUCCESS) {
78		cfg_obj_log(obj, logc, ISC_LOG_ERROR,
79			    "change directory to '%s' failed: %s\n",
80			    directory, isc_result_totext(result));
81		return (result);
82	}
83
84	return (ISC_R_SUCCESS);
85}
86
87static isc_result_t
88configure_zone(const char *vclass, const char *view,
89	       const cfg_obj_t *zconfig, isc_mem_t *mctx)
90{
91	isc_result_t result;
92	const char *zclass;
93	const char *zname;
94	const char *zfile;
95	const cfg_obj_t *zoptions = NULL;
96	const cfg_obj_t *classobj = NULL;
97	const cfg_obj_t *typeobj = NULL;
98	const cfg_obj_t *fileobj = NULL;
99	const cfg_obj_t *dbobj = NULL;
100
101	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
102	classobj = cfg_tuple_get(zconfig, "class");
103        if (!cfg_obj_isstring(classobj))
104                zclass = vclass;
105        else
106		zclass = cfg_obj_asstring(classobj);
107	zoptions = cfg_tuple_get(zconfig, "options");
108	cfg_map_get(zoptions, "type", &typeobj);
109	if (typeobj == NULL)
110		return (ISC_R_FAILURE);
111	if (strcasecmp(cfg_obj_asstring(typeobj), "master") != 0)
112		return (ISC_R_SUCCESS);
113        cfg_map_get(zoptions, "database", &dbobj);
114        if (dbobj != NULL)
115                return (ISC_R_SUCCESS);
116	cfg_map_get(zoptions, "file", &fileobj);
117	if (fileobj == NULL)
118		return (ISC_R_FAILURE);
119	zfile = cfg_obj_asstring(fileobj);
120	result = load_zone(mctx, zname, zfile, zclass, NULL);
121	if (result != ISC_R_SUCCESS)
122		fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
123			dns_result_totext(result));
124	return(result);
125}
126
127static isc_result_t
128configure_view(const char *vclass, const char *view, const cfg_obj_t *config,
129	       const cfg_obj_t *vconfig, isc_mem_t *mctx)
130{
131	const cfg_listelt_t *element;
132	const cfg_obj_t *voptions;
133	const cfg_obj_t *zonelist;
134	isc_result_t result = ISC_R_SUCCESS;
135	isc_result_t tresult;
136
137	voptions = NULL;
138	if (vconfig != NULL)
139		voptions = cfg_tuple_get(vconfig, "options");
140
141	zonelist = NULL;
142	if (voptions != NULL)
143		(void)cfg_map_get(voptions, "zone", &zonelist);
144	else
145		(void)cfg_map_get(config, "zone", &zonelist);
146
147	for (element = cfg_list_first(zonelist);
148	     element != NULL;
149	     element = cfg_list_next(element))
150	{
151		const cfg_obj_t *zconfig = cfg_listelt_value(element);
152		tresult = configure_zone(vclass, view, zconfig, mctx);
153		if (tresult != ISC_R_SUCCESS)
154			result = tresult;
155	}
156	return (result);
157}
158
159
160static isc_result_t
161load_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
162	const cfg_listelt_t *element;
163	const cfg_obj_t *classobj;
164	const cfg_obj_t *views;
165	const cfg_obj_t *vconfig;
166	const char *vclass;
167	isc_result_t result = ISC_R_SUCCESS;
168	isc_result_t tresult;
169
170	views = NULL;
171
172	(void)cfg_map_get(config, "view", &views);
173	for (element = cfg_list_first(views);
174	     element != NULL;
175	     element = cfg_list_next(element))
176	{
177		const char *vname;
178
179		vclass = "IN";
180		vconfig = cfg_listelt_value(element);
181		if (vconfig != NULL) {
182			classobj = cfg_tuple_get(vconfig, "class");
183			if (cfg_obj_isstring(classobj))
184				vclass = cfg_obj_asstring(classobj);
185		}
186		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
187		tresult = configure_view(vclass, vname, config, vconfig, mctx);
188		if (tresult != ISC_R_SUCCESS)
189			result = tresult;
190	}
191
192	if (views == NULL) {
193		tresult = configure_view("IN", "_default", config, NULL, mctx);
194		if (tresult != ISC_R_SUCCESS)
195			result = tresult;
196	}
197	return (result);
198}
199
200int
201main(int argc, char **argv) {
202	int c;
203	cfg_parser_t *parser = NULL;
204	cfg_obj_t *config = NULL;
205	const char *conffile = NULL;
206	isc_mem_t *mctx = NULL;
207	isc_result_t result;
208	int exit_status = 0;
209	isc_entropy_t *ectx = NULL;
210	isc_boolean_t load_zones = ISC_FALSE;
211
212	while ((c = isc_commandline_parse(argc, argv, "djt:vz")) != EOF) {
213		switch (c) {
214		case 'd':
215			debug++;
216			break;
217
218		case 'j':
219			nomerge = ISC_FALSE;
220			break;
221
222		case 't':
223			result = isc_dir_chroot(isc_commandline_argument);
224			if (result != ISC_R_SUCCESS) {
225				fprintf(stderr, "isc_dir_chroot: %s\n",
226					isc_result_totext(result));
227				exit(1);
228			}
229			result = isc_dir_chdir("/");
230			if (result != ISC_R_SUCCESS) {
231				fprintf(stderr, "isc_dir_chdir: %s\n",
232					isc_result_totext(result));
233				exit(1);
234			}
235			break;
236
237		case 'v':
238			printf(VERSION "\n");
239			exit(0);
240
241		case 'z':
242			load_zones = ISC_TRUE;
243			break;
244
245		default:
246			usage();
247		}
248	}
249
250	if (argv[isc_commandline_index] != NULL)
251		conffile = argv[isc_commandline_index];
252	if (conffile == NULL || conffile[0] == '\0')
253		conffile = NAMED_CONFFILE;
254
255	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
256
257	RUNTIME_CHECK(setup_logging(mctx, &logc) == ISC_R_SUCCESS);
258
259	RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
260	RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
261		      == ISC_R_SUCCESS);
262
263	dns_result_register();
264
265	RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
266
267	cfg_parser_setcallback(parser, directory_callback, NULL);
268
269	if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
270	    ISC_R_SUCCESS)
271		exit(1);
272
273	result = bind9_check_namedconf(config, logc, mctx);
274	if (result != ISC_R_SUCCESS)
275		exit_status = 1;
276
277	if (result == ISC_R_SUCCESS && load_zones) {
278		dns_log_init(logc);
279                dns_log_setcontext(logc);
280		result = load_zones_fromconfig(config, mctx);
281		if (result != ISC_R_SUCCESS)
282			exit_status = 1;
283	}
284
285	cfg_obj_destroy(parser, &config);
286
287	cfg_parser_destroy(&parser);
288
289	isc_log_destroy(&logc);
290
291	isc_hash_destroy();
292	isc_entropy_detach(&ectx);
293
294	isc_mem_destroy(&mctx);
295
296	return (exit_status);
297}
298