From: Wouter Wijngaards Date: Thu, 22 Nov 2018 15:51:09 +0000 (+0000) Subject: - auth zone zonefiles can be in a chroot, the chroot directory X-Git-Tag: release-1.8.2rc1~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=692caffe2c7417444f4e36437d9578f3f2916b8d;p=thirdparty%2Funbound.git - auth zone zonefiles can be in a chroot, the chroot directory components are removed before use. git-svn-id: file:///svn/unbound/trunk@4972 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/daemon/remote.c b/daemon/remote.c index 3971e4540..84b90a95d 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -2456,7 +2456,7 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg) (void)ssl_printf(ssl, "error no auth-zone %s\n", arg); return; } - if(!auth_zone_read_zonefile(z)) { + if(!auth_zone_read_zonefile(z, worker->env.cfg)) { lock_rw_unlock(&z->lock); (void)ssl_printf(ssl, "error failed to read %s\n", arg); return; diff --git a/doc/Changelog b/doc/Changelog index e056a4a33..50c86f380 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -6,6 +6,8 @@ - ignore debug python module for test in doxygen output. - review fixes for python module. - Fix #4209: Crash in libunbound when called from getdns. + - auth zone zonefiles can be in a chroot, the chroot directory + components are removed before use. 21 November 2018: Wouter - Scrub NS records from NODATA responses as well. diff --git a/services/authzone.c b/services/authzone.c index 1f29c3ae9..a25106bd2 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -1450,11 +1450,13 @@ az_remove_rr_decompress(struct auth_zone* z, uint8_t* pkt, size_t pktlen, * The lineno is set at 1 and then increased by the function. * @param fname: file name. * @param depth: recursion depth for includes + * @param cfg: config for chroot. * returns false on failure, has printed an error message */ static int az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen, - struct sldns_file_parse_state* state, char* fname, int depth) + struct sldns_file_parse_state* state, char* fname, int depth, + struct config_file* cfg) { size_t rr_len, dname_len; int status; @@ -1480,6 +1482,8 @@ az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen, /* skip spaces */ while(*incfile == ' ' || *incfile == '\t') incfile++; + /* adjust for chroot on include file */ + incfile = fname_after_chroot(incfile, cfg, 1); incfile = strdup(incfile); if(!incfile) { log_err("malloc failure"); @@ -1490,7 +1494,7 @@ az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen, inc = fopen(incfile, "r"); if(!inc) { log_err("%s:%d cannot open include " - "file %s: %s", z->zonefile, + "file %s: %s", fname, lineno_orig, incfile, strerror(errno)); free(incfile); @@ -1498,7 +1502,7 @@ az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen, } /* recurse read that file now */ if(!az_parse_file(z, inc, rr, rrbuflen, - state, incfile, depth+1)) { + state, incfile, depth+1, cfg)) { log_err("%s:%d cannot parse include " "file %s", fname, lineno_orig, incfile); @@ -1538,30 +1542,32 @@ az_parse_file(struct auth_zone* z, FILE* in, uint8_t* rr, size_t rrbuflen, } int -auth_zone_read_zonefile(struct auth_zone* z) +auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg) { uint8_t rr[LDNS_RR_BUF_SIZE]; struct sldns_file_parse_state state; + char* zfilename; FILE* in; if(!z || !z->zonefile || z->zonefile[0]==0) return 1; /* no file, or "", nothing to read */ + zfilename = fname_after_chroot(z->zonefile, cfg, 1); if(verbosity >= VERB_ALGO) { char nm[255+1]; dname_str(z->name, nm); - verbose(VERB_ALGO, "read zonefile %s for %s", z->zonefile, nm); + verbose(VERB_ALGO, "read zonefile %s for %s", zfilename, nm); } - in = fopen(z->zonefile, "r"); + in = fopen(zfilename, "r"); if(!in) { char* n = sldns_wire2str_dname(z->name, z->namelen); if(z->zone_is_slave && errno == ENOENT) { /* we fetch the zone contents later, no file yet */ verbose(VERB_ALGO, "no zonefile %s for %s", - z->zonefile, n?n:"error"); + zfilename, n?n:"error"); free(n); return 1; } log_err("cannot open zonefile %s for %s: %s", - z->zonefile, n?n:"error", strerror(errno)); + zfilename, n?n:"error", strerror(errno)); free(n); return 0; } @@ -1579,10 +1585,10 @@ auth_zone_read_zonefile(struct auth_zone* z) state.origin_len = z->namelen; } /* parse the (toplevel) file */ - if(!az_parse_file(z, in, rr, sizeof(rr), &state, z->zonefile, 0)) { + if(!az_parse_file(z, in, rr, sizeof(rr), &state, zfilename, 0, cfg)) { char* n = sldns_wire2str_dname(z->name, z->namelen); log_err("error parsing zonefile %s for %s", - z->zonefile, n?n:"error"); + zfilename, n?n:"error"); free(n); fclose(in); return 0; @@ -1710,13 +1716,13 @@ int auth_zone_write_file(struct auth_zone* z, const char* fname) /** read all auth zones from file (if they have) */ static int -auth_zones_read_zones(struct auth_zones* az) +auth_zones_read_zones(struct auth_zones* az, struct config_file* cfg) { struct auth_zone* z; lock_rw_wrlock(&az->lock); RBTREE_FOR(z, struct auth_zone*, &az->ztree) { lock_rw_wrlock(&z->lock); - if(!auth_zone_read_zonefile(z)) { + if(!auth_zone_read_zonefile(z, cfg)) { lock_rw_unlock(&z->lock); lock_rw_unlock(&az->lock); return 0; @@ -1953,7 +1959,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg, } } az_delete_deleted_zones(az); - if(!auth_zones_read_zones(az)) + if(!auth_zones_read_zones(az, cfg)) return 0; if(setup) { if(!auth_zones_setup_zones(az)) @@ -4775,6 +4781,7 @@ xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) { struct auth_zone* z; char tmpfile[1024]; + char* zfilename; lock_basic_unlock(&xfr->lock); /* get lock again, so it is a readlock and concurrently queries @@ -4797,15 +4804,16 @@ xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) /* no write needed, no zonefile set */ return; } + zfilename = fname_after_chroot(z->zonefile, env->cfg, 1); /* write to tempfile first */ - if((size_t)strlen(z->zonefile) + 16 > sizeof(tmpfile)) { + if((size_t)strlen(zfilename) + 16 > sizeof(tmpfile)) { verbose(VERB_ALGO, "tmpfilename too long, cannot update " - " zonefile %s", z->zonefile); + " zonefile %s", zfilename); lock_rw_unlock(&z->lock); return; } - snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", z->zonefile, + snprintf(tmpfile, sizeof(tmpfile), "%s.tmp%u", zfilename, (unsigned)getpid()); if(xfr->task_transfer->master->http) { /* use the stored chunk list to write them */ @@ -4818,8 +4826,8 @@ xfr_write_after_update(struct auth_xfer* xfr, struct module_env* env) lock_rw_unlock(&z->lock); return; } - if(rename(tmpfile, z->zonefile) < 0) { - log_err("could not rename(%s, %s): %s", tmpfile, z->zonefile, + if(rename(tmpfile, zfilename) < 0) { + log_err("could not rename(%s, %s): %s", tmpfile, zfilename, strerror(errno)); unlink(tmpfile); lock_rw_unlock(&z->lock); diff --git a/services/authzone.h b/services/authzone.h index 8c636eaa4..243f3e4a0 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -599,7 +599,7 @@ int auth_zones_startprobesequence(struct auth_zones* az, struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t dclass); /** read auth zone from zonefile. caller must lock zone. false on failure */ -int auth_zone_read_zonefile(struct auth_zone* z); +int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg); /** find serial number of zone or false if none (no SOA record) */ int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial); diff --git a/testcode/unitauth.c b/testcode/unitauth.c index c162e7ef9..4b3410c9e 100644 --- a/testcode/unitauth.c +++ b/testcode/unitauth.c @@ -42,6 +42,7 @@ #include "testcode/unitmain.h" #include "util/regional.h" #include "util/net_help.h" +#include "util/config_file.h" #include "util/data/msgreply.h" #include "services/cache/dns.h" #include "sldns/str2wire.h" @@ -522,6 +523,7 @@ addzone(struct auth_zones* az, const char* name, char* fname) struct auth_zone* z; size_t nmlen; uint8_t* nm = sldns_str2wire_dname(name, &nmlen); + struct config_file* cfg; if(!nm) fatal_exit("out of memory"); lock_rw_wrlock(&az->lock); z = auth_zone_create(az, nm, nmlen, LDNS_RR_CLASS_IN); @@ -529,12 +531,16 @@ addzone(struct auth_zones* az, const char* name, char* fname) if(!z) fatal_exit("cannot find zone"); auth_zone_set_zonefile(z, fname); z->for_upstream = 1; + cfg = config_create(); + free(cfg->chrootdir); + cfg->chrootdir = NULL; - if(!auth_zone_read_zonefile(z)) { + if(!auth_zone_read_zonefile(z, cfg)) { fatal_exit("parse failure for auth zone %s", name); } lock_rw_unlock(&z->lock); free(nm); + config_delete(cfg); return z; }