--- /dev/null
+From 360f2513ab12a9bf1e262d388dd2ea8a566590a3 Mon Sep 17 00:00:00 2001
+From: Simon Kelley <simon@thekelleys.org.uk>
+Date: Sat, 7 Mar 2015 18:28:06 +0000
+Subject: [PATCH 57/57] Tweak DNSSEC timestamp code to create file later,
+ removing need to chown it.
+
+---
+ man/dnsmasq.8 | 3 ++-
+ src/dnsmasq.c | 35 ++++++++++++++++++++++-------------
+ src/dnsmasq.h | 3 ++-
+ src/dnssec.c | 18 ++++++++++--------
+ 4 files changed, 36 insertions(+), 23 deletions(-)
+
+diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
+index 097e7d75145c..2db780d90987 100644
+--- a/man/dnsmasq.8
++++ b/man/dnsmasq.8
+@@ -678,7 +678,8 @@ which have not been throughly checked.
+ Enables an alternative way of checking the validity of the system time for DNSSEC (see --dnssec-no-timecheck). In this case, the
+ system time is considered to be valid once it becomes later than the timestamp on the specified file. The file is created and
+ its timestamp set automatically by dnsmasq. The file must be stored on a persistent filesystem, so that it and its mtime are carried
+-over system restarts.
++over system restarts. The timestamp file is created after dnsmasq has dropped root, so it must be in a location writable by the
++unprivileged user that dnsmasq runs as.
+ .TP
+ .B --proxy-dnssec
+ Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients and cache it. This is an
+diff --git a/src/dnsmasq.c b/src/dnsmasq.c
+index 9e05c0e31569..f3e5bcffec4f 100644
+--- a/src/dnsmasq.c
++++ b/src/dnsmasq.c
+@@ -58,9 +58,6 @@ int main (int argc, char **argv)
+ struct dhcp_context *context;
+ struct dhcp_relay *relay;
+ #endif
+-#ifdef HAVE_DNSSEC
+- int badtime;
+-#endif
+
+ #ifdef LOCALEDIR
+ setlocale(LC_ALL, "");
+@@ -156,10 +153,10 @@ int main (int argc, char **argv)
+ {
+ #ifdef HAVE_DNSSEC
+ if (!daemon->ds)
+- die(_("No trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
++ die(_("no trust anchors provided for DNSSEC"), NULL, EC_BADCONF);
+
+ if (daemon->cachesize < CACHESIZ)
+- die(_("Cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
++ die(_("cannot reduce cache size from default when DNSSEC enabled"), NULL, EC_BADCONF);
+ #else
+ die(_("DNSSEC not available: set HAVE_DNSSEC in src/config.h"), NULL, EC_BADCONF);
+ #endif
+@@ -172,10 +169,10 @@ int main (int argc, char **argv)
+
+ #ifdef HAVE_CONNTRACK
+ if (option_bool(OPT_CONNTRACK) && (daemon->query_port != 0 || daemon->osport))
+- die (_("Cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
++ die (_("cannot use --conntrack AND --query-port"), NULL, EC_BADCONF);
+ #else
+ if (option_bool(OPT_CONNTRACK))
+- die(_("Conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
++ die(_("conntrack support not available: set HAVE_CONNTRACK in src/config.h"), NULL, EC_BADCONF);
+ #endif
+
+ #ifdef HAVE_SOLARIS_NETWORK
+@@ -195,7 +192,7 @@ int main (int argc, char **argv)
+
+ #ifndef HAVE_LOOP
+ if (option_bool(OPT_LOOP_DETECT))
+- die(_("Loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
++ die(_("loop detection not available: set HAVE_LOOP in src/config.h"), NULL, EC_BADCONF);
+ #endif
+
+ now = dnsmasq_time();
+@@ -373,10 +370,6 @@ int main (int argc, char **argv)
+ if (baduser)
+ die(_("unknown user or group: %s"), baduser, EC_BADCONF);
+
+-#ifdef HAVE_DNSSEC
+- badtime = setup_timestamp(ent_pw);
+-#endif
+-
+ /* implement group defaults, "dip" if available, or group associated with uid */
+ if (!daemon->group_set && !gp)
+ {
+@@ -693,10 +686,23 @@ int main (int argc, char **argv)
+ #ifdef HAVE_DNSSEC
+ if (option_bool(OPT_DNSSEC_VALID))
+ {
++ int rc;
++
++ /* Delay creating the timestamp file until here, after we've changed user, so that
++ it has the correct owner to allow updating the mtime later.
++ This means we have to report fatal errors via the pipe. */
++ if ((rc = setup_timestamp()) == -1)
++ {
++ send_event(err_pipe[1], EVENT_TIME_ERR, errno, daemon->timestamp_file);
++ _exit(0);
++ }
++
+ my_syslog(LOG_INFO, _("DNSSEC validation enabled"));
++
+ if (option_bool(OPT_DNSSEC_TIME))
+ my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until first cache reload"));
+- if (badtime)
++
++ if (rc == 1)
+ my_syslog(LOG_INFO, _("DNSSEC signature timestamps not checked until system time valid"));
+ }
+ #endif
+@@ -1170,6 +1176,9 @@ static void fatal_event(struct event_desc *ev, char *msg)
+
+ case EVENT_TFTP_ERR:
+ die(_("TFTP directory %s inaccessible: %s"), msg, EC_FILE);
++
++ case EVENT_TIME_ERR:
++ die(_("cannot create timestamp file %s: %s" ), msg, EC_BADCONF);
+ }
+ }
+
+diff --git a/src/dnsmasq.h b/src/dnsmasq.h
+index a451cb4dd03c..fc7259881358 100644
+--- a/src/dnsmasq.h
++++ b/src/dnsmasq.h
+@@ -167,6 +167,7 @@ struct event_desc {
+ #define EVENT_INIT 21
+ #define EVENT_NEWADDR 22
+ #define EVENT_NEWROUTE 23
++#define EVENT_TIME_ERR 24
+
+ /* Exit codes. */
+ #define EC_GOOD 0
+@@ -1152,7 +1153,7 @@ int dnssec_chase_cname(time_t now, struct dns_header *header, size_t plen, char
+ int dnskey_keytag(int alg, int flags, unsigned char *rdata, int rdlen);
+ size_t filter_rrsigs(struct dns_header *header, size_t plen);
+ unsigned char* hash_questions(struct dns_header *header, size_t plen, char *name);
+-int setup_timestamp(struct passwd *ent_pw);
++int setup_timestamp(void);
+
+ /* util.c */
+ void rand_init(void);
+diff --git a/src/dnssec.c b/src/dnssec.c
+index c60eacf73c6b..ad0d6f072ba2 100644
+--- a/src/dnssec.c
++++ b/src/dnssec.c
+@@ -397,18 +397,21 @@ static int serial_compare_32(unsigned long s1, unsigned long s2)
+
+ /* Called at startup. If the timestamp file is configured and exists, put its mtime on
+ timestamp_time. If it doesn't exist, create it, and set the mtime to 1-1-2015.
+- Change the ownership to the user we'll be running as, so that we can update the mtime.
++ return -1 -> Cannot create file.
++ 0 -> not using timestamp, or timestamp exists and is in past.
++ 1 -> timestamp exists and is in future.
+ */
++
+ static time_t timestamp_time;
+ static int back_to_the_future;
+
+-int setup_timestamp(struct passwd *ent_pw)
++int setup_timestamp(void)
+ {
+ struct stat statbuf;
+
+ back_to_the_future = 0;
+
+- if (!option_bool(OPT_DNSSEC_VALID) || !daemon->timestamp_file)
++ if (!daemon->timestamp_file)
+ return 0;
+
+ if (stat(daemon->timestamp_file, &statbuf) != -1)
+@@ -428,7 +431,8 @@ int setup_timestamp(struct passwd *ent_pw)
+
+ if (errno == ENOENT)
+ {
+- int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK, 0666);
++ /* NB. for explanation of O_EXCL flag, see comment on pidfile in dnsmasq.c */
++ int fd = open(daemon->timestamp_file, O_WRONLY | O_CREAT | O_NONBLOCK | O_EXCL, 0666);
+ if (fd != -1)
+ {
+ struct utimbuf timbuf;
+@@ -436,14 +440,12 @@ int setup_timestamp(struct passwd *ent_pw)
+ close(fd);
+
+ timestamp_time = timbuf.actime = timbuf.modtime = 1420070400; /* 1-1-2015 */
+- if (utime(daemon->timestamp_file, &timbuf) == 0 &&
+- (!ent_pw || getuid() != 0 || chown(daemon->timestamp_file, ent_pw->pw_uid, -1) == 0))
++ if (utime(daemon->timestamp_file, &timbuf) == 0)
+ goto check_and_exit;
+ }
+ }
+
+- die(_("Cannot create timestamp file %s: %s" ), daemon->timestamp_file, EC_BADCONF);
+- return 0;
++ return -1;
+ }
+
+ /* Check whether today/now is between date_start and date_end */
+--
+2.1.0
+