From: Wouter Wijngaards Date: Wed, 31 Oct 2007 10:56:31 +0000 (+0000) Subject: better chroot support, and also default chroot and userchange. X-Git-Tag: release-0.6~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2e9785cfb5c752e8a2bed93b6764aeb046377ef1;p=thirdparty%2Funbound.git better chroot support, and also default chroot and userchange. git-svn-id: file:///svn/unbound/trunk@723 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/Makefile.in b/Makefile.in index 70772d262..a6475fef6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -32,8 +32,8 @@ staticexe=@staticexe@ YACC=@YACC@ LEX=@LEX@ CC=@CC@ -CPPFLAGS=-I. @CPPFLAGS@ @DEFS@ -CFLAGS=-I. @CFLAGS@ +CPPFLAGS=-I$(srcdir) @CPPFLAGS@ @DEFS@ +CFLAGS=@CFLAGS@ LDFLAGS=@LDFLAGS@ LIBS=@LIBS@ LIBOBJS=@LIBOBJS@ @@ -59,7 +59,8 @@ COMMON_SRC=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/services/*.c \ util/configparser.c util/configlexer.c testcode/checklocks.c COMMON_OBJ=$(addprefix $(BUILD),$(COMMON_SRC:.c=.o)) COMPAT_OBJ=$(addprefix $(BUILD)compat/,$(LIBOBJS)) -UNITTEST_SRC=$(patsubst $(srcdir)/%,%, $(wildcard $(srcdir)/testcode/unit*.c)) \ +UNITTEST_SRC=$(patsubst $(srcdir)/%,%, \ + $(wildcard $(srcdir)/testcode/unit*.c)) \ testcode/readhex.c testcode/ldns-testpkts.c checkconf/worker_cb.c \ $(COMMON_SRC) UNITTEST_OBJ=$(addprefix $(BUILD),$(UNITTEST_SRC:.c=.o)) $(COMPAT_OBJ) diff --git a/checkconf/unbound-checkconf.c b/checkconf/unbound-checkconf.c index 8869fbeea..ba4e20a92 100644 --- a/checkconf/unbound-checkconf.c +++ b/checkconf/unbound-checkconf.c @@ -172,7 +172,7 @@ int main(int argc, char* argv[]) { int c; log_ident_set("unbound-checkconf"); - log_init(NULL, 0); + log_init(NULL, 0, NULL); /* parse the options */ while( (c=getopt(argc, argv, "h")) != -1) { switch(c) { diff --git a/daemon/daemon.c b/daemon/daemon.c index c585ef0e3..1ef5f6cd3 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -460,7 +460,6 @@ daemon_delete(struct daemon* daemon) infra_delete(daemon->env->infra_cache); } alloc_clear(&daemon->superalloc); - free(daemon->cwd); free(daemon->pidfile); free(daemon->env); free(daemon); diff --git a/daemon/daemon.h b/daemon/daemon.h index bc20abc09..be24f5bad 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -58,8 +58,6 @@ struct rrset_cache; struct daemon { /** The config settings */ struct config_file* cfg; - /** current working directory */ - char* cwd; /** pidfile that is used */ char* pidfile; /** port number that has ports opened. */ diff --git a/daemon/unbound.c b/daemon/unbound.c index 3b5149723..953586162 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -110,25 +110,15 @@ checkrlimits(struct config_file* cfg) } } -/** to changedir, logfile */ +/** set verbosity, check rlimits, cache settings */ static void -apply_dir(struct daemon* daemon, struct config_file* cfg, int cmdline_verbose) +apply_settings(struct daemon* daemon, struct config_file* cfg, + int cmdline_verbose) { /* apply if they have changed */ daemon->cfg = cfg; verbosity = cmdline_verbose + cfg->verbosity; config_apply(cfg); - if(cfg->directory && cfg->directory[0]) { - if(!daemon->cwd || strcmp(daemon->cwd, cfg->directory) != 0) { - if(chdir(cfg->directory)) { - log_err("Could not chdir to %s: %s", - cfg->directory, strerror(errno)); - } - free(daemon->cwd); - if(!(daemon->cwd = strdup(cfg->directory))) - log_err("cwd: malloc failed"); - } - } if(!daemon->env->msg_cache || cfg->msg_cache_size != slabhash_get_size(daemon->env->msg_cache) || cfg->msg_cache_slabs != daemon->env->msg_cache->size) { @@ -223,7 +213,12 @@ static void checkoldpid(struct config_file* cfg) { pid_t old; - if((old = readpid(cfg->pidfile)) != -1) { + char* file = cfg->pidfile; + if(cfg->chrootdir && cfg->chrootdir[0] && + strncmp(file, cfg->chrootdir, strlen(cfg->chrootdir))==0) { + file += strlen(cfg->chrootdir); + } + if((old = readpid(file)) != -1) { /* see if it is still alive */ if(kill(old, 0) == 0 || errno == EPERM) log_warn("unbound is already running as pid %u.", @@ -268,9 +263,15 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode) log_assert(cfg); /* daemonize last to be able to print error to user */ + if(cfg->directory && cfg->directory[0]) + if(chdir(cfg->directory)) { + fatal_exit("Could not chdir to %s: %s", + cfg->directory, strerror(errno)); + } if(cfg->chrootdir && cfg->chrootdir[0]) if(chroot(cfg->chrootdir)) - fatal_exit("unable to chroot: %s", strerror(errno)); + fatal_exit("unable to chroot to %s: %s", + cfg->chrootdir, strerror(errno)); if(cfg->username && cfg->username[0]) { struct passwd *pwd; if((pwd = getpwnam(cfg->username)) == NULL) @@ -287,13 +288,17 @@ do_chroot(struct daemon* daemon, struct config_file* cfg, int debug_mode) } /* init logfile just before fork */ - log_init(cfg->logfile, cfg->use_syslog); + log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); if(!debug_mode && cfg->do_daemonize) { detach(cfg); } if(cfg->pidfile && cfg->pidfile[0]) { - writepid(cfg->pidfile, getpid()); - if(!(daemon->pidfile = strdup(cfg->pidfile))) + char* pf = cfg->pidfile; + if(cfg->chrootdir && cfg->chrootdir[0] && + strncmp(pf, cfg->chrootdir, strlen(cfg->chrootdir))==0) + pf += strlen(cfg->chrootdir); + writepid(pf, getpid()); + if(!(daemon->pidfile = strdup(pf))) log_err("pidf: malloc failed"); } } @@ -324,7 +329,7 @@ run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode) fatal_exit("Could not alloc config defaults"); if(!config_read(cfg, cfgfile)) fatal_exit("Could not read config file: %s", cfgfile); - apply_dir(daemon, cfg, cmdline_verbose); + apply_settings(daemon, cfg, cmdline_verbose); /* prepare */ if(!daemon_open_shared_ports(daemon)) @@ -332,7 +337,7 @@ run_daemon(char* cfgfile, int cmdline_verbose, int debug_mode) if(!done_chroot) { do_chroot(daemon, cfg, debug_mode); done_chroot = 1; - } else log_init(cfg->logfile, cfg->use_syslog); + } else log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); /* work */ daemon_fork(daemon); @@ -369,7 +374,7 @@ main(int argc, char* argv[]) /* take debug snapshot of heap */ unbound_start_brk = sbrk(0); - log_init(NULL, 0); + log_init(NULL, 0, NULL); /* parse the options */ while( (c=getopt(argc, argv, "c:dhv")) != -1) { switch(c) { @@ -399,6 +404,6 @@ main(int argc, char* argv[]) } run_daemon(cfgfile, cmdline_verbose, debug_mode); - log_init(NULL, 0); /* close logfile */ + log_init(NULL, 0, NULL); /* close logfile */ return 0; } diff --git a/doc/Changelog b/doc/Changelog index eb937c230..d024105ce 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,6 +1,10 @@ 31 October 2007: Wouter - cache-max-ttl config option. - building outside sourcedir works again. + - defaults more secure: + username: "unbound" + chroot: "/etc/unbound" + The operator can override them to be less secure ("") if necessary. 30 October 2007: Wouter - fixup assertion failure that relied on compressed names to be diff --git a/doc/TODO b/doc/TODO index 7f6fcf8b7..eb082ccff 100644 --- a/doc/TODO +++ b/doc/TODO @@ -52,3 +52,4 @@ o make timeout backoffs randomized (a couple percent random) to spread traffic. o inspect date on executable, then warn user in log if its more than 1 year. o proactively prime root, stubs and trust anchors, feature. early failure, faster on first query, but more traffic. +o use privilege separation, to change privilege options during reload securely diff --git a/doc/example.conf b/doc/example.conf index 1125b5ba0..a96670758 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -114,10 +114,12 @@ server: # if given, a chroot(2) is done to the given directory. # i.e. you can chroot to the working directory, for example, # for extra security, but make sure all files are in that directory. - # chroot: "/some/directory" + # If you give "" no chroot is performed. + # chroot: "/etc/unbound" # if given, user privileges are dropped (after binding port), - # and the given username is assumed. Default is nothing "". + # and the given username is assumed. Default is user "unbound". + # If you give "" no priviliges are dropped. # username: "unbound" # the working directory. diff --git a/doc/unbound.conf.5 b/doc/unbound.conf.5 index 6100154d5..a3603339b 100644 --- a/doc/unbound.conf.5 +++ b/doc/unbound.conf.5 @@ -155,10 +155,11 @@ Enable or disable whether UDP queries are answered. Default is yes. .It \fBdo-tcp:\fR Enable or disable whether TCP queries are answered. Default is yes. .It \fBchroot:\fR -If given a chroot is done to the given directory. The default is none (""). +If given a chroot is done to the given directory. The default is +"/etc/unbound". If you give "" no chroot is performed. .It \fBusername:\fR If given, after binding the port the user privileges are dropped. Default is -not to change user, username: "". +"unbound". If you give username: "" no user change is performed. .Pp If this user is not capable of binding the port, reloads (by signal HUP) will still retain the opened ports. @@ -355,13 +356,16 @@ server: .Sh FILES .Bl -tag -width indent .It Pa /etc/unbound -default unbound working directory +default unbound working directory and default +.Xr chroot 2 +location. .It Pa unbound.conf unbound configuration file. .It Pa unbound.pid default unbound pidfile with process ID of the running daemon. .It Pa unbound.log -unbound log file. +unbound log file. default is to log to +.Xr syslog 3 . .El .Sh SEE ALSO .Xr unbound 8 , diff --git a/testcode/lock_verify.c b/testcode/lock_verify.c index 21ec324d7..96fd6ca46 100644 --- a/testcode/lock_verify.c +++ b/testcode/lock_verify.c @@ -385,7 +385,7 @@ main(int argc, char* argv[]) usage(); return 1; } - log_init(NULL, 0); + log_init(NULL, 0, NULL); log_ident_set("lock-verify"); /* init */ all_locks = rbtree_create(order_lock_cmp); diff --git a/testcode/signit.c b/testcode/signit.c index 717b4e2de..3072ffefa 100644 --- a/testcode/signit.c +++ b/testcode/signit.c @@ -236,7 +236,7 @@ process_nsec3(int argc, char* argv[]) /** main program */ int main(int argc, char* argv[]) { - log_init(NULL, 0); + log_init(NULL, 0, NULL); if(argc != 6) { usage(); } diff --git a/testcode/testbound.c b/testcode/testbound.c index 6a45a74ec..c7de18150 100644 --- a/testcode/testbound.c +++ b/testcode/testbound.c @@ -138,6 +138,8 @@ setup_config(FILE* in, char* configfile, int* lineno, /* some basic settings to not pollute the host system */ fprintf(cfg, "server: use-syslog: no\n"); fprintf(cfg, " directory: \"\"\n"); + fprintf(cfg, " chroot: \"\"\n"); + fprintf(cfg, " username: \"\"\n"); while(fgets(line, MAX_LINE_LEN-1, in)) { parse = line; (*lineno)++; @@ -207,7 +209,7 @@ main(int argc, char* argv[]) char* init_optarg = optarg; struct replay_scenario* scen = NULL; - log_init(NULL, 0); + log_init(NULL, 0, NULL); log_info("Start of %s testbound program.", PACKAGE_STRING); /* determine commandline options for the daemon */ cfgfile[0] = 0; diff --git a/testcode/unitmain.c b/testcode/unitmain.c index 0db87f85e..03ff3cfad 100644 --- a/testcode/unitmain.c +++ b/testcode/unitmain.c @@ -228,7 +228,7 @@ rnd_test() int main(int argc, char* argv[]) { - log_init(NULL, 0); + log_init(NULL, 0, NULL); if(argc != 1) { printf("usage: %s\n", argv[0]); printf("\tperforms unit tests.\n"); diff --git a/testdata/fwd_compress_c00c.tpkg b/testdata/fwd_compress_c00c.tpkg index 1bac0886d..627cf92d4 100644 Binary files a/testdata/fwd_compress_c00c.tpkg and b/testdata/fwd_compress_c00c.tpkg differ diff --git a/testdata/fwd_no_edns.tpkg b/testdata/fwd_no_edns.tpkg index 1b8e1bedc..34962337e 100644 Binary files a/testdata/fwd_no_edns.tpkg and b/testdata/fwd_no_edns.tpkg differ diff --git a/testdata/fwd_tcp.tpkg b/testdata/fwd_tcp.tpkg index cad670dd8..bef8747bc 100644 Binary files a/testdata/fwd_tcp.tpkg and b/testdata/fwd_tcp.tpkg differ diff --git a/testdata/fwd_tcp_tc.tpkg b/testdata/fwd_tcp_tc.tpkg index e061afe5e..1487a253a 100644 Binary files a/testdata/fwd_tcp_tc.tpkg and b/testdata/fwd_tcp_tc.tpkg differ diff --git a/testdata/fwd_tcp_tc6.tpkg b/testdata/fwd_tcp_tc6.tpkg index f7762488e..df45e9e5b 100644 Binary files a/testdata/fwd_tcp_tc6.tpkg and b/testdata/fwd_tcp_tc6.tpkg differ diff --git a/testdata/fwd_three.tpkg b/testdata/fwd_three.tpkg index ca8946971..860b17a77 100644 Binary files a/testdata/fwd_three.tpkg and b/testdata/fwd_three.tpkg differ diff --git a/testdata/fwd_three_service.tpkg b/testdata/fwd_three_service.tpkg index 65e6148d8..983e47b75 100644 Binary files a/testdata/fwd_three_service.tpkg and b/testdata/fwd_three_service.tpkg differ diff --git a/testdata/fwd_ttlexpire.tpkg b/testdata/fwd_ttlexpire.tpkg index 3c3b120fc..98e3f21d4 100644 Binary files a/testdata/fwd_ttlexpire.tpkg and b/testdata/fwd_ttlexpire.tpkg differ diff --git a/testdata/fwd_udp.tpkg b/testdata/fwd_udp.tpkg index cb5482090..d3c398666 100644 Binary files a/testdata/fwd_udp.tpkg and b/testdata/fwd_udp.tpkg differ diff --git a/util/config_file.c b/util/config_file.c index a2a836377..76d42968c 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -93,8 +93,8 @@ config_create() cfg->infra_cache_slabs = 4; cfg->infra_cache_numhosts = 10000; cfg->infra_cache_lame_size = 10240; /* easily 40 or more entries */ - if(!(cfg->username = strdup(""))) goto error_exit; - if(!(cfg->chrootdir = strdup(""))) goto error_exit; + if(!(cfg->username = strdup("unbound"))) goto error_exit; + if(!(cfg->chrootdir = strdup("/etc/unbound"))) goto error_exit; if(!(cfg->directory = strdup("/etc/unbound"))) goto error_exit; if(!(cfg->logfile = strdup(""))) goto error_exit; if(!(cfg->pidfile = strdup("unbound.pid"))) goto error_exit; diff --git a/util/log.c b/util/log.c index a0b33a9ec..a63080947 100644 --- a/util/log.c +++ b/util/log.c @@ -71,7 +71,7 @@ static int log_to_syslog = 0; #endif /* HAVE_SYSLOG_H */ void -log_init(const char* filename, int use_syslog) +log_init(const char* filename, int use_syslog, const char* chrootdir) { FILE *f; if(!key_created) { @@ -103,6 +103,9 @@ log_init(const char* filename, int use_syslog) return; } /* open the file for logging */ + if(chrootdir && chrootdir[0] && strncmp(filename, chrootdir, + strlen(chrootdir)) == 0) + filename += strlen(chrootdir); f = fopen(filename, "a"); if(!f) { log_err("Could not open logfile %s: %s", filename, diff --git a/util/log.h b/util/log.h index f14256f17..fb4096375 100644 --- a/util/log.h +++ b/util/log.h @@ -78,8 +78,9 @@ void verbose(enum verbosity_value level, * call this to initialize logging services. * @param filename: if NULL stderr is used. * @param use_syslog: set to true to ignore filename and use syslog(3). + * @param chrootdir: to which directory we have been chrooted, if any. */ -void log_init(const char* filename, int use_syslog); +void log_init(const char* filename, int use_syslog, const char* chrootdir); /** * Init a thread (will print this number for the thread log entries).