1/*
2 * Copyright (C) 2004-2011  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  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: main.c,v 1.180.14.4 2011/11/05 00:45:52 each Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <ctype.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include <isc/app.h>
29#include <isc/backtrace.h>
30#include <isc/commandline.h>
31#include <isc/dir.h>
32#include <isc/entropy.h>
33#include <isc/file.h>
34#include <isc/hash.h>
35#include <isc/os.h>
36#include <isc/platform.h>
37#include <isc/print.h>
38#include <isc/resource.h>
39#include <isc/stdio.h>
40#include <isc/string.h>
41#include <isc/task.h>
42#include <isc/timer.h>
43#include <isc/util.h>
44
45#include <isccc/result.h>
46
47#include <dns/dispatch.h>
48#include <dns/name.h>
49#include <dns/result.h>
50#include <dns/view.h>
51
52#include <dst/result.h>
53
54#include <dlz/dlz_dlopen_driver.h>
55
56/*
57 * Defining NS_MAIN provides storage declarations (rather than extern)
58 * for variables in named/globals.h.
59 */
60#define NS_MAIN 1
61
62#include <named/builtin.h>
63#include <named/control.h>
64#include <named/globals.h>	/* Explicit, though named/log.h includes it. */
65#include <named/interfacemgr.h>
66#include <named/log.h>
67#include <named/os.h>
68#include <named/server.h>
69#include <named/lwresd.h>
70#include <named/main.h>
71#ifdef HAVE_LIBSCF
72#include <named/ns_smf_globals.h>
73#endif
74
75#include <notify.h>
76#include <notify_keys.h>
77
78#ifdef OPENSSL
79#include <openssl/opensslv.h>
80#endif
81#ifdef HAVE_LIBXML2
82#include <libxml/xmlversion.h>
83#endif
84/*
85 * Include header files for database drivers here.
86 */
87/* #include "xxdb.h" */
88
89#ifdef CONTRIB_DLZ
90/*
91 * Include contributed DLZ drivers if appropriate.
92 */
93#include <dlz/dlz_drivers.h>
94#endif
95
96/*
97 * The maximum number of stack frames to dump on assertion failure.
98 */
99#ifndef BACKTRACE_MAXFRAME
100#define BACKTRACE_MAXFRAME 128
101#endif
102
103static isc_boolean_t	want_stats = ISC_FALSE;
104static char		program_name[ISC_DIR_NAMEMAX] = "named";
105static char		absolute_conffile[ISC_DIR_PATHMAX];
106static char		saved_command_line[512];
107static char		version[512];
108static unsigned int	maxsocks = 0;
109static int		maxudp = 0;
110
111void
112ns_main_earlywarning(const char *format, ...) {
113	va_list args;
114
115	va_start(args, format);
116	if (ns_g_lctx != NULL) {
117		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
118			       NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
119			       format, args);
120	} else {
121		fprintf(stderr, "%s: ", program_name);
122		vfprintf(stderr, format, args);
123		fprintf(stderr, "\n");
124		fflush(stderr);
125	}
126	va_end(args);
127}
128
129void
130ns_main_earlyfatal(const char *format, ...) {
131	va_list args;
132
133	va_start(args, format);
134	if (ns_g_lctx != NULL) {
135		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
136			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
137			       format, args);
138		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
139			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
140			       "exiting (due to early fatal error)");
141	} else {
142		fprintf(stderr, "%s: ", program_name);
143		vfprintf(stderr, format, args);
144		fprintf(stderr, "\n");
145		fflush(stderr);
146	}
147	va_end(args);
148
149	exit(1);
150}
151
152ISC_PLATFORM_NORETURN_PRE static void
153assertion_failed(const char *file, int line, isc_assertiontype_t type,
154		 const char *cond) ISC_PLATFORM_NORETURN_POST;
155
156static void
157assertion_failed(const char *file, int line, isc_assertiontype_t type,
158		 const char *cond)
159{
160	void *tracebuf[BACKTRACE_MAXFRAME];
161	int i, nframes;
162	isc_result_t result;
163	const char *logsuffix = "";
164	const char *fname;
165
166	/*
167	 * Handle assertion failures.
168	 */
169
170	if (ns_g_lctx != NULL) {
171		/*
172		 * Reset the assertion callback in case it is the log
173		 * routines causing the assertion.
174		 */
175		isc_assertion_setcallback(NULL);
176
177		result = isc_backtrace_gettrace(tracebuf, BACKTRACE_MAXFRAME,
178						&nframes);
179		if (result == ISC_R_SUCCESS && nframes > 0)
180			logsuffix = ", back trace";
181		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
182			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
183			      "%s:%d: %s(%s) failed%s", file, line,
184			      isc_assertion_typetotext(type), cond, logsuffix);
185		if (result == ISC_R_SUCCESS) {
186			for (i = 0; i < nframes; i++) {
187				unsigned long offset;
188
189				fname = NULL;
190				result = isc_backtrace_getsymbol(tracebuf[i],
191								 &fname,
192								 &offset);
193				if (result == ISC_R_SUCCESS) {
194					isc_log_write(ns_g_lctx,
195						      NS_LOGCATEGORY_GENERAL,
196						      NS_LOGMODULE_MAIN,
197						      ISC_LOG_CRITICAL,
198						      "#%d %p in %s()+0x%lx", i,
199						      tracebuf[i], fname,
200						      offset);
201				} else {
202					isc_log_write(ns_g_lctx,
203						      NS_LOGCATEGORY_GENERAL,
204						      NS_LOGMODULE_MAIN,
205						      ISC_LOG_CRITICAL,
206						      "#%d %p in ??", i,
207						      tracebuf[i]);
208				}
209			}
210		}
211		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
212			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
213			      "exiting (due to assertion failure)");
214	} else {
215		fprintf(stderr, "%s:%d: %s(%s) failed\n",
216			file, line, isc_assertion_typetotext(type), cond);
217		fflush(stderr);
218	}
219
220	if (ns_g_coreok)
221		abort();
222	exit(1);
223}
224
225ISC_PLATFORM_NORETURN_PRE static void
226library_fatal_error(const char *file, int line, const char *format,
227		    va_list args)
228ISC_FORMAT_PRINTF(3, 0) ISC_PLATFORM_NORETURN_POST;
229
230static void
231library_fatal_error(const char *file, int line, const char *format,
232		    va_list args)
233{
234	/*
235	 * Handle isc_error_fatal() calls from our libraries.
236	 */
237
238	if (ns_g_lctx != NULL) {
239		/*
240		 * Reset the error callback in case it is the log
241		 * routines causing the assertion.
242		 */
243		isc_error_setfatal(NULL);
244
245		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
246			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
247			      "%s:%d: fatal error:", file, line);
248		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
249			       NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
250			       format, args);
251		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
252			      NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
253			      "exiting (due to fatal error in library)");
254	} else {
255		fprintf(stderr, "%s:%d: fatal error: ", file, line);
256		vfprintf(stderr, format, args);
257		fprintf(stderr, "\n");
258		fflush(stderr);
259	}
260
261	if (ns_g_coreok)
262		abort();
263	exit(1);
264}
265
266static void
267library_unexpected_error(const char *file, int line, const char *format,
268			 va_list args) ISC_FORMAT_PRINTF(3, 0);
269
270static void
271library_unexpected_error(const char *file, int line, const char *format,
272			 va_list args)
273{
274	/*
275	 * Handle isc_error_unexpected() calls from our libraries.
276	 */
277
278	if (ns_g_lctx != NULL) {
279		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
280			      NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
281			      "%s:%d: unexpected error:", file, line);
282		isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
283			       NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
284			       format, args);
285	} else {
286		fprintf(stderr, "%s:%d: fatal error: ", file, line);
287		vfprintf(stderr, format, args);
288		fprintf(stderr, "\n");
289		fflush(stderr);
290	}
291}
292
293static void
294lwresd_usage(void) {
295	fprintf(stderr,
296		"usage: lwresd [-4|-6] [-c conffile | -C resolvconffile] "
297		"[-d debuglevel]\n"
298		"              [-f|-g] [-n number_of_cpus] [-p port] "
299		"[-P listen-port] [-s]\n"
300		"              [-t chrootdir] [-u username] [-i pidfile]\n"
301		"              [-m {usage|trace|record|size|mctx}]\n");
302}
303
304static void
305usage(void) {
306	if (ns_g_lwresdonly) {
307		lwresd_usage();
308		return;
309	}
310	fprintf(stderr,
311		"usage: named [-4|-6] [-c conffile] [-d debuglevel] "
312		"[-E engine] [-f|-g]\n"
313		"             [-n number_of_cpus] [-p port] [-s] "
314		"[-t chrootdir] [-u username]\n"
315		"             [-m {usage|trace|record|size|mctx}]\n");
316}
317
318static void
319save_command_line(int argc, char *argv[]) {
320	int i;
321	char *src;
322	char *dst;
323	char *eob;
324	const char truncated[] = "...";
325	isc_boolean_t quoted = ISC_FALSE;
326
327	dst = saved_command_line;
328	eob = saved_command_line + sizeof(saved_command_line);
329
330	for (i = 1; i < argc && dst < eob; i++) {
331		*dst++ = ' ';
332
333		src = argv[i];
334		while (*src != '\0' && dst < eob) {
335			/*
336			 * This won't perfectly produce a shell-independent
337			 * pastable command line in all circumstances, but
338			 * comes close, and for practical purposes will
339			 * nearly always be fine.
340			 */
341			if (quoted || isalnum(*src & 0xff) ||
342			    *src == '-' || *src == '_' ||
343			    *src == '.' || *src == '/') {
344				*dst++ = *src++;
345				quoted = ISC_FALSE;
346			} else {
347				*dst++ = '\\';
348				quoted = ISC_TRUE;
349			}
350		}
351	}
352
353	INSIST(sizeof(saved_command_line) >= sizeof(truncated));
354
355	if (dst == eob)
356		strcpy(eob - sizeof(truncated), truncated);
357	else
358		*dst = '\0';
359}
360
361static int
362parse_int(char *arg, const char *desc) {
363	char *endp;
364	int tmp;
365	long int ltmp;
366
367	ltmp = strtol(arg, &endp, 10);
368	tmp = (int) ltmp;
369	if (*endp != '\0')
370		ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
371	if (tmp < 0 || tmp != ltmp)
372		ns_main_earlyfatal("%s '%s' out of range", desc, arg);
373	return (tmp);
374}
375
376static struct flag_def {
377	const char *name;
378	unsigned int value;
379} mem_debug_flags[] = {
380	{ "trace",  ISC_MEM_DEBUGTRACE },
381	{ "record", ISC_MEM_DEBUGRECORD },
382	{ "usage", ISC_MEM_DEBUGUSAGE },
383	{ "size", ISC_MEM_DEBUGSIZE },
384	{ "mctx", ISC_MEM_DEBUGCTX },
385	{ NULL, 0 }
386};
387
388static void
389set_flags(const char *arg, struct flag_def *defs, unsigned int *ret) {
390	for (;;) {
391		const struct flag_def *def;
392		const char *end = strchr(arg, ',');
393		int arglen;
394		if (end == NULL)
395			end = arg + strlen(arg);
396		arglen = end - arg;
397		for (def = defs; def->name != NULL; def++) {
398			if (arglen == (int)strlen(def->name) &&
399			    memcmp(arg, def->name, arglen) == 0) {
400				*ret |= def->value;
401				goto found;
402			}
403		}
404		ns_main_earlyfatal("unrecognized flag '%.*s'", arglen, arg);
405	 found:
406		if (*end == '\0')
407			break;
408		arg = end + 1;
409	}
410}
411
412static void
413parse_command_line(int argc, char *argv[]) {
414	int ch;
415	int port;
416	isc_boolean_t disable6 = ISC_FALSE;
417	isc_boolean_t disable4 = ISC_FALSE;
418
419	save_command_line(argc, argv);
420
421	isc_commandline_errprint = ISC_FALSE;
422	while ((ch = isc_commandline_parse(argc, argv,
423					   "46c:C:d:E:fFgi:lm:n:N:p:P:"
424					   "sS:t:T:u:vVx:")) != -1) {
425		switch (ch) {
426		case '4':
427			if (disable4)
428				ns_main_earlyfatal("cannot specify -4 and -6");
429			if (isc_net_probeipv4() != ISC_R_SUCCESS)
430				ns_main_earlyfatal("IPv4 not supported by OS");
431			isc_net_disableipv6();
432			disable6 = ISC_TRUE;
433			break;
434		case '6':
435			if (disable6)
436				ns_main_earlyfatal("cannot specify -4 and -6");
437			if (isc_net_probeipv6() != ISC_R_SUCCESS)
438				ns_main_earlyfatal("IPv6 not supported by OS");
439			isc_net_disableipv4();
440			disable4 = ISC_TRUE;
441			break;
442		case 'c':
443			ns_g_conffile = isc_commandline_argument;
444			lwresd_g_conffile = isc_commandline_argument;
445			if (lwresd_g_useresolvconf)
446				ns_main_earlyfatal("cannot specify -c and -C");
447			ns_g_conffileset = ISC_TRUE;
448			break;
449		case 'C':
450			lwresd_g_resolvconffile = isc_commandline_argument;
451			if (ns_g_conffileset)
452				ns_main_earlyfatal("cannot specify -c and -C");
453			lwresd_g_useresolvconf = ISC_TRUE;
454			break;
455		case 'd':
456			ns_g_debuglevel = parse_int(isc_commandline_argument,
457						    "debug level");
458			break;
459		case 'E':
460			ns_g_engine = isc_commandline_argument;
461			break;
462		case 'f':
463			ns_g_foreground = ISC_TRUE;
464			break;
465		case 'g':
466			ns_g_foreground = ISC_TRUE;
467			ns_g_logstderr = ISC_TRUE;
468			break;
469		/* XXXBEW -i should be removed */
470		case 'i':
471			lwresd_g_defaultpidfile = isc_commandline_argument;
472			break;
473		case 'l':
474			ns_g_lwresdonly = ISC_TRUE;
475			break;
476		case 'm':
477			set_flags(isc_commandline_argument, mem_debug_flags,
478				  &isc_mem_debugging);
479			break;
480		case 'N': /* Deprecated. */
481		case 'n':
482			ns_g_cpus = parse_int(isc_commandline_argument,
483					      "number of cpus");
484			if (ns_g_cpus == 0)
485				ns_g_cpus = 1;
486			break;
487		case 'p':
488			port = parse_int(isc_commandline_argument, "port");
489			if (port < 1 || port > 65535)
490				ns_main_earlyfatal("port '%s' out of range",
491						   isc_commandline_argument);
492			ns_g_port = port;
493			break;
494		/* XXXBEW Should -P be removed? */
495		case 'P':
496			port = parse_int(isc_commandline_argument, "port");
497			if (port < 1 || port > 65535)
498				ns_main_earlyfatal("port '%s' out of range",
499						   isc_commandline_argument);
500			lwresd_g_listenport = port;
501			break;
502		case 's':
503			/* XXXRTH temporary syntax */
504			want_stats = ISC_TRUE;
505			break;
506		case 'S':
507			maxsocks = parse_int(isc_commandline_argument,
508					     "max number of sockets");
509			break;
510		case 't':
511			/* XXXJAB should we make a copy? */
512			ns_g_chrootdir = isc_commandline_argument;
513			break;
514		case 'T':	/* NOT DOCUMENTED */
515			/*
516			 * clienttest: make clients single shot with their
517			 * 	       own memory context.
518			 */
519			if (!strcmp(isc_commandline_argument, "clienttest"))
520				ns_g_clienttest = ISC_TRUE;
521			else if (!strcmp(isc_commandline_argument, "nosoa"))
522				ns_g_nosoa = ISC_TRUE;
523			else if (!strcmp(isc_commandline_argument, "noaa"))
524				ns_g_noaa = ISC_TRUE;
525			else if (!strcmp(isc_commandline_argument, "maxudp512"))
526				maxudp = 512;
527			else if (!strcmp(isc_commandline_argument, "maxudp1460"))
528				maxudp = 1460;
529			else
530				fprintf(stderr, "unknown -T flag '%s\n",
531					isc_commandline_argument);
532			break;
533		case 'u':
534			ns_g_username = isc_commandline_argument;
535			break;
536		case 'v':
537			printf("BIND %s\n", ns_g_version);
538			exit(0);
539		case 'V':
540			printf("BIND %s built with %s\n", ns_g_version,
541				ns_g_configargs);
542#ifdef OPENSSL
543			printf("using OpenSSL version: %s\n",
544			       OPENSSL_VERSION_TEXT);
545#endif
546#ifdef HAVE_LIBXML2
547			printf("using libxml2 version: %s\n",
548			       LIBXML_DOTTED_VERSION);
549#endif
550			exit(0);
551		case 'F':
552			/* Reserved for FIPS mode */
553			/* FALLTHROUGH */
554		case '?':
555			usage();
556			if (isc_commandline_option == '?')
557				exit(0);
558			ns_main_earlyfatal("unknown option '-%c'",
559					   isc_commandline_option);
560			/* FALLTHROUGH */
561		default:
562			ns_main_earlyfatal("parsing options returned %d", ch);
563		}
564	}
565
566	argc -= isc_commandline_index;
567	argv += isc_commandline_index;
568	POST(argv);
569
570	if (argc > 0) {
571		usage();
572		ns_main_earlyfatal("extra command line arguments");
573	}
574}
575
576static isc_result_t
577create_managers(void) {
578	isc_result_t result;
579	unsigned int socks;
580
581#ifdef ISC_PLATFORM_USETHREADS
582	if (ns_g_cpus == 0)
583		ns_g_cpus = ns_g_cpus_detected;
584	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
585		      ISC_LOG_INFO, "found %u CPU%s, using %u worker thread%s",
586		      ns_g_cpus_detected, ns_g_cpus_detected == 1 ? "" : "s",
587		      ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
588#else
589	ns_g_cpus = 1;
590#endif
591	result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
592	if (result != ISC_R_SUCCESS) {
593		UNEXPECTED_ERROR(__FILE__, __LINE__,
594				 "isc_taskmgr_create() failed: %s",
595				 isc_result_totext(result));
596		return (ISC_R_UNEXPECTED);
597	}
598
599	result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
600	if (result != ISC_R_SUCCESS) {
601		UNEXPECTED_ERROR(__FILE__, __LINE__,
602				 "isc_timermgr_create() failed: %s",
603				 isc_result_totext(result));
604		return (ISC_R_UNEXPECTED);
605	}
606
607	result = isc_socketmgr_create2(ns_g_mctx, &ns_g_socketmgr, maxsocks);
608	if (result != ISC_R_SUCCESS) {
609		UNEXPECTED_ERROR(__FILE__, __LINE__,
610				 "isc_socketmgr_create() failed: %s",
611				 isc_result_totext(result));
612		return (ISC_R_UNEXPECTED);
613	}
614	isc__socketmgr_maxudp(ns_g_socketmgr, maxudp);
615	result = isc_socketmgr_getmaxsockets(ns_g_socketmgr, &socks);
616	if (result == ISC_R_SUCCESS) {
617		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
618			      NS_LOGMODULE_SERVER,
619			      ISC_LOG_INFO, "using up to %u sockets", socks);
620	}
621
622	result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
623	if (result != ISC_R_SUCCESS) {
624		UNEXPECTED_ERROR(__FILE__, __LINE__,
625				 "isc_entropy_create() failed: %s",
626				 isc_result_totext(result));
627		return (ISC_R_UNEXPECTED);
628	}
629
630	result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
631	if (result != ISC_R_SUCCESS) {
632		UNEXPECTED_ERROR(__FILE__, __LINE__,
633				 "isc_hash_create() failed: %s",
634				 isc_result_totext(result));
635		return (ISC_R_UNEXPECTED);
636	}
637
638	return (ISC_R_SUCCESS);
639}
640
641static void
642destroy_managers(void) {
643	ns_lwresd_shutdown();
644
645	isc_entropy_detach(&ns_g_entropy);
646	if (ns_g_fallbackentropy != NULL)
647		isc_entropy_detach(&ns_g_fallbackentropy);
648
649	/*
650	 * isc_taskmgr_destroy() will block until all tasks have exited,
651	 */
652	isc_taskmgr_destroy(&ns_g_taskmgr);
653	isc_timermgr_destroy(&ns_g_timermgr);
654	isc_socketmgr_destroy(&ns_g_socketmgr);
655
656	/*
657	 * isc_hash_destroy() cannot be called as long as a resolver may be
658	 * running.  Calling this after isc_taskmgr_destroy() ensures the
659	 * call is safe.
660	 */
661	isc_hash_destroy();
662}
663
664static void
665dump_symboltable() {
666	int i;
667	isc_result_t result;
668	const char *fname;
669	const void *addr;
670
671	if (isc__backtrace_nsymbols == 0)
672		return;
673
674	if (!isc_log_wouldlog(ns_g_lctx, ISC_LOG_DEBUG(99)))
675		return;
676
677	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
678		      ISC_LOG_DEBUG(99), "Symbol table:");
679
680	for (i = 0, result = ISC_R_SUCCESS; result == ISC_R_SUCCESS; i++) {
681		addr = NULL;
682		fname = NULL;
683		result = isc_backtrace_getsymbolfromindex(i, &addr, &fname);
684		if (result == ISC_R_SUCCESS) {
685			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
686				      NS_LOGMODULE_MAIN, ISC_LOG_DEBUG(99),
687				      "[%d] %p %s", i, addr, fname);
688		}
689	}
690}
691
692static void
693setup(void) {
694	isc_result_t result;
695	isc_resourcevalue_t old_openfiles;
696#ifdef HAVE_LIBSCF
697	char *instance = NULL;
698#endif
699
700	/*
701	 * Get the user and group information before changing the root
702	 * directory, so the administrator does not need to keep a copy
703	 * of the user and group databases in the chroot'ed environment.
704	 */
705	ns_os_inituserinfo(ns_g_username);
706
707	/*
708	 * Initialize time conversion information
709	 */
710	ns_os_tzset();
711
712	ns_os_opendevnull();
713
714#ifdef HAVE_LIBSCF
715	/* Check if named is under smf control, before chroot. */
716	result = ns_smf_get_instance(&instance, 0, ns_g_mctx);
717	/* We don't care about instance, just check if we got one. */
718	if (result == ISC_R_SUCCESS)
719		ns_smf_got_instance = 1;
720	else
721		ns_smf_got_instance = 0;
722	if (instance != NULL)
723		isc_mem_free(ns_g_mctx, instance);
724#endif /* HAVE_LIBSCF */
725
726#ifdef PATH_RANDOMDEV
727	/*
728	 * Initialize system's random device as fallback entropy source
729	 * if running chroot'ed.
730	 */
731	if (ns_g_chrootdir != NULL) {
732		result = isc_entropy_create(ns_g_mctx, &ns_g_fallbackentropy);
733		if (result != ISC_R_SUCCESS)
734			ns_main_earlyfatal("isc_entropy_create() failed: %s",
735					   isc_result_totext(result));
736
737		result = isc_entropy_createfilesource(ns_g_fallbackentropy,
738						      PATH_RANDOMDEV);
739		if (result != ISC_R_SUCCESS) {
740			ns_main_earlywarning("could not open pre-chroot "
741					     "entropy source %s: %s",
742					     PATH_RANDOMDEV,
743					     isc_result_totext(result));
744			isc_entropy_detach(&ns_g_fallbackentropy);
745		}
746	}
747#endif
748
749#ifdef ISC_PLATFORM_USETHREADS
750	/*
751	 * Check for the number of cpu's before ns_os_chroot().
752	 */
753	ns_g_cpus_detected = isc_os_ncpus();
754#endif
755
756	ns_os_chroot(ns_g_chrootdir);
757
758	/*
759	 * For operating systems which have a capability mechanism, now
760	 * is the time to switch to minimal privs and change our user id.
761	 * On traditional UNIX systems, this call will be a no-op, and we
762	 * will change the user ID after reading the config file the first
763	 * time.  (We need to read the config file to know which possibly
764	 * privileged ports to bind() to.)
765	 */
766	ns_os_minprivs();
767
768	result = ns_log_init(ISC_TF(ns_g_username != NULL));
769	if (result != ISC_R_SUCCESS)
770		ns_main_earlyfatal("ns_log_init() failed: %s",
771				   isc_result_totext(result));
772
773	/*
774	 * Now is the time to daemonize (if we're not running in the
775	 * foreground).  We waited until now because we wanted to get
776	 * a valid logging context setup.  We cannot daemonize any later,
777	 * because calling create_managers() will create threads, which
778	 * would be lost after fork().
779	 */
780	if (!ns_g_foreground)
781		ns_os_daemonize();
782
783	/*
784	 * We call isc_app_start() here as some versions of FreeBSD's fork()
785	 * destroys all the signal handling it sets up.
786	 */
787	result = isc_app_start();
788	if (result != ISC_R_SUCCESS)
789		ns_main_earlyfatal("isc_app_start() failed: %s",
790				   isc_result_totext(result));
791
792	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
793		      ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
794		      saved_command_line);
795
796	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
797		      ISC_LOG_NOTICE, "built with %s", ns_g_configargs);
798
799	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
800		      ISC_LOG_NOTICE,
801		      "----------------------------------------------------");
802	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
803		      ISC_LOG_NOTICE,
804		      "BIND 9 is maintained by Internet Systems Consortium,");
805	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
806		      ISC_LOG_NOTICE,
807		      "Inc. (ISC), a non-profit 501(c)(3) public-benefit ");
808	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
809		      ISC_LOG_NOTICE,
810		      "corporation.  Support and training for BIND 9 are ");
811	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
812		      ISC_LOG_NOTICE,
813		      "available at https://www.isc.org/support");
814	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
815		      ISC_LOG_NOTICE,
816		      "----------------------------------------------------");
817
818	dump_symboltable();
819
820	/*
821	 * Get the initial resource limits.
822	 */
823	(void)isc_resource_getlimit(isc_resource_stacksize,
824				    &ns_g_initstacksize);
825	(void)isc_resource_getlimit(isc_resource_datasize,
826				    &ns_g_initdatasize);
827	(void)isc_resource_getlimit(isc_resource_coresize,
828				    &ns_g_initcoresize);
829	(void)isc_resource_getlimit(isc_resource_openfiles,
830				    &ns_g_initopenfiles);
831
832	/*
833	 * System resources cannot effectively be tuned on some systems.
834	 * Raise the limit in such cases for safety.
835	 */
836	old_openfiles = ns_g_initopenfiles;
837	ns_os_adjustnofile();
838	(void)isc_resource_getlimit(isc_resource_openfiles,
839				    &ns_g_initopenfiles);
840	if (old_openfiles != ns_g_initopenfiles) {
841		isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
842			      NS_LOGMODULE_MAIN, ISC_LOG_NOTICE,
843			      "adjusted limit on open files from "
844			      "%" ISC_PRINT_QUADFORMAT "u to "
845			      "%" ISC_PRINT_QUADFORMAT "u",
846			      old_openfiles, ns_g_initopenfiles);
847	}
848
849	/*
850	 * If the named configuration filename is relative, prepend the current
851	 * directory's name before possibly changing to another directory.
852	 */
853	if (! isc_file_isabsolute(ns_g_conffile)) {
854		result = isc_file_absolutepath(ns_g_conffile,
855					       absolute_conffile,
856					       sizeof(absolute_conffile));
857		if (result != ISC_R_SUCCESS)
858			ns_main_earlyfatal("could not construct absolute path "
859					   "of configuration file: %s",
860					   isc_result_totext(result));
861		ns_g_conffile = absolute_conffile;
862	}
863
864	/*
865	 * Record the server's startup time.
866	 */
867	result = isc_time_now(&ns_g_boottime);
868	if (result != ISC_R_SUCCESS)
869		ns_main_earlyfatal("isc_time_now() failed: %s",
870				   isc_result_totext(result));
871
872	result = create_managers();
873	if (result != ISC_R_SUCCESS)
874		ns_main_earlyfatal("create_managers() failed: %s",
875				   isc_result_totext(result));
876
877	ns_builtin_init();
878
879	/*
880	 * Add calls to register sdb drivers here.
881	 */
882	/* xxdb_init(); */
883
884#ifdef ISC_DLZ_DLOPEN
885	/*
886	 * Register the DLZ "dlopen" driver.
887	 */
888	result = dlz_dlopen_init(ns_g_mctx);
889	if (result != ISC_R_SUCCESS)
890		ns_main_earlyfatal("dlz_dlopen_init() failed: %s",
891				   isc_result_totext(result));
892#endif
893
894#if CONTRIB_DLZ
895	/*
896	 * Register any other contributed DLZ drivers.
897	 */
898	result = dlz_drivers_init();
899	if (result != ISC_R_SUCCESS)
900		ns_main_earlyfatal("dlz_drivers_init() failed: %s",
901				   isc_result_totext(result));
902#endif
903
904	ns_server_create(ns_g_mctx, &ns_g_server);
905}
906
907static void
908cleanup(void) {
909
910	destroy_managers();
911
912	ns_server_destroy(&ns_g_server);
913
914	ns_builtin_deinit();
915
916	/*
917	 * Add calls to unregister sdb drivers here.
918	 */
919	/* xxdb_clear(); */
920
921#ifdef CONTRIB_DLZ
922	/*
923	 * Unregister contributed DLZ drivers.
924	 */
925	dlz_drivers_clear();
926#endif
927#ifdef ISC_DLZ_DLOPEN
928	/*
929	 * Unregister "dlopen" DLZ driver.
930	 */
931	dlz_dlopen_clear();
932#endif
933
934	dns_name_destroy();
935
936	isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
937		      ISC_LOG_NOTICE, "exiting");
938	ns_log_shutdown();
939}
940
941static char *memstats = NULL;
942
943void
944ns_main_setmemstats(const char *filename) {
945	/*
946	 * Caller has to ensure locking.
947	 */
948
949	if (memstats != NULL) {
950		free(memstats);
951		memstats = NULL;
952	}
953	if (filename == NULL)
954		return;
955	memstats = malloc(strlen(filename) + 1);
956	if (memstats)
957		strcpy(memstats, filename);
958}
959
960#ifdef HAVE_LIBSCF
961/*
962 * Get FMRI for the named process.
963 */
964isc_result_t
965ns_smf_get_instance(char **ins_name, int debug, isc_mem_t *mctx) {
966	scf_handle_t *h = NULL;
967	int namelen;
968	char *instance;
969
970	REQUIRE(ins_name != NULL && *ins_name == NULL);
971
972	if ((h = scf_handle_create(SCF_VERSION)) == NULL) {
973		if (debug)
974			UNEXPECTED_ERROR(__FILE__, __LINE__,
975					 "scf_handle_create() failed: %s",
976					 scf_strerror(scf_error()));
977		return (ISC_R_FAILURE);
978	}
979
980	if (scf_handle_bind(h) == -1) {
981		if (debug)
982			UNEXPECTED_ERROR(__FILE__, __LINE__,
983					 "scf_handle_bind() failed: %s",
984					 scf_strerror(scf_error()));
985		scf_handle_destroy(h);
986		return (ISC_R_FAILURE);
987	}
988
989	if ((namelen = scf_myname(h, NULL, 0)) == -1) {
990		if (debug)
991			UNEXPECTED_ERROR(__FILE__, __LINE__,
992					 "scf_myname() failed: %s",
993					 scf_strerror(scf_error()));
994		scf_handle_destroy(h);
995		return (ISC_R_FAILURE);
996	}
997
998	if ((instance = isc_mem_allocate(mctx, namelen + 1)) == NULL) {
999		UNEXPECTED_ERROR(__FILE__, __LINE__,
1000				 "ns_smf_get_instance memory "
1001				 "allocation failed: %s",
1002				 isc_result_totext(ISC_R_NOMEMORY));
1003		scf_handle_destroy(h);
1004		return (ISC_R_FAILURE);
1005	}
1006
1007	if (scf_myname(h, instance, namelen + 1) == -1) {
1008		if (debug)
1009			UNEXPECTED_ERROR(__FILE__, __LINE__,
1010					 "scf_myname() failed: %s",
1011					 scf_strerror(scf_error()));
1012		scf_handle_destroy(h);
1013		isc_mem_free(mctx, instance);
1014		return (ISC_R_FAILURE);
1015	}
1016
1017	scf_handle_destroy(h);
1018	*ins_name = instance;
1019	return (ISC_R_SUCCESS);
1020}
1021#endif /* HAVE_LIBSCF */
1022
1023int
1024main(int argc, char *argv[]) {
1025	isc_result_t result;
1026#ifdef HAVE_LIBSCF
1027	char *instance = NULL;
1028#endif
1029	int nctoken;
1030
1031	/*
1032	 * Record version in core image.
1033	 * strings named.core | grep "named version:"
1034	 */
1035	strlcat(version,
1036#if defined(NO_VERSION_DATE) || !defined(__DATE__)
1037		"named version: BIND " VERSION,
1038#else
1039		"named version: BIND " VERSION " (" __DATE__ ")",
1040#endif
1041		sizeof(version));
1042	result = isc_file_progname(*argv, program_name, sizeof(program_name));
1043	if (result != ISC_R_SUCCESS)
1044		ns_main_earlyfatal("program name too long");
1045
1046	if (strcmp(program_name, "lwresd") == 0)
1047		ns_g_lwresdonly = ISC_TRUE;
1048
1049	if (result != ISC_R_SUCCESS)
1050		ns_main_earlyfatal("failed to build internal symbol table");
1051
1052	isc_assertion_setcallback(assertion_failed);
1053	isc_error_setfatal(library_fatal_error);
1054	isc_error_setunexpected(library_unexpected_error);
1055
1056	ns_os_init(program_name);
1057
1058	dns_result_register();
1059	dst_result_register();
1060	isccc_result_register();
1061
1062	parse_command_line(argc, argv);
1063
1064	/*
1065	 * Warn about common configuration error.
1066	 */
1067	if (ns_g_chrootdir != NULL) {
1068		int len = strlen(ns_g_chrootdir);
1069		if (strncmp(ns_g_chrootdir, ns_g_conffile, len) == 0 &&
1070		    (ns_g_conffile[len] == '/' || ns_g_conffile[len] == '\\'))
1071			ns_main_earlywarning("config filename (-c %s) contains "
1072					     "chroot path (-t %s)",
1073					     ns_g_conffile, ns_g_chrootdir);
1074	}
1075
1076	result = isc_mem_create(0, 0, &ns_g_mctx);
1077	if (result != ISC_R_SUCCESS)
1078		ns_main_earlyfatal("isc_mem_create() failed: %s",
1079				   isc_result_totext(result));
1080	isc_mem_setname(ns_g_mctx, "main", NULL);
1081
1082	/*
1083	 * register for a SIGHUP when there's a network configuration change
1084	 */
1085	nctoken = -1;
1086	notify_register_signal(kNotifySCNetworkChange, SIGHUP, &nctoken);
1087
1088	setup();
1089
1090	/*
1091	 * Start things running and then wait for a shutdown request
1092	 * or reload.
1093	 */
1094	do {
1095		result = isc_app_run();
1096
1097		if (result == ISC_R_RELOAD) {
1098			ns_server_reloadwanted(ns_g_server);
1099		} else if (result != ISC_R_SUCCESS) {
1100			UNEXPECTED_ERROR(__FILE__, __LINE__,
1101					 "isc_app_run(): %s",
1102					 isc_result_totext(result));
1103			/*
1104			 * Force exit.
1105			 */
1106			result = ISC_R_SUCCESS;
1107		}
1108	} while (result != ISC_R_SUCCESS);
1109
1110#ifdef HAVE_LIBSCF
1111	if (ns_smf_want_disable == 1) {
1112		result = ns_smf_get_instance(&instance, 1, ns_g_mctx);
1113		if (result == ISC_R_SUCCESS && instance != NULL) {
1114			if (smf_disable_instance(instance, 0) != 0)
1115				UNEXPECTED_ERROR(__FILE__, __LINE__,
1116						 "smf_disable_instance() "
1117						 "failed for %s : %s",
1118						 instance,
1119						 scf_strerror(scf_error()));
1120		}
1121		if (instance != NULL)
1122			isc_mem_free(ns_g_mctx, instance);
1123	}
1124#endif /* HAVE_LIBSCF */
1125
1126	cleanup();
1127
1128	if (want_stats) {
1129		isc_mem_stats(ns_g_mctx, stdout);
1130		isc_mutex_stats(stdout);
1131	}
1132
1133	if (ns_g_memstatistics && memstats != NULL) {
1134		FILE *fp = NULL;
1135		result = isc_stdio_open(memstats, "w", &fp);
1136		if (result == ISC_R_SUCCESS) {
1137			isc_mem_stats(ns_g_mctx, fp);
1138			isc_mutex_stats(fp);
1139			isc_stdio_close(fp);
1140		}
1141	}
1142	isc_mem_destroy(&ns_g_mctx);
1143	isc_mem_checkdestroyed(stderr);
1144
1145	ns_main_setmemstats(NULL);
1146
1147	isc_app_finish();
1148
1149	ns_os_closedevnull();
1150
1151	ns_os_shutdown();
1152
1153	return (0);
1154}
1155