mirror of
https://github.com/isc-projects/bind9.git
synced 2026-04-15 22:09:31 -04:00
This commit was manufactured by cvs2git to create branch 'v9_3'.
This commit is contained in:
commit
d761f65a20
5 changed files with 1493 additions and 0 deletions
629
bin/named/main.c
Normal file
629
bin/named/main.c
Normal file
|
|
@ -0,0 +1,629 @@
|
|||
/*
|
||||
* Copyright (C) 1999-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: main.c,v 1.119.2.3 2003/07/25 03:31:41 marka Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/commandline.h>
|
||||
#include <isc/dir.h>
|
||||
#include <isc/entropy.h>
|
||||
#include <isc/file.h>
|
||||
#include <isc/hash.h>
|
||||
#include <isc/os.h>
|
||||
#include <isc/platform.h>
|
||||
#include <isc/resource.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/timer.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <isccc/result.h>
|
||||
|
||||
#include <dns/dispatch.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/result.h>
|
||||
#include <dns/view.h>
|
||||
|
||||
#include <dst/result.h>
|
||||
|
||||
/*
|
||||
* Defining NS_MAIN provides storage declarations (rather than extern)
|
||||
* for variables in named/globals.h.
|
||||
*/
|
||||
#define NS_MAIN 1
|
||||
|
||||
#include <named/control.h>
|
||||
#include <named/globals.h> /* Explicit, though named/log.h includes it. */
|
||||
#include <named/interfacemgr.h>
|
||||
#include <named/log.h>
|
||||
#include <named/os.h>
|
||||
#include <named/server.h>
|
||||
#include <named/lwresd.h>
|
||||
#include <named/main.h>
|
||||
|
||||
/*
|
||||
* Include header files for database drivers here.
|
||||
*/
|
||||
/* #include "xxdb.h" */
|
||||
|
||||
static isc_boolean_t want_stats = ISC_FALSE;
|
||||
static char program_name[ISC_DIR_NAMEMAX] = "named";
|
||||
static char absolute_conffile[ISC_DIR_PATHMAX];
|
||||
static char saved_command_line[512];
|
||||
|
||||
void
|
||||
ns_main_earlywarning(const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (ns_g_lctx != NULL) {
|
||||
isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_WARNING,
|
||||
format, args);
|
||||
} else {
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
ns_main_earlyfatal(const char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
if (ns_g_lctx != NULL) {
|
||||
isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
format, args);
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
"exiting (due to early fatal error)");
|
||||
} else {
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
assertion_failed(const char *file, int line, isc_assertiontype_t type,
|
||||
const char *cond)
|
||||
{
|
||||
/*
|
||||
* Handle assertion failures.
|
||||
*/
|
||||
|
||||
if (ns_g_lctx != NULL) {
|
||||
/*
|
||||
* Reset the assetion callback in case it is the log
|
||||
* routines causing the assertion.
|
||||
*/
|
||||
isc_assertion_setcallback(NULL);
|
||||
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
"%s:%d: %s(%s) failed", file, line,
|
||||
isc_assertion_typetotext(type), cond);
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
"exiting (due to assertion failure)");
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: %s(%s) failed\n",
|
||||
file, line, isc_assertion_typetotext(type), cond);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
if (ns_g_coreok)
|
||||
abort();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
library_fatal_error(const char *file, int line, const char *format,
|
||||
va_list args) ISC_FORMAT_PRINTF(3, 0);
|
||||
|
||||
static void
|
||||
library_fatal_error(const char *file, int line, const char *format,
|
||||
va_list args)
|
||||
{
|
||||
/*
|
||||
* Handle isc_error_fatal() calls from our libraries.
|
||||
*/
|
||||
|
||||
if (ns_g_lctx != NULL) {
|
||||
/*
|
||||
* Reset the error callback in case it is the log
|
||||
* routines causing the assertion.
|
||||
*/
|
||||
isc_error_setfatal(NULL);
|
||||
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
"%s:%d: fatal error:", file, line);
|
||||
isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
format, args);
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_CRITICAL,
|
||||
"exiting (due to fatal error in library)");
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: fatal error: ", file, line);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
if (ns_g_coreok)
|
||||
abort();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
library_unexpected_error(const char *file, int line, const char *format,
|
||||
va_list args) ISC_FORMAT_PRINTF(3, 0);
|
||||
|
||||
static void
|
||||
library_unexpected_error(const char *file, int line, const char *format,
|
||||
va_list args)
|
||||
{
|
||||
/*
|
||||
* Handle isc_error_unexpected() calls from our libraries.
|
||||
*/
|
||||
|
||||
if (ns_g_lctx != NULL) {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
|
||||
"%s:%d: unexpected error:", file, line);
|
||||
isc_log_vwrite(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_MAIN, ISC_LOG_ERROR,
|
||||
format, args);
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d: fatal error: ", file, line);
|
||||
vfprintf(stderr, format, args);
|
||||
fprintf(stderr, "\n");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lwresd_usage(void) {
|
||||
fprintf(stderr,
|
||||
"usage: lwresd [-c conffile | -C resolvconffile] "
|
||||
"[-d debuglevel] [-f|-g]\n"
|
||||
" [-n number_of_cpus] [-p port]"
|
||||
"[-P listen-port] [-s]\n"
|
||||
" [-t chrootdir] [-u username] [-i pidfile]\n");
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void) {
|
||||
if (ns_g_lwresdonly) {
|
||||
lwresd_usage();
|
||||
return;
|
||||
}
|
||||
fprintf(stderr,
|
||||
"usage: named [-c conffile] [-d debuglevel] "
|
||||
"[-f|-g] [-n number_of_cpus]\n"
|
||||
" [-p port] [-s] [-t chrootdir] [-u username]\n");
|
||||
}
|
||||
|
||||
static void
|
||||
save_command_line(int argc, char *argv[]) {
|
||||
int i;
|
||||
char *src;
|
||||
char *dst;
|
||||
char *eob;
|
||||
const char truncated[] = "...";
|
||||
isc_boolean_t quoted = ISC_FALSE;
|
||||
|
||||
dst = saved_command_line;
|
||||
eob = saved_command_line + sizeof(saved_command_line);
|
||||
|
||||
for (i = 1; i < argc && dst < eob; i++) {
|
||||
*dst++ = ' ';
|
||||
|
||||
src = argv[i];
|
||||
while (*src != '\0' && dst < eob) {
|
||||
/*
|
||||
* This won't perfectly produce a shell-independent
|
||||
* pastable command line in all circumstances, but
|
||||
* comes close, and for practical purposes will
|
||||
* nearly always be fine.
|
||||
*/
|
||||
if (quoted || isalnum(*src & 0xff) ||
|
||||
*src == '-' || *src == '_' ||
|
||||
*src == '.' || *src == '/') {
|
||||
*dst++ = *src++;
|
||||
quoted = ISC_FALSE;
|
||||
} else {
|
||||
*dst++ = '\\';
|
||||
quoted = ISC_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSIST(sizeof(saved_command_line) >= sizeof(truncated));
|
||||
|
||||
if (dst == eob)
|
||||
strcpy(eob - sizeof(truncated), truncated);
|
||||
else
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
parse_int(char *arg, const char *desc) {
|
||||
char *endp;
|
||||
int tmp;
|
||||
long int ltmp;
|
||||
|
||||
ltmp = strtol(arg, &endp, 10);
|
||||
tmp = (int) ltmp;
|
||||
if (*endp != '\0')
|
||||
ns_main_earlyfatal("%s '%s' must be numeric", desc, arg);
|
||||
if (tmp < 0 || tmp != ltmp)
|
||||
ns_main_earlyfatal("%s '%s' out of range", desc, arg);
|
||||
return (tmp);
|
||||
}
|
||||
|
||||
static void
|
||||
parse_command_line(int argc, char *argv[]) {
|
||||
int ch;
|
||||
int port;
|
||||
|
||||
save_command_line(argc, argv);
|
||||
|
||||
isc_commandline_errprint = ISC_FALSE;
|
||||
while ((ch = isc_commandline_parse(argc, argv,
|
||||
"c:C:d:fgi:ln:N:p:P:st:u:vx:")) !=
|
||||
-1) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
ns_g_conffile = isc_commandline_argument;
|
||||
lwresd_g_conffile = isc_commandline_argument;
|
||||
if (lwresd_g_useresolvconf)
|
||||
ns_main_earlyfatal("cannot specify -c and -C");
|
||||
ns_g_conffileset = ISC_TRUE;
|
||||
break;
|
||||
case 'C':
|
||||
lwresd_g_resolvconffile = isc_commandline_argument;
|
||||
if (ns_g_conffileset)
|
||||
ns_main_earlyfatal("cannot specify -c and -C");
|
||||
lwresd_g_useresolvconf = ISC_TRUE;
|
||||
break;
|
||||
case 'd':
|
||||
ns_g_debuglevel = parse_int(isc_commandline_argument,
|
||||
"debug level");
|
||||
break;
|
||||
case 'f':
|
||||
ns_g_foreground = ISC_TRUE;
|
||||
break;
|
||||
case 'g':
|
||||
ns_g_foreground = ISC_TRUE;
|
||||
ns_g_logstderr = ISC_TRUE;
|
||||
break;
|
||||
/* XXXBEW -i should be removed */
|
||||
case 'i':
|
||||
lwresd_g_defaultpidfile = isc_commandline_argument;
|
||||
break;
|
||||
case 'l':
|
||||
ns_g_lwresdonly = ISC_TRUE;
|
||||
break;
|
||||
case 'N': /* Deprecated. */
|
||||
case 'n':
|
||||
ns_g_cpus = parse_int(isc_commandline_argument,
|
||||
"number of cpus");
|
||||
if (ns_g_cpus == 0)
|
||||
ns_g_cpus = 1;
|
||||
break;
|
||||
case 'p':
|
||||
port = parse_int(isc_commandline_argument, "port");
|
||||
if (port < 1 || port > 65535)
|
||||
ns_main_earlyfatal("port '%s' out of range",
|
||||
isc_commandline_argument);
|
||||
ns_g_port = port;
|
||||
break;
|
||||
/* XXXBEW Should -P be removed? */
|
||||
case 'P':
|
||||
port = parse_int(isc_commandline_argument, "port");
|
||||
if (port < 1 || port > 65535)
|
||||
ns_main_earlyfatal("port '%s' out of range",
|
||||
isc_commandline_argument);
|
||||
lwresd_g_listenport = port;
|
||||
break;
|
||||
case 's':
|
||||
/* XXXRTH temporary syntax */
|
||||
want_stats = ISC_TRUE;
|
||||
break;
|
||||
case 't':
|
||||
/* XXXJAB should we make a copy? */
|
||||
ns_g_chrootdir = isc_commandline_argument;
|
||||
break;
|
||||
case 'u':
|
||||
ns_g_username = isc_commandline_argument;
|
||||
break;
|
||||
case 'v':
|
||||
printf("BIND %s\n", ns_g_version);
|
||||
exit(0);
|
||||
case '?':
|
||||
usage();
|
||||
ns_main_earlyfatal("unknown option '-%c'",
|
||||
isc_commandline_option);
|
||||
default:
|
||||
ns_main_earlyfatal("parsing options returned %d", ch);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= isc_commandline_index;
|
||||
argv += isc_commandline_index;
|
||||
|
||||
if (argc > 0) {
|
||||
usage();
|
||||
ns_main_earlyfatal("extra command line arguments");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
create_managers(void) {
|
||||
isc_result_t result;
|
||||
|
||||
#ifdef ISC_PLATFORM_USETHREADS
|
||||
if (ns_g_cpus == 0)
|
||||
ns_g_cpus = isc_os_ncpus();
|
||||
#else
|
||||
ns_g_cpus = 1;
|
||||
#endif
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_INFO, "using %u CPU%s",
|
||||
ns_g_cpus, ns_g_cpus == 1 ? "" : "s");
|
||||
result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_taskmgr_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_timermgr_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_socketmgr_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_entropy_create(ns_g_mctx, &ns_g_entropy);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_entropy_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_hash_create(ns_g_mctx, ns_g_entropy, DNS_NAME_MAXWIRE);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_hash_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_managers(void) {
|
||||
ns_lwresd_shutdown();
|
||||
|
||||
isc_hash_destroy();
|
||||
isc_entropy_detach(&ns_g_entropy);
|
||||
/*
|
||||
* isc_taskmgr_destroy() will block until all tasks have exited,
|
||||
*/
|
||||
isc_taskmgr_destroy(&ns_g_taskmgr);
|
||||
isc_timermgr_destroy(&ns_g_timermgr);
|
||||
isc_socketmgr_destroy(&ns_g_socketmgr);
|
||||
}
|
||||
|
||||
static void
|
||||
setup(void) {
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
* Get the user and group information before changing the root
|
||||
* directory, so the administrator does not need to keep a copy
|
||||
* of the user and group databases in the chroot'ed environment.
|
||||
*/
|
||||
ns_os_inituserinfo(ns_g_username);
|
||||
|
||||
ns_os_chroot(ns_g_chrootdir);
|
||||
|
||||
/*
|
||||
* For operating systems which have a capability mechanism, now
|
||||
* is the time to switch to minimal privs and change our user id.
|
||||
* On traditional UNIX systems, this call will be a no-op, and we
|
||||
* will change the user ID after reading the config file the first
|
||||
* time. (We need to read the config file to know which possibly
|
||||
* privileged ports to bind() to.)
|
||||
*/
|
||||
ns_os_minprivs();
|
||||
|
||||
result = ns_log_init(ISC_TF(ns_g_username != NULL));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("ns_log_init() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
/*
|
||||
* Now is the time to daemonize (if we're not running in the
|
||||
* foreground). We waited until now because we wanted to get
|
||||
* a valid logging context setup. We cannot daemonize any later,
|
||||
* because calling create_managers() will create threads, which
|
||||
* would be lost after fork().
|
||||
*/
|
||||
if (!ns_g_foreground)
|
||||
ns_os_daemonize();
|
||||
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
|
||||
ISC_LOG_NOTICE, "starting BIND %s%s", ns_g_version,
|
||||
saved_command_line);
|
||||
|
||||
/*
|
||||
* Get the initial resource limits.
|
||||
*/
|
||||
(void)isc_resource_getlimit(isc_resource_stacksize,
|
||||
&ns_g_initstacksize);
|
||||
(void)isc_resource_getlimit(isc_resource_datasize,
|
||||
&ns_g_initdatasize);
|
||||
(void)isc_resource_getlimit(isc_resource_coresize,
|
||||
&ns_g_initcoresize);
|
||||
(void)isc_resource_getlimit(isc_resource_openfiles,
|
||||
&ns_g_initopenfiles);
|
||||
|
||||
/*
|
||||
* If the named configuration filename is relative, prepend the current
|
||||
* directory's name before possibly changing to another directory.
|
||||
*/
|
||||
if (! isc_file_isabsolute(ns_g_conffile)) {
|
||||
result = isc_file_absolutepath(ns_g_conffile,
|
||||
absolute_conffile,
|
||||
sizeof(absolute_conffile));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("could not construct absolute path of "
|
||||
"configuration file: %s",
|
||||
isc_result_totext(result));
|
||||
ns_g_conffile = absolute_conffile;
|
||||
}
|
||||
|
||||
result = create_managers();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("create_managers() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
/*
|
||||
* Add calls to register sdb drivers here.
|
||||
*/
|
||||
/* xxdb_init(); */
|
||||
|
||||
ns_server_create(ns_g_mctx, &ns_g_server);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup(void) {
|
||||
destroy_managers();
|
||||
|
||||
ns_server_destroy(&ns_g_server);
|
||||
|
||||
/*
|
||||
* Add calls to unregister sdb drivers here.
|
||||
*/
|
||||
/* xxdb_clear(); */
|
||||
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN,
|
||||
ISC_LOG_NOTICE, "exiting");
|
||||
ns_log_shutdown();
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
isc_result_t result;
|
||||
|
||||
result = isc_file_progname(*argv, program_name, sizeof(program_name));
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("program name too long");
|
||||
|
||||
if (strcmp(program_name, "lwresd") == 0)
|
||||
ns_g_lwresdonly = ISC_TRUE;
|
||||
|
||||
isc_assertion_setcallback(assertion_failed);
|
||||
isc_error_setfatal(library_fatal_error);
|
||||
isc_error_setunexpected(library_unexpected_error);
|
||||
|
||||
ns_os_init(program_name);
|
||||
|
||||
result = isc_app_start();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("isc_app_start() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
result = isc_mem_create(0, 0, &ns_g_mctx);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
ns_main_earlyfatal("isc_mem_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
dns_result_register();
|
||||
dst_result_register();
|
||||
isccc_result_register();
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
setup();
|
||||
|
||||
/*
|
||||
* Start things running and then wait for a shutdown request
|
||||
* or reload.
|
||||
*/
|
||||
do {
|
||||
result = isc_app_run();
|
||||
|
||||
if (result == ISC_R_RELOAD) {
|
||||
ns_server_reloadwanted(ns_g_server);
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_app_run(): %s",
|
||||
isc_result_totext(result));
|
||||
/*
|
||||
* Force exit.
|
||||
*/
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
} while (result != ISC_R_SUCCESS);
|
||||
|
||||
cleanup();
|
||||
|
||||
if (want_stats) {
|
||||
isc_mem_stats(ns_g_mctx, stdout);
|
||||
isc_mutex_stats(stdout);
|
||||
}
|
||||
isc_mem_destroy(&ns_g_mctx);
|
||||
|
||||
isc_app_finish();
|
||||
|
||||
ns_os_shutdown();
|
||||
|
||||
return (0);
|
||||
}
|
||||
49
bin/named/unix/include/named/os.h
Normal file
49
bin/named/unix/include/named/os.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 1999-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: os.h,v 1.14.2.2 2002/08/05 06:57:03 marka Exp $ */
|
||||
|
||||
#ifndef NS_OS_H
|
||||
#define NS_OS_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
|
||||
void
|
||||
ns_os_init(const char *progname);
|
||||
|
||||
void
|
||||
ns_os_daemonize(void);
|
||||
|
||||
void
|
||||
ns_os_chroot(const char *root);
|
||||
|
||||
void
|
||||
ns_os_inituserinfo(const char *username);
|
||||
|
||||
void
|
||||
ns_os_changeuser(void);
|
||||
|
||||
void
|
||||
ns_os_minprivs(void);
|
||||
|
||||
void
|
||||
ns_os_writepidfile(const char *filename, isc_boolean_t first_time);
|
||||
|
||||
void
|
||||
ns_os_shutdown(void);
|
||||
|
||||
#endif /* NS_OS_H */
|
||||
539
bin/named/unix/os.c
Normal file
539
bin/named/unix/os.c
Normal file
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
* Copyright (C) 1999-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: os.c,v 1.46.2.4 2002/08/05 06:57:03 marka Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/types.h> /* dev_t FreeBSD 2.1 */
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h> /* Required for initgroups() on IRIX. */
|
||||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <isc/file.h>
|
||||
#include <isc/print.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/strerror.h>
|
||||
#include <isc/string.h>
|
||||
|
||||
#include <named/main.h>
|
||||
#include <named/os.h>
|
||||
|
||||
static char *pidfile = NULL;
|
||||
|
||||
/*
|
||||
* If there's no <linux/capability.h>, we don't care about <sys/prctl.h>
|
||||
*/
|
||||
#ifndef HAVE_LINUX_CAPABILITY_H
|
||||
#undef HAVE_SYS_PRCTL_H
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Linux defines:
|
||||
* (T) HAVE_LINUXTHREADS
|
||||
* (C) HAVE_LINUX_CAPABILITY_H
|
||||
* (P) HAVE_SYS_PRCTL_H
|
||||
* The possible cases are:
|
||||
* none: setuid() normally
|
||||
* T: no setuid()
|
||||
* C: setuid() normally, drop caps (keep CAP_SETUID)
|
||||
* T+C: no setuid(), drop caps (don't keep CAP_SETUID)
|
||||
* T+C+P: setuid() early, drop caps (keep CAP_SETUID)
|
||||
* C+P: setuid() normally, drop caps (keep CAP_SETUID)
|
||||
* P: not possible
|
||||
* T+P: not possible
|
||||
*
|
||||
* if (C)
|
||||
* caps = BIND_SERVICE + CHROOT + SETGID
|
||||
* if ((T && C && P) || !T)
|
||||
* caps += SETUID
|
||||
* endif
|
||||
* capset(caps)
|
||||
* endif
|
||||
* if (T && C && P && -u)
|
||||
* setuid()
|
||||
* else if (T && -u)
|
||||
* fail
|
||||
* --> start threads
|
||||
* if (!T && -u)
|
||||
* setuid()
|
||||
* if (C && (P || !-u))
|
||||
* caps = BIND_SERVICE
|
||||
* capset(caps)
|
||||
* endif
|
||||
*
|
||||
* It will be nice when Linux threads work properly with setuid().
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
static pid_t mainpid = 0;
|
||||
#endif
|
||||
|
||||
static struct passwd *runas_pw = NULL;
|
||||
static isc_boolean_t done_setuid = ISC_FALSE;
|
||||
|
||||
#ifdef HAVE_LINUX_CAPABILITY_H
|
||||
|
||||
static isc_boolean_t non_root = ISC_FALSE;
|
||||
static isc_boolean_t non_root_caps = ISC_FALSE;
|
||||
|
||||
/*
|
||||
* We define _LINUX_FS_H to prevent it from being included. We don't need
|
||||
* anything from it, and the files it includes cause warnings with 2.2
|
||||
* kernels, and compilation failures (due to conflicts between <linux/string.h>
|
||||
* and <string.h>) on 2.3 kernels.
|
||||
*/
|
||||
#define _LINUX_FS_H
|
||||
|
||||
#include <sys/syscall.h> /* Required for syscall(). */
|
||||
#include <linux/capability.h> /* Required for _LINUX_CAPABILITY_VERSION. */
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
#include <sys/prctl.h> /* Required for prctl(). */
|
||||
|
||||
/*
|
||||
* If the value of PR_SET_KEEPCAPS is not in <sys/prctl.h>, define it
|
||||
* here. This allows setuid() to work on systems running a new enough
|
||||
* kernel but with /usr/include/linux pointing to "standard" kernel
|
||||
* headers.
|
||||
*/
|
||||
#ifndef PR_SET_KEEPCAPS
|
||||
#define PR_SET_KEEPCAPS 8
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_SYS_PRCTL_H */
|
||||
|
||||
#ifndef SYS_capset
|
||||
#ifndef __NR_capset
|
||||
#include <asm/unistd.h> /* Slackware 4.0 needs this. */
|
||||
#endif
|
||||
#define SYS_capset __NR_capset
|
||||
#endif
|
||||
|
||||
static void
|
||||
linux_setcaps(unsigned int caps) {
|
||||
struct __user_cap_header_struct caphead;
|
||||
struct __user_cap_data_struct cap;
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
|
||||
if ((getuid() != 0 && !non_root_caps) || non_root)
|
||||
return;
|
||||
|
||||
memset(&caphead, 0, sizeof caphead);
|
||||
caphead.version = _LINUX_CAPABILITY_VERSION;
|
||||
caphead.pid = 0;
|
||||
memset(&cap, 0, sizeof cap);
|
||||
cap.effective = caps;
|
||||
cap.permitted = caps;
|
||||
cap.inheritable = caps;
|
||||
if (syscall(SYS_capset, &caphead, &cap) < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("capset failed: %s", strbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
linux_initialprivs(void) {
|
||||
unsigned int caps;
|
||||
|
||||
/*
|
||||
* We don't need most privileges, so we drop them right away.
|
||||
* Later on linux_minprivs() will be called, which will drop our
|
||||
* capabilities to the minimum needed to run the server.
|
||||
*/
|
||||
|
||||
caps = 0;
|
||||
|
||||
/*
|
||||
* We need to be able to bind() to privileged ports, notably port 53!
|
||||
*/
|
||||
caps |= (1 << CAP_NET_BIND_SERVICE);
|
||||
|
||||
/*
|
||||
* We need chroot() initially too.
|
||||
*/
|
||||
caps |= (1 << CAP_SYS_CHROOT);
|
||||
|
||||
#if defined(HAVE_SYS_PRCTL_H) || !defined(HAVE_LINUXTHREADS)
|
||||
/*
|
||||
* We can setuid() only if either the kernel supports keeping
|
||||
* capabilities after setuid() (which we don't know until we've
|
||||
* tried) or we're not using threads. If either of these is
|
||||
* true, we want the setuid capability.
|
||||
*/
|
||||
caps |= (1 << CAP_SETUID);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since we call initgroups, we need this.
|
||||
*/
|
||||
caps |= (1 << CAP_SETGID);
|
||||
|
||||
/*
|
||||
* Without this, we run into problems reading a configuration file
|
||||
* owned by a non-root user and non-world-readable on startup.
|
||||
*/
|
||||
caps |= (1 << CAP_DAC_READ_SEARCH);
|
||||
|
||||
/*
|
||||
* XXX We might want to add CAP_SYS_RESOURCE, though it's not
|
||||
* clear it would work right given the way linuxthreads work.
|
||||
* XXXDCL But since we need to be able to set the maximum number
|
||||
* of files, the stack size, data size, and core dump size to
|
||||
* support named.conf options, this is now being added to test.
|
||||
*/
|
||||
caps |= (1 << CAP_SYS_RESOURCE);
|
||||
|
||||
linux_setcaps(caps);
|
||||
}
|
||||
|
||||
static void
|
||||
linux_minprivs(void) {
|
||||
unsigned int caps;
|
||||
|
||||
/*
|
||||
* Drop all privileges except the ability to bind() to privileged
|
||||
* ports.
|
||||
*
|
||||
* It's important that we drop CAP_SYS_CHROOT. If we didn't, it
|
||||
* chroot() could be used to escape from the chrooted area.
|
||||
*/
|
||||
|
||||
caps = 0;
|
||||
caps |= (1 << CAP_NET_BIND_SERVICE);
|
||||
|
||||
/*
|
||||
* XXX We might want to add CAP_SYS_RESOURCE, though it's not
|
||||
* clear it would work right given the way linuxthreads work.
|
||||
* XXXDCL But since we need to be able to set the maximum number
|
||||
* of files, the stack size, data size, and core dump size to
|
||||
* support named.conf options, this is now being added to test.
|
||||
*/
|
||||
caps |= (1 << CAP_SYS_RESOURCE);
|
||||
|
||||
linux_setcaps(caps);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
static void
|
||||
linux_keepcaps(void) {
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
/*
|
||||
* Ask the kernel to allow us to keep our capabilities after we
|
||||
* setuid().
|
||||
*/
|
||||
|
||||
if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
|
||||
if (errno != EINVAL) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("prctl() failed: %s", strbuf);
|
||||
}
|
||||
} else {
|
||||
non_root_caps = ISC_TRUE;
|
||||
if (getuid() != 0)
|
||||
non_root = ISC_TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_LINUX_CAPABILITY_H */
|
||||
|
||||
|
||||
static void
|
||||
setup_syslog(const char *progname) {
|
||||
int options;
|
||||
|
||||
options = LOG_PID;
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
openlog(isc_file_basename(progname), options, LOG_DAEMON);
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_init(const char *progname) {
|
||||
setup_syslog(progname);
|
||||
#ifdef HAVE_LINUX_CAPABILITY_H
|
||||
linux_initialprivs();
|
||||
#endif
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
mainpid = getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_daemonize(void) {
|
||||
pid_t pid;
|
||||
int fd;
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("fork(): %s", strbuf);
|
||||
}
|
||||
if (pid != 0)
|
||||
_exit(0);
|
||||
|
||||
/*
|
||||
* We're the child.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
mainpid = getpid();
|
||||
#endif
|
||||
|
||||
if (setsid() == -1) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("setsid(): %s", strbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to set stdin, stdout, and stderr to /dev/null, but press
|
||||
* on even if it fails.
|
||||
*
|
||||
* XXXMLG The close() calls here are unneeded on all but NetBSD, but
|
||||
* are harmless to include everywhere. dup2() is supposed to close
|
||||
* the FD if it is in use, but unproven-pthreads-0.16 is broken
|
||||
* and will end up closing the wrong FD. This will be fixed eventually,
|
||||
* and these calls will be removed.
|
||||
*/
|
||||
fd = open("/dev/null", O_RDWR, 0);
|
||||
if (fd != -1) {
|
||||
close(STDIN_FILENO);
|
||||
(void)dup2(fd, STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
(void)dup2(fd, STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
(void)dup2(fd, STDERR_FILENO);
|
||||
if (fd != STDIN_FILENO &&
|
||||
fd != STDOUT_FILENO &&
|
||||
fd != STDERR_FILENO)
|
||||
(void)close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
all_digits(const char *s) {
|
||||
if (*s == '\0')
|
||||
return (ISC_FALSE);
|
||||
while (*s != '\0') {
|
||||
if (!isdigit((*s)&0xff))
|
||||
return (ISC_FALSE);
|
||||
s++;
|
||||
}
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_chroot(const char *root) {
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
if (root != NULL) {
|
||||
if (chroot(root) < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("chroot(): %s", strbuf);
|
||||
}
|
||||
if (chdir("/") < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("chdir(/): %s", strbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_inituserinfo(const char *username) {
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
if (username == NULL)
|
||||
return;
|
||||
|
||||
if (all_digits(username))
|
||||
runas_pw = getpwuid((uid_t)atoi(username));
|
||||
else
|
||||
runas_pw = getpwnam(username);
|
||||
endpwent();
|
||||
|
||||
if (runas_pw == NULL)
|
||||
ns_main_earlyfatal("user '%s' unknown", username);
|
||||
|
||||
if (getuid() == 0) {
|
||||
if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("initgroups(): %s", strbuf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_changeuser(void) {
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
if (runas_pw == NULL || done_setuid)
|
||||
return;
|
||||
|
||||
done_setuid = ISC_TRUE;
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
#ifdef HAVE_LINUX_CAPABILITY_H
|
||||
if (!non_root_caps)
|
||||
#endif
|
||||
ns_main_earlyfatal(
|
||||
"-u not supported on Linux kernels older than "
|
||||
"2.3.99-pre3 or 2.2.18 when using threads");
|
||||
#endif
|
||||
|
||||
if (setgid(runas_pw->pw_gid) < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("setgid(): %s", strbuf);
|
||||
}
|
||||
|
||||
if (setuid(runas_pw->pw_uid) < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
ns_main_earlyfatal("setuid(): %s", strbuf);
|
||||
}
|
||||
|
||||
#if defined(HAVE_LINUX_CAPABILITY_H) && !defined(HAVE_LINUXTHREADS)
|
||||
linux_minprivs();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_minprivs(void) {
|
||||
#ifdef HAVE_SYS_PRCTL_H
|
||||
linux_keepcaps();
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
ns_os_changeuser(); /* Call setuid() before threads are started */
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LINUX_CAPABILITY_H) && defined(HAVE_LINUXTHREADS)
|
||||
linux_minprivs();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
safe_open(const char *filename, isc_boolean_t append) {
|
||||
int fd;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(filename, &sb) == -1) {
|
||||
if (errno != ENOENT)
|
||||
return (-1);
|
||||
} else if ((sb.st_mode & S_IFREG) == 0) {
|
||||
errno = EOPNOTSUPP;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (append)
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_APPEND,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
else {
|
||||
(void)unlink(filename);
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
}
|
||||
return (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_pidfile(void) {
|
||||
if (pidfile != NULL) {
|
||||
(void)unlink(pidfile);
|
||||
free(pidfile);
|
||||
}
|
||||
pidfile = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
|
||||
int fd;
|
||||
FILE *lockfile;
|
||||
size_t len;
|
||||
pid_t pid;
|
||||
char strbuf[ISC_STRERRORSIZE];
|
||||
void (*report)(const char *, ...);
|
||||
|
||||
/*
|
||||
* The caller must ensure any required synchronization.
|
||||
*/
|
||||
|
||||
report = first_time ? ns_main_earlyfatal : ns_main_earlywarning;
|
||||
|
||||
cleanup_pidfile();
|
||||
|
||||
len = strlen(filename);
|
||||
pidfile = malloc(len + 1);
|
||||
if (pidfile == NULL) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
(*report)("couldn't malloc '%s': %s", filename, strbuf);
|
||||
return;
|
||||
}
|
||||
/* This is safe. */
|
||||
strcpy(pidfile, filename);
|
||||
|
||||
fd = safe_open(filename, ISC_FALSE);
|
||||
if (fd < 0) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
(*report)("couldn't open pid file '%s': %s", filename, strbuf);
|
||||
free(pidfile);
|
||||
pidfile = NULL;
|
||||
return;
|
||||
}
|
||||
lockfile = fdopen(fd, "w");
|
||||
if (lockfile == NULL) {
|
||||
isc__strerror(errno, strbuf, sizeof(strbuf));
|
||||
(*report)("could not fdopen() pid file '%s': %s",
|
||||
filename, strbuf);
|
||||
(void)close(fd);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
pid = mainpid;
|
||||
#else
|
||||
pid = getpid();
|
||||
#endif
|
||||
if (fprintf(lockfile, "%ld\n", (long)pid) < 0) {
|
||||
(*report)("fprintf() to pid file '%s' failed", filename);
|
||||
(void)fclose(lockfile);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
if (fflush(lockfile) == EOF) {
|
||||
(*report)("fflush() to pid file '%s' failed", filename);
|
||||
(void)fclose(lockfile);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
(void)fclose(lockfile);
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_shutdown(void) {
|
||||
closelog();
|
||||
cleanup_pidfile();
|
||||
}
|
||||
49
bin/named/win32/include/named/os.h
Normal file
49
bin/named/win32/include/named/os.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 1999-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: os.h,v 1.1.2.2 2002/08/05 06:57:04 marka Exp $ */
|
||||
|
||||
#ifndef NS_OS_H
|
||||
#define NS_OS_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
|
||||
void
|
||||
ns_os_init(const char *progname);
|
||||
|
||||
void
|
||||
ns_os_daemonize(void);
|
||||
|
||||
void
|
||||
ns_os_chroot(const char *root);
|
||||
|
||||
void
|
||||
ns_os_inituserinfo(const char *username);
|
||||
|
||||
void
|
||||
ns_os_changeuser(void);
|
||||
|
||||
void
|
||||
ns_os_minprivs(void);
|
||||
|
||||
void
|
||||
ns_os_writepidfile(const char *filename, isc_boolean_t first_time);
|
||||
|
||||
void
|
||||
ns_os_shutdown(void);
|
||||
|
||||
#endif /* NS_OS_H */
|
||||
227
bin/named/win32/os.c
Normal file
227
bin/named/win32/os.c
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (C) 1999-2002 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
|
||||
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
|
||||
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
|
||||
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: os.c,v 1.5.2.3 2002/08/08 19:15:19 mayer Exp $ */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
#include <process.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include <isc/print.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/string.h>
|
||||
//#include <isc/ntfile.h>
|
||||
#include <isc/ntpaths.h>
|
||||
|
||||
#include <named/main.h>
|
||||
#include <named/os.h>
|
||||
#include <named/globals.h>
|
||||
#include <named/ntservice.h>
|
||||
|
||||
|
||||
static char *pidfile = NULL;
|
||||
|
||||
static BOOL Initialized = FALSE;
|
||||
|
||||
void
|
||||
ns_paths_init() {
|
||||
if (!Initialized)
|
||||
isc_ntpaths_init();
|
||||
|
||||
ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH);
|
||||
lwresd_g_conffile = isc_ntpaths_get(LWRES_CONF_PATH);
|
||||
lwresd_g_resolvconffile = isc_ntpaths_get(RESOLV_CONF_PATH);
|
||||
ns_g_conffile = isc_ntpaths_get(NAMED_CONF_PATH);
|
||||
ns_g_defaultpidfile = isc_ntpaths_get(NAMED_PID_PATH);
|
||||
lwresd_g_defaultpidfile = isc_ntpaths_get(LWRESD_PID_PATH);
|
||||
ns_g_keyfile = isc_ntpaths_get(RNDC_KEY_PATH);
|
||||
|
||||
Initialized = TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
setup_syslog(const char *progname) {
|
||||
int options;
|
||||
|
||||
options = LOG_PID;
|
||||
#ifdef LOG_NDELAY
|
||||
options |= LOG_NDELAY;
|
||||
#endif
|
||||
|
||||
openlog(progname, options, LOG_DAEMON);
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_init(const char *progname) {
|
||||
ns_paths_init();
|
||||
setup_syslog(progname);
|
||||
ntservice_init();
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_daemonize(void) {
|
||||
int fd;
|
||||
|
||||
/*
|
||||
* Try to set stdin, stdout, and stderr to /dev/null, but press
|
||||
* on even if it fails.
|
||||
*
|
||||
* XXXMLG The close() calls here are unneeded on all but NetBSD, but
|
||||
* are harmless to include everywhere. dup2() is supposed to close
|
||||
* the FD if it is in use, but unproven-pthreads-0.16 is broken
|
||||
* and will end up closing the wrong FD. This will be fixed eventually,
|
||||
* and these calls will be removed.
|
||||
*/
|
||||
fd = open("NUL", O_RDWR, 0);
|
||||
if (fd != -1) {
|
||||
close(_fileno(stdin));
|
||||
(void)_dup2(fd, _fileno(stdin));
|
||||
close(_fileno(stdout));
|
||||
(void)_dup2(fd, _fileno(stdout));
|
||||
close(_fileno(stderr));
|
||||
(void)_dup2(fd, _fileno(stderr));
|
||||
if (fd != _fileno(stdin) &&
|
||||
fd != _fileno(stdout) &&
|
||||
fd != _fileno(stderr))
|
||||
(void)close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_chroot(const char *root) {
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_inituserinfo(const char *username) {
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_changeuser(void) {
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_minprivs(void) {
|
||||
}
|
||||
|
||||
static int
|
||||
safe_open(const char *filename, isc_boolean_t append) {
|
||||
int fd;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(filename, &sb) == -1) {
|
||||
if (errno != ENOENT)
|
||||
return (-1);
|
||||
} else if ((sb.st_mode & S_IFREG) == 0)
|
||||
return (-1);
|
||||
|
||||
if (append)
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_APPEND,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
else {
|
||||
(void)unlink(filename);
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
|
||||
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
}
|
||||
return (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_pidfile(void) {
|
||||
if (pidfile != NULL) {
|
||||
(void)unlink(pidfile);
|
||||
free(pidfile);
|
||||
}
|
||||
pidfile = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_writepidfile(const char *filename, isc_boolean_t first_time) {
|
||||
int fd;
|
||||
FILE *lockfile;
|
||||
size_t len;
|
||||
pid_t pid;
|
||||
void (*report)(const char *, ...);
|
||||
|
||||
/*
|
||||
* The caller must ensure any required synchronization.
|
||||
*/
|
||||
|
||||
report = first_time ? ns_main_earlyfatal : ns_main_earlywarning;
|
||||
|
||||
cleanup_pidfile();
|
||||
|
||||
len = strlen(filename);
|
||||
pidfile = malloc(len + 1);
|
||||
if (pidfile == NULL) {
|
||||
(*report)("couldn't malloc '%s': %s", filename,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
/* This is safe. */
|
||||
strcpy(pidfile, filename);
|
||||
|
||||
fd = safe_open(filename, ISC_FALSE);
|
||||
if (fd < 0) {
|
||||
(*report)("couldn't open pid file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
free(pidfile);
|
||||
pidfile = NULL;
|
||||
return;
|
||||
}
|
||||
lockfile = fdopen(fd, "w");
|
||||
if (lockfile == NULL) {
|
||||
(*report)("could not fdopen() pid file '%s': %s", filename,
|
||||
strerror(errno));
|
||||
(void)close(fd);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
|
||||
pid = getpid();
|
||||
|
||||
if (fprintf(lockfile, "%ld\n", (long)pid) < 0) {
|
||||
(*report)("fprintf() to pid file '%s' failed", filename);
|
||||
(void)fclose(lockfile);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
if (fflush(lockfile) == EOF) {
|
||||
(*report)("fflush() to pid file '%s' failed", filename);
|
||||
(void)fclose(lockfile);
|
||||
cleanup_pidfile();
|
||||
return;
|
||||
}
|
||||
(void)fclose(lockfile);
|
||||
}
|
||||
|
||||
void
|
||||
ns_os_shutdown(void) {
|
||||
closelog();
|
||||
cleanup_pidfile();
|
||||
ntservice_shutdown(); /* This MUST be the last thing done */
|
||||
}
|
||||
Loading…
Reference in a new issue