]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
better chroot support, and also default chroot and userchange.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 31 Oct 2007 10:56:31 +0000 (10:56 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 31 Oct 2007 10:56:31 +0000 (10:56 +0000)
git-svn-id: file:///svn/unbound/trunk@723 be551aaa-1e26-0410-a405-d3ace91eadb9

25 files changed:
Makefile.in
checkconf/unbound-checkconf.c
daemon/daemon.c
daemon/daemon.h
daemon/unbound.c
doc/Changelog
doc/TODO
doc/example.conf
doc/unbound.conf.5
testcode/lock_verify.c
testcode/signit.c
testcode/testbound.c
testcode/unitmain.c
testdata/fwd_compress_c00c.tpkg
testdata/fwd_no_edns.tpkg
testdata/fwd_tcp.tpkg
testdata/fwd_tcp_tc.tpkg
testdata/fwd_tcp_tc6.tpkg
testdata/fwd_three.tpkg
testdata/fwd_three_service.tpkg
testdata/fwd_ttlexpire.tpkg
testdata/fwd_udp.tpkg
util/config_file.c
util/log.c
util/log.h

index 70772d2628d4583be1a4b5e3af40053f51865a0d..a6475fef655cfec520f5e2bac6276fdf44b16f83 100644 (file)
@@ -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)
index 8869fbeea49d68b863b65de30051810411cd100a..ba4e20a92d7fe9737b4588ac2af77f33abcd9107 100644 (file)
@@ -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) {
index c585ef0e3f76c774c22af0554933e365fb594940..1ef5f6cd37a5f9c8f64871c61ee08d849064cd20 100644 (file)
@@ -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);
index bc20abc09cbb07202a728d40ddeeb3123f564ad9..be24f5bad0d6b35453ebe9d15206e0736fea67cd 100644 (file)
@@ -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. */
index 3b5149723bea7b3fa0addb6ebb448b1da3b1c9ce..95358616243d6dc6a7bd9a5725e322a70f63e0b1 100644 (file)
@@ -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;
 }
index eb937c230e84d2ae5d1a7865836e5eac160c2e3c..d024105ce45e545b7c8a269baa60351b967368ae 100644 (file)
@@ -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
index 7f6fcf8b74ce909228c598b0682f589d8ec9fece..eb082ccffe39ef07e8adf79d3028b02df68ba78a 100644 (file)
--- 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
index 1125b5ba084a81ae3f879b9568aea308ec9df138..a96670758dcda3aaa7bb932ef1682346c76b6233 100644 (file)
@@ -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.
index 6100154d57bd13e5b000b84240c56fa979740e8f..a3603339b58830d8ac235ae6e625d269e2976e7d 100644 (file)
@@ -155,10 +155,11 @@ Enable or disable whether UDP queries are answered. Default is yes.
 .It \fBdo-tcp:\fR <yes or no>
 Enable or disable whether TCP queries are answered. Default is yes.
 .It \fBchroot:\fR <directory>
-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 <name>
 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 , 
index 21ec324d7a493c50eea9cb402055cc7fb7690988..96fd6ca46a9d50776d844ae53e77e0f0e08c093b 100644 (file)
@@ -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);
index 717b4e2de676ccaa06228eee443d10acb773d2e4..3072ffefaded7e77a7ffb167743b4b576805d524 100644 (file)
@@ -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();
        }
index 6a45a74ecc1b3fb0f7dad901ed248e8682f85cb4..c7de18150899860430aa77c4b3a1ead82a6f8ab3 100644 (file)
@@ -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;
index 0db87f85e6788a639521f722422fdc731da7a316..03ff3cfad7695321302c168cdeb97aab22e34e98 100644 (file)
@@ -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");
index 1bac0886d0491d3252a81aa742c176f5233d7b40..627cf92d497d3e00701c2381471715c17689e8bc 100644 (file)
Binary files a/testdata/fwd_compress_c00c.tpkg and b/testdata/fwd_compress_c00c.tpkg differ
index 1b8e1bedcbda0c58d4a17a0d197323e28989ddec..34962337e01db8a6a1fb5d5141fc7a931131e639 100644 (file)
Binary files a/testdata/fwd_no_edns.tpkg and b/testdata/fwd_no_edns.tpkg differ
index cad670dd8b1796c159b0772694805433c0ec0876..bef8747bc560fef3c741136041fe64ca4d3c0485 100644 (file)
Binary files a/testdata/fwd_tcp.tpkg and b/testdata/fwd_tcp.tpkg differ
index e061afe5ebbec3b1227a7b4ead79cbf54b4b8a64..1487a253aedc01fe69ebfccbe7207dbd63c573da 100644 (file)
Binary files a/testdata/fwd_tcp_tc.tpkg and b/testdata/fwd_tcp_tc.tpkg differ
index f7762488e7ee0d5a252fc7dfc8be071214728634..df45e9e5b4d96cc74274bd1a3002d38cadfbf790 100644 (file)
Binary files a/testdata/fwd_tcp_tc6.tpkg and b/testdata/fwd_tcp_tc6.tpkg differ
index ca8946971d39f70f2dd2e03134ec70e7198b8a34..860b17a777ab694c3827766060ca922b166de541 100644 (file)
Binary files a/testdata/fwd_three.tpkg and b/testdata/fwd_three.tpkg differ
index 65e6148d84c2ecce2d808de0f20791803e9703ed..983e47b7558797f64f58c9e16f2815fea7d7fdb2 100644 (file)
Binary files a/testdata/fwd_three_service.tpkg and b/testdata/fwd_three_service.tpkg differ
index 3c3b120fc985f59fafe576d2f053e45b54425745..98e3f21d47efa99998955b7c39de07c44be01e2e 100644 (file)
Binary files a/testdata/fwd_ttlexpire.tpkg and b/testdata/fwd_ttlexpire.tpkg differ
index cb5482090add398607bc25854caa1d3594b94716..d3c3986662c5ed3c2a7832d3d96b0a561345c4af 100644 (file)
Binary files a/testdata/fwd_udp.tpkg and b/testdata/fwd_udp.tpkg differ
index a2a8363773c1c4f82f7f3f822321d71ce07b67b0..76d42968cc9e01ba17d55cf989edcf1c3a7844fb 100644 (file)
@@ -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;
index a0b33a9ecf974eb39b4e6c0588916c0e6716dbc8..a63080947d77f6f718f9209d15d40e491dc50110 100644 (file)
@@ -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, 
index f14256f17ff58089521b61ef561dfade8fa14cbd..fb4096375621c96916b0cca899be143d25c7f8ac 100644 (file)
@@ -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).