Commit 360f2513 authored by Simon Kelley's avatar Simon Kelley

Tweak DNSSEC timestamp code to create file later, removing need to chown it.

parent 4c960fa9
......@@ -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
......
......@@ -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);
}
}
......
......@@ -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);
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment