1135446Strhodes/*
2262706Serwin * Copyright (C) 2004-2007, 2009-2014  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 1999-2002  Internet Software Consortium.
4135446Strhodes *
5186462Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18254897Serwin/* $Id: named-checkconf.c,v 1.56 2011/03/12 04:59:46 tbox Exp $ */
19135446Strhodes
20170222Sdougb/*! \file */
21170222Sdougb
22135446Strhodes#include <config.h>
23135446Strhodes
24135446Strhodes#include <errno.h>
25135446Strhodes#include <stdlib.h>
26135446Strhodes#include <stdio.h>
27135446Strhodes
28135446Strhodes#include <isc/commandline.h>
29135446Strhodes#include <isc/dir.h>
30143731Sdougb#include <isc/entropy.h>
31143731Sdougb#include <isc/hash.h>
32135446Strhodes#include <isc/log.h>
33135446Strhodes#include <isc/mem.h>
34135446Strhodes#include <isc/result.h>
35135446Strhodes#include <isc/string.h>
36135446Strhodes#include <isc/util.h>
37135446Strhodes
38135446Strhodes#include <isccfg/namedconf.h>
39135446Strhodes
40135446Strhodes#include <bind9/check.h>
41135446Strhodes
42262706Serwin#include <dns/db.h>
43143731Sdougb#include <dns/fixedname.h>
44135446Strhodes#include <dns/log.h>
45170222Sdougb#include <dns/name.h>
46262706Serwin#include <dns/rdataclass.h>
47135446Strhodes#include <dns/result.h>
48262706Serwin#include <dns/rootns.h>
49170222Sdougb#include <dns/zone.h>
50135446Strhodes
51135446Strhodes#include "check-tool.h"
52135446Strhodes
53193149Sdougbstatic const char *program = "named-checkconf";
54193149Sdougb
55135446Strhodesisc_log_t *logc = NULL;
56135446Strhodes
57135446Strhodes#define CHECK(r)\
58135446Strhodes	do { \
59135446Strhodes		result = (r); \
60135446Strhodes		if (result != ISC_R_SUCCESS) \
61135446Strhodes			goto cleanup; \
62135446Strhodes	} while (0)
63135446Strhodes
64170222Sdougb/*% usage */
65224092SdougbISC_PLATFORM_NORETURN_PRE static void
66224092Sdougbusage(void) ISC_PLATFORM_NORETURN_POST;
67224092Sdougb
68135446Strhodesstatic void
69135446Strhodesusage(void) {
70224092Sdougb	fprintf(stderr, "usage: %s [-h] [-j] [-p] [-v] [-z] [-t directory] "
71193149Sdougb		"[named.conf]\n", program);
72193149Sdougb	exit(1);
73135446Strhodes}
74135446Strhodes
75170222Sdougb/*% directory callback */
76135446Strhodesstatic isc_result_t
77165071Sdougbdirectory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
78135446Strhodes	isc_result_t result;
79165071Sdougb	const char *directory;
80135446Strhodes
81135446Strhodes	REQUIRE(strcasecmp("directory", clausename) == 0);
82135446Strhodes
83135446Strhodes	UNUSED(arg);
84135446Strhodes	UNUSED(clausename);
85135446Strhodes
86135446Strhodes	/*
87135446Strhodes	 * Change directory.
88135446Strhodes	 */
89135446Strhodes	directory = cfg_obj_asstring(obj);
90135446Strhodes	result = isc_dir_chdir(directory);
91135446Strhodes	if (result != ISC_R_SUCCESS) {
92135446Strhodes		cfg_obj_log(obj, logc, ISC_LOG_ERROR,
93135446Strhodes			    "change directory to '%s' failed: %s\n",
94135446Strhodes			    directory, isc_result_totext(result));
95135446Strhodes		return (result);
96135446Strhodes	}
97135446Strhodes
98135446Strhodes	return (ISC_R_SUCCESS);
99135446Strhodes}
100135446Strhodes
101170222Sdougbstatic isc_boolean_t
102170222Sdougbget_maps(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
103170222Sdougb	int i;
104170222Sdougb	for (i = 0;; i++) {
105170222Sdougb		if (maps[i] == NULL)
106170222Sdougb			return (ISC_FALSE);
107170222Sdougb		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
108170222Sdougb			return (ISC_TRUE);
109170222Sdougb	}
110170222Sdougb}
111170222Sdougb
112170222Sdougbstatic isc_boolean_t
113170222Sdougbget_checknames(const cfg_obj_t **maps, const cfg_obj_t **obj) {
114170222Sdougb	const cfg_listelt_t *element;
115170222Sdougb	const cfg_obj_t *checknames;
116170222Sdougb	const cfg_obj_t *type;
117170222Sdougb	const cfg_obj_t *value;
118170222Sdougb	isc_result_t result;
119170222Sdougb	int i;
120170222Sdougb
121170222Sdougb	for (i = 0;; i++) {
122170222Sdougb		if (maps[i] == NULL)
123170222Sdougb			return (ISC_FALSE);
124170222Sdougb		checknames = NULL;
125170222Sdougb		result = cfg_map_get(maps[i], "check-names", &checknames);
126170222Sdougb		if (result != ISC_R_SUCCESS)
127170222Sdougb			continue;
128170222Sdougb		if (checknames != NULL && !cfg_obj_islist(checknames)) {
129170222Sdougb			*obj = checknames;
130170222Sdougb			return (ISC_TRUE);
131170222Sdougb		}
132170222Sdougb		for (element = cfg_list_first(checknames);
133170222Sdougb		     element != NULL;
134170222Sdougb		     element = cfg_list_next(element)) {
135170222Sdougb			value = cfg_listelt_value(element);
136170222Sdougb			type = cfg_tuple_get(value, "type");
137170222Sdougb			if (strcasecmp(cfg_obj_asstring(type), "master") != 0)
138170222Sdougb				continue;
139170222Sdougb			*obj = cfg_tuple_get(value, "mode");
140170222Sdougb			return (ISC_TRUE);
141170222Sdougb		}
142170222Sdougb	}
143170222Sdougb}
144170222Sdougb
145135446Strhodesstatic isc_result_t
146170222Sdougbconfig_get(const cfg_obj_t **maps, const char *name, const cfg_obj_t **obj) {
147170222Sdougb	int i;
148170222Sdougb
149170222Sdougb	for (i = 0;; i++) {
150170222Sdougb		if (maps[i] == NULL)
151170222Sdougb			return (ISC_R_NOTFOUND);
152170222Sdougb		if (cfg_map_get(maps[i], name, obj) == ISC_R_SUCCESS)
153170222Sdougb			return (ISC_R_SUCCESS);
154170222Sdougb	}
155170222Sdougb}
156170222Sdougb
157262706Serwinstatic isc_result_t
158262706Serwinconfigure_hint(const char *zfile, const char *zclass, isc_mem_t *mctx) {
159262706Serwin	isc_result_t result;
160262706Serwin	dns_db_t *db = NULL;
161262706Serwin	dns_rdataclass_t rdclass;
162262706Serwin	isc_textregion_t r;
163262706Serwin
164262706Serwin	if (zfile == NULL)
165262706Serwin		return (ISC_R_FAILURE);
166262706Serwin
167262706Serwin	DE_CONST(zclass, r.base);
168262706Serwin	r.length = strlen(zclass);
169262706Serwin	result = dns_rdataclass_fromtext(&rdclass, &r);
170262706Serwin	if (result != ISC_R_SUCCESS)
171262706Serwin		return (result);
172262706Serwin
173262706Serwin	result = dns_rootns_create(mctx, rdclass, zfile, &db);
174262706Serwin	if (result != ISC_R_SUCCESS)
175262706Serwin		return (result);
176262706Serwin
177262706Serwin	dns_db_detach(&db);
178262706Serwin	return (ISC_R_SUCCESS);
179262706Serwin}
180262706Serwin
181170222Sdougb/*% configure the zone */
182170222Sdougbstatic isc_result_t
183165071Sdougbconfigure_zone(const char *vclass, const char *view,
184170222Sdougb	       const cfg_obj_t *zconfig, const cfg_obj_t *vconfig,
185170222Sdougb	       const cfg_obj_t *config, isc_mem_t *mctx)
186135446Strhodes{
187170222Sdougb	int i = 0;
188135446Strhodes	isc_result_t result;
189135446Strhodes	const char *zclass;
190135446Strhodes	const char *zname;
191262706Serwin	const char *zfile = NULL;
192170222Sdougb	const cfg_obj_t *maps[4];
193165071Sdougb	const cfg_obj_t *zoptions = NULL;
194165071Sdougb	const cfg_obj_t *classobj = NULL;
195165071Sdougb	const cfg_obj_t *typeobj = NULL;
196165071Sdougb	const cfg_obj_t *fileobj = NULL;
197165071Sdougb	const cfg_obj_t *dbobj = NULL;
198170222Sdougb	const cfg_obj_t *obj = NULL;
199170222Sdougb	const cfg_obj_t *fmtobj = NULL;
200170222Sdougb	dns_masterformat_t masterformat;
201135446Strhodes
202170222Sdougb	zone_options = DNS_ZONEOPT_CHECKNS | DNS_ZONEOPT_MANYERRORS;
203170222Sdougb
204135446Strhodes	zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
205135446Strhodes	classobj = cfg_tuple_get(zconfig, "class");
206193149Sdougb	if (!cfg_obj_isstring(classobj))
207193149Sdougb		zclass = vclass;
208193149Sdougb	else
209135446Strhodes		zclass = cfg_obj_asstring(classobj);
210170222Sdougb
211135446Strhodes	zoptions = cfg_tuple_get(zconfig, "options");
212170222Sdougb	maps[i++] = zoptions;
213170222Sdougb	if (vconfig != NULL)
214170222Sdougb		maps[i++] = cfg_tuple_get(vconfig, "options");
215170222Sdougb	if (config != NULL) {
216170222Sdougb		cfg_map_get(config, "options", &obj);
217170222Sdougb		if (obj != NULL)
218170222Sdougb			maps[i++] = obj;
219170222Sdougb	}
220225361Sdougb	maps[i] = NULL;
221170222Sdougb
222135446Strhodes	cfg_map_get(zoptions, "type", &typeobj);
223135446Strhodes	if (typeobj == NULL)
224135446Strhodes		return (ISC_R_FAILURE);
225262706Serwin
226262706Serwin	cfg_map_get(zoptions, "file", &fileobj);
227262706Serwin	if (fileobj != NULL)
228262706Serwin		zfile = cfg_obj_asstring(fileobj);
229262706Serwin
230262706Serwin	/*
231262706Serwin	 * Check hints files for hint zones.
232262706Serwin	 * Skip loading checks for any type other than
233262706Serwin	 * master and redirect
234262706Serwin	 */
235262706Serwin	if (strcasecmp(cfg_obj_asstring(typeobj), "hint") == 0)
236262706Serwin		return (configure_hint(zfile, zclass, mctx));
237262706Serwin	else if ((strcasecmp(cfg_obj_asstring(typeobj), "master") != 0) &&
238262706Serwin		  (strcasecmp(cfg_obj_asstring(typeobj), "redirect") != 0))
239135446Strhodes		return (ISC_R_SUCCESS);
240262706Serwin
241262706Serwin	if (zfile == NULL)
242262706Serwin		return (ISC_R_FAILURE);
243262706Serwin
244193149Sdougb	cfg_map_get(zoptions, "database", &dbobj);
245193149Sdougb	if (dbobj != NULL)
246193149Sdougb		return (ISC_R_SUCCESS);
247170222Sdougb
248170222Sdougb	obj = NULL;
249224092Sdougb	if (get_maps(maps, "check-dup-records", &obj)) {
250224092Sdougb		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
251224092Sdougb			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
252224092Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
253224092Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
254224092Sdougb			zone_options |= DNS_ZONEOPT_CHECKDUPRR;
255224092Sdougb			zone_options |= DNS_ZONEOPT_CHECKDUPRRFAIL;
256224092Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
257224092Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKDUPRR;
258224092Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
259224092Sdougb		} else
260224092Sdougb			INSIST(0);
261224092Sdougb	} else {
262224092Sdougb		zone_options |= DNS_ZONEOPT_CHECKDUPRR;
263224092Sdougb		zone_options &= ~DNS_ZONEOPT_CHECKDUPRRFAIL;
264224092Sdougb	}
265224092Sdougb
266224092Sdougb	obj = NULL;
267170222Sdougb	if (get_maps(maps, "check-mx", &obj)) {
268170222Sdougb		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
269170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKMX;
270170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
271170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
272170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKMX;
273170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKMXFAIL;
274170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
275170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKMX;
276170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
277170222Sdougb		} else
278170222Sdougb			INSIST(0);
279170222Sdougb	} else {
280170222Sdougb		zone_options |= DNS_ZONEOPT_CHECKMX;
281170222Sdougb		zone_options &= ~DNS_ZONEOPT_CHECKMXFAIL;
282170222Sdougb	}
283170222Sdougb
284170222Sdougb	obj = NULL;
285170222Sdougb	if (get_maps(maps, "check-integrity", &obj)) {
286170222Sdougb		if (cfg_obj_asboolean(obj))
287170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
288170222Sdougb		else
289170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKINTEGRITY;
290186462Sdougb	} else
291186462Sdougb		zone_options |= DNS_ZONEOPT_CHECKINTEGRITY;
292170222Sdougb
293170222Sdougb	obj = NULL;
294170222Sdougb	if (get_maps(maps, "check-mx-cname", &obj)) {
295170222Sdougb		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
296170222Sdougb			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
297170222Sdougb			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
298170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
299170222Sdougb			zone_options &= ~DNS_ZONEOPT_WARNMXCNAME;
300170222Sdougb			zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
301170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
302170222Sdougb			zone_options |= DNS_ZONEOPT_WARNMXCNAME;
303170222Sdougb			zone_options |= DNS_ZONEOPT_IGNOREMXCNAME;
304170222Sdougb		} else
305170222Sdougb			INSIST(0);
306170222Sdougb	} else {
307170222Sdougb		zone_options |= DNS_ZONEOPT_WARNMXCNAME;
308170222Sdougb		zone_options &= ~DNS_ZONEOPT_IGNOREMXCNAME;
309170222Sdougb	}
310170222Sdougb
311170222Sdougb	obj = NULL;
312170222Sdougb	if (get_maps(maps, "check-srv-cname", &obj)) {
313170222Sdougb		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
314170222Sdougb			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
315170222Sdougb			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
316170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
317170222Sdougb			zone_options &= ~DNS_ZONEOPT_WARNSRVCNAME;
318170222Sdougb			zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
319170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
320170222Sdougb			zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
321170222Sdougb			zone_options |= DNS_ZONEOPT_IGNORESRVCNAME;
322170222Sdougb		} else
323170222Sdougb			INSIST(0);
324170222Sdougb	} else {
325170222Sdougb		zone_options |= DNS_ZONEOPT_WARNSRVCNAME;
326170222Sdougb		zone_options &= ~DNS_ZONEOPT_IGNORESRVCNAME;
327170222Sdougb	}
328170222Sdougb
329170222Sdougb	obj = NULL;
330170222Sdougb	if (get_maps(maps, "check-sibling", &obj)) {
331170222Sdougb		if (cfg_obj_asboolean(obj))
332170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKSIBLING;
333170222Sdougb		else
334170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKSIBLING;
335170222Sdougb	}
336170222Sdougb
337170222Sdougb	obj = NULL;
338254402Serwin	if (get_maps(maps, "check-spf", &obj)) {
339254402Serwin		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
340254402Serwin			zone_options |= DNS_ZONEOPT_CHECKSPF;
341254402Serwin		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
342254402Serwin			zone_options &= ~DNS_ZONEOPT_CHECKSPF;
343254402Serwin		} else
344254402Serwin			INSIST(0);
345254402Serwin	} else {
346254402Serwin		zone_options |= DNS_ZONEOPT_CHECKSPF;
347254402Serwin	}
348254402Serwin
349254402Serwin	obj = NULL;
350170222Sdougb	if (get_checknames(maps, &obj)) {
351170222Sdougb		if (strcasecmp(cfg_obj_asstring(obj), "warn") == 0) {
352170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKNAMES;
353170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
354170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "fail") == 0) {
355170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKNAMES;
356170222Sdougb			zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
357170222Sdougb		} else if (strcasecmp(cfg_obj_asstring(obj), "ignore") == 0) {
358170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKNAMES;
359170222Sdougb			zone_options &= ~DNS_ZONEOPT_CHECKNAMESFAIL;
360170222Sdougb		} else
361170222Sdougb			INSIST(0);
362170222Sdougb	} else {
363193149Sdougb	       zone_options |= DNS_ZONEOPT_CHECKNAMES;
364193149Sdougb	       zone_options |= DNS_ZONEOPT_CHECKNAMESFAIL;
365170222Sdougb	}
366170222Sdougb
367170222Sdougb	masterformat = dns_masterformat_text;
368170222Sdougb	fmtobj = NULL;
369170222Sdougb	result = config_get(maps, "masterfile-format", &fmtobj);
370170222Sdougb	if (result == ISC_R_SUCCESS) {
371170222Sdougb		const char *masterformatstr = cfg_obj_asstring(fmtobj);
372170222Sdougb		if (strcasecmp(masterformatstr, "text") == 0)
373170222Sdougb			masterformat = dns_masterformat_text;
374170222Sdougb		else if (strcasecmp(masterformatstr, "raw") == 0)
375170222Sdougb			masterformat = dns_masterformat_raw;
376170222Sdougb		else
377170222Sdougb			INSIST(0);
378170222Sdougb	}
379170222Sdougb
380170222Sdougb	result = load_zone(mctx, zname, zfile, masterformat, zclass, NULL);
381135446Strhodes	if (result != ISC_R_SUCCESS)
382135446Strhodes		fprintf(stderr, "%s/%s/%s: %s\n", view, zname, zclass,
383135446Strhodes			dns_result_totext(result));
384262706Serwin	return (result);
385135446Strhodes}
386135446Strhodes
387170222Sdougb/*% configure a view */
388135446Strhodesstatic isc_result_t
389165071Sdougbconfigure_view(const char *vclass, const char *view, const cfg_obj_t *config,
390165071Sdougb	       const cfg_obj_t *vconfig, isc_mem_t *mctx)
391135446Strhodes{
392165071Sdougb	const cfg_listelt_t *element;
393165071Sdougb	const cfg_obj_t *voptions;
394165071Sdougb	const cfg_obj_t *zonelist;
395135446Strhodes	isc_result_t result = ISC_R_SUCCESS;
396135446Strhodes	isc_result_t tresult;
397135446Strhodes
398135446Strhodes	voptions = NULL;
399135446Strhodes	if (vconfig != NULL)
400135446Strhodes		voptions = cfg_tuple_get(vconfig, "options");
401135446Strhodes
402135446Strhodes	zonelist = NULL;
403135446Strhodes	if (voptions != NULL)
404135446Strhodes		(void)cfg_map_get(voptions, "zone", &zonelist);
405135446Strhodes	else
406135446Strhodes		(void)cfg_map_get(config, "zone", &zonelist);
407135446Strhodes
408135446Strhodes	for (element = cfg_list_first(zonelist);
409135446Strhodes	     element != NULL;
410135446Strhodes	     element = cfg_list_next(element))
411135446Strhodes	{
412165071Sdougb		const cfg_obj_t *zconfig = cfg_listelt_value(element);
413170222Sdougb		tresult = configure_zone(vclass, view, zconfig, vconfig,
414170222Sdougb					 config, mctx);
415135446Strhodes		if (tresult != ISC_R_SUCCESS)
416135446Strhodes			result = tresult;
417135446Strhodes	}
418135446Strhodes	return (result);
419135446Strhodes}
420135446Strhodes
421135446Strhodes
422170222Sdougb/*% load zones from the configuration */
423135446Strhodesstatic isc_result_t
424165071Sdougbload_zones_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx) {
425165071Sdougb	const cfg_listelt_t *element;
426165071Sdougb	const cfg_obj_t *classobj;
427165071Sdougb	const cfg_obj_t *views;
428165071Sdougb	const cfg_obj_t *vconfig;
429135446Strhodes	const char *vclass;
430135446Strhodes	isc_result_t result = ISC_R_SUCCESS;
431135446Strhodes	isc_result_t tresult;
432135446Strhodes
433135446Strhodes	views = NULL;
434135446Strhodes
435135446Strhodes	(void)cfg_map_get(config, "view", &views);
436135446Strhodes	for (element = cfg_list_first(views);
437135446Strhodes	     element != NULL;
438135446Strhodes	     element = cfg_list_next(element))
439135446Strhodes	{
440135446Strhodes		const char *vname;
441135446Strhodes
442135446Strhodes		vclass = "IN";
443135446Strhodes		vconfig = cfg_listelt_value(element);
444135446Strhodes		if (vconfig != NULL) {
445135446Strhodes			classobj = cfg_tuple_get(vconfig, "class");
446135446Strhodes			if (cfg_obj_isstring(classobj))
447135446Strhodes				vclass = cfg_obj_asstring(classobj);
448135446Strhodes		}
449135446Strhodes		vname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
450135446Strhodes		tresult = configure_view(vclass, vname, config, vconfig, mctx);
451135446Strhodes		if (tresult != ISC_R_SUCCESS)
452135446Strhodes			result = tresult;
453135446Strhodes	}
454135446Strhodes
455135446Strhodes	if (views == NULL) {
456135446Strhodes		tresult = configure_view("IN", "_default", config, NULL, mctx);
457135446Strhodes		if (tresult != ISC_R_SUCCESS)
458135446Strhodes			result = tresult;
459135446Strhodes	}
460135446Strhodes	return (result);
461135446Strhodes}
462135446Strhodes
463224092Sdougbstatic void
464224092Sdougboutput(void *closure, const char *text, int textlen) {
465224092Sdougb	UNUSED(closure);
466224092Sdougb	if (fwrite(text, 1, textlen, stdout) != (size_t)textlen) {
467224092Sdougb		perror("fwrite");
468224092Sdougb		exit(1);
469224092Sdougb	}
470224092Sdougb}
471224092Sdougb
472170222Sdougb/*% The main processing routine */
473135446Strhodesint
474135446Strhodesmain(int argc, char **argv) {
475135446Strhodes	int c;
476135446Strhodes	cfg_parser_t *parser = NULL;
477135446Strhodes	cfg_obj_t *config = NULL;
478135446Strhodes	const char *conffile = NULL;
479135446Strhodes	isc_mem_t *mctx = NULL;
480135446Strhodes	isc_result_t result;
481135446Strhodes	int exit_status = 0;
482143731Sdougb	isc_entropy_t *ectx = NULL;
483135446Strhodes	isc_boolean_t load_zones = ISC_FALSE;
484224092Sdougb	isc_boolean_t print = ISC_FALSE;
485262706Serwin	unsigned int flags = 0;
486193149Sdougb
487193149Sdougb	isc_commandline_errprint = ISC_FALSE;
488193149Sdougb
489262706Serwin	while ((c = isc_commandline_parse(argc, argv, "dhjt:pvxz")) != EOF) {
490135446Strhodes		switch (c) {
491135446Strhodes		case 'd':
492135446Strhodes			debug++;
493135446Strhodes			break;
494135446Strhodes
495135446Strhodes		case 'j':
496135446Strhodes			nomerge = ISC_FALSE;
497135446Strhodes			break;
498135446Strhodes
499135446Strhodes		case 't':
500135446Strhodes			result = isc_dir_chroot(isc_commandline_argument);
501135446Strhodes			if (result != ISC_R_SUCCESS) {
502135446Strhodes				fprintf(stderr, "isc_dir_chroot: %s\n",
503135446Strhodes					isc_result_totext(result));
504135446Strhodes				exit(1);
505135446Strhodes			}
506135446Strhodes			break;
507135446Strhodes
508224092Sdougb		case 'p':
509224092Sdougb			print = ISC_TRUE;
510224092Sdougb			break;
511224092Sdougb
512135446Strhodes		case 'v':
513135446Strhodes			printf(VERSION "\n");
514135446Strhodes			exit(0);
515135446Strhodes
516262706Serwin		case 'x':
517262706Serwin			flags |= CFG_PRINTER_XKEY;
518262706Serwin			break;
519262706Serwin
520135446Strhodes		case 'z':
521135446Strhodes			load_zones = ISC_TRUE;
522170222Sdougb			docheckmx = ISC_FALSE;
523170222Sdougb			docheckns = ISC_FALSE;
524170222Sdougb			dochecksrv = ISC_FALSE;
525135446Strhodes			break;
526135446Strhodes
527193149Sdougb		case '?':
528193149Sdougb			if (isc_commandline_option != '?')
529193149Sdougb				fprintf(stderr, "%s: invalid argument -%c\n",
530193149Sdougb					program, isc_commandline_option);
531254402Serwin			/* FALLTHROUGH */
532193149Sdougb		case 'h':
533193149Sdougb			usage();
534193149Sdougb
535135446Strhodes		default:
536193149Sdougb			fprintf(stderr, "%s: unhandled option -%c\n",
537193149Sdougb				program, isc_commandline_option);
538193149Sdougb			exit(1);
539135446Strhodes		}
540135446Strhodes	}
541135446Strhodes
542262706Serwin	if (((flags & CFG_PRINTER_XKEY) != 0) && !print) {
543262706Serwin		fprintf(stderr, "%s: -x cannot be used without -p\n", program);
544262706Serwin		exit(1);
545262706Serwin	}
546262706Serwin
547193149Sdougb	if (isc_commandline_index + 1 < argc)
548193149Sdougb		usage();
549135446Strhodes	if (argv[isc_commandline_index] != NULL)
550135446Strhodes		conffile = argv[isc_commandline_index];
551135446Strhodes	if (conffile == NULL || conffile[0] == '\0')
552135446Strhodes		conffile = NAMED_CONFFILE;
553135446Strhodes
554216175Sdougb#ifdef _WIN32
555216175Sdougb	InitSockets();
556216175Sdougb#endif
557216175Sdougb
558135446Strhodes	RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
559135446Strhodes
560193149Sdougb	RUNTIME_CHECK(setup_logging(mctx, stdout, &logc) == ISC_R_SUCCESS);
561135446Strhodes
562143731Sdougb	RUNTIME_CHECK(isc_entropy_create(mctx, &ectx) == ISC_R_SUCCESS);
563143731Sdougb	RUNTIME_CHECK(isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE)
564143731Sdougb		      == ISC_R_SUCCESS);
565143731Sdougb
566135446Strhodes	dns_result_register();
567135446Strhodes
568135446Strhodes	RUNTIME_CHECK(cfg_parser_create(mctx, logc, &parser) == ISC_R_SUCCESS);
569135446Strhodes
570135446Strhodes	cfg_parser_setcallback(parser, directory_callback, NULL);
571135446Strhodes
572135446Strhodes	if (cfg_parse_file(parser, conffile, &cfg_type_namedconf, &config) !=
573135446Strhodes	    ISC_R_SUCCESS)
574135446Strhodes		exit(1);
575135446Strhodes
576135446Strhodes	result = bind9_check_namedconf(config, logc, mctx);
577135446Strhodes	if (result != ISC_R_SUCCESS)
578135446Strhodes		exit_status = 1;
579135446Strhodes
580135446Strhodes	if (result == ISC_R_SUCCESS && load_zones) {
581135446Strhodes		result = load_zones_fromconfig(config, mctx);
582135446Strhodes		if (result != ISC_R_SUCCESS)
583135446Strhodes			exit_status = 1;
584135446Strhodes	}
585135446Strhodes
586224092Sdougb	if (print && exit_status == 0)
587262706Serwin		cfg_printx(config, flags, output, NULL);
588135446Strhodes	cfg_obj_destroy(parser, &config);
589135446Strhodes
590135446Strhodes	cfg_parser_destroy(&parser);
591135446Strhodes
592170222Sdougb	dns_name_destroy();
593170222Sdougb
594135446Strhodes	isc_log_destroy(&logc);
595135446Strhodes
596143731Sdougb	isc_hash_destroy();
597143731Sdougb	isc_entropy_detach(&ectx);
598143731Sdougb
599135446Strhodes	isc_mem_destroy(&mctx);
600135446Strhodes
601216175Sdougb#ifdef _WIN32
602216175Sdougb	DestroySockets();
603216175Sdougb#endif
604216175Sdougb
605135446Strhodes	return (exit_status);
606135446Strhodes}
607