summaryrefslogtreecommitdiffstats
path: root/daemon
diff options
context:
space:
mode:
authorVitezslav Kriz <vitezslav.kriz@nic.cz>2017-08-14 09:25:42 +0200
committerPetr Špaček <petr.spacek@nic.cz>2018-01-23 15:54:34 +0100
commit6c2db2b56b5cca96513e2da872d8336743172464 (patch)
treed6b5abe482922ded0aadb6f3d55d402eba085e23 /daemon
parentMerge branch 'draft-huston-kskroll-sentinel' into 'master' (diff)
downloadknot-resolver-6c2db2b56b5cca96513e2da872d8336743172464.tar.xz
knot-resolver-6c2db2b56b5cca96513e2da872d8336743172464.zip
keyfile argument distiguish managed and unmanaged mode
Arguments --keyfile, -k for managed mode and --keyfile-ro, -K for unmanaged (readonly) mode. Automatic setting based on the file permission is removed because it was confusing and could easily lead to state where automatic update does not happen because of unexpected file permissions. Check if folder is writeable was moved into Lua code. Default unmanaged keyfile path can be specified at compile time with option KEYFILE_DEFAULT. This default configuration can be disabled in configuration file with trust_anchors.keyfile_default = nil.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/README.rst2
-rw-r--r--daemon/daemon.mk3
-rw-r--r--daemon/engine.c40
-rw-r--r--daemon/engine.h13
-rw-r--r--daemon/lua/config.lua10
-rw-r--r--daemon/lua/trust_anchors.lua.in16
-rw-r--r--daemon/main.c107
7 files changed, 92 insertions, 99 deletions
diff --git a/daemon/README.rst b/daemon/README.rst
index c7979012..830cc22a 100644
--- a/daemon/README.rst
+++ b/daemon/README.rst
@@ -58,6 +58,8 @@ The root anchors bootstrap may fail for various reasons, in this case you need t
You've just enabled DNSSEC!
+.. note:: Bootstrapping and automatic update need write access to keyfile direcory. If you want to manage root anchors manually you should use ``trust_anchors.add_file('root.keys', true)``.
+
CLI interface
=============
diff --git a/daemon/daemon.mk b/daemon/daemon.mk
index a455c2c2..cf28be0f 100644
--- a/daemon/daemon.mk
+++ b/daemon/daemon.mk
@@ -56,6 +56,7 @@ daemon-install: kresd-install bindings-install
ifneq ($(SED),)
$(SED) -e "s/@VERSION@/$(VERSION)/" -e "s/@DATE@/$(date)/" \
-e "s|@MODULEDIR@|$(MODULEDIR)|" \
+ -e "s|@KEYFILE_DEFAULT@|$(KEYFILE_DEFAULT)|" \
doc/kresd.8.in > doc/kresd.8
$(INSTALL) -d -m 0755 $(DESTDIR)$(MANDIR)/man8/
$(INSTALL) -m 0644 doc/kresd.8 $(DESTDIR)$(MANDIR)/man8/
@@ -65,7 +66,7 @@ daemon-clean: kresd-clean
daemon/lua/zonefile.lua
daemon/lua/trust_anchors.lua: daemon/lua/trust_anchors.lua.in
- @$(call quiet,SED,$<) -e "s|@ETCDIR@|$(ETCDIR)|g" $< > $@
+ @$(call quiet,SED,$<) -e "s|@ETCDIR@|$(ETCDIR)|g;s|@KEYFILE_DEFAULT@|$(KEYFILE_DEFAULT)|g" $< > $@
LIBZSCANNER_COMMENTS := \
$(shell pkg-config libzscanner --atleast-version=2.4.2 && echo true || echo false)
diff --git a/daemon/engine.c b/daemon/engine.c
index 8eb78244..b7e69db7 100644
--- a/daemon/engine.c
+++ b/daemon/engine.c
@@ -812,9 +812,8 @@ int engine_ipc(struct engine *engine, const char *expr)
}
}
-static int engine_loadconf(struct engine *engine, const char *config_path)
+int engine_load_sandbox(struct engine *engine)
{
- int ret = 0;
/* Init environment */
static const char sandbox_bytecode[] = {
#include "daemon/lua/sandbox.inc"
@@ -824,22 +823,13 @@ static int engine_loadconf(struct engine *engine, const char *config_path)
lua_pop(engine->L, 1);
return kr_error(ENOEXEC);
}
- /* Load config file */
- if (config_path) {
- if (strcmp(config_path, "-") == 0) {
- return ret; /* No config and no defaults. */
- }
- ret = l_dosandboxfile(engine->L, config_path);
- }
- if (ret == 0) {
- /* Load defaults */
- static const char config_bytecode[] = {
- #include "daemon/lua/config.inc"
- };
- ret = l_dobytecode(engine->L, config_bytecode, sizeof(config_bytecode), "config");
- }
+ return kr_ok();
+}
- /* Evaluate */
+int engine_loadconf(struct engine *engine, const char *config_path)
+{
+ assert(config_path != NULL);
+ int ret = l_dosandboxfile(engine->L, config_path);
if (ret != 0) {
fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
lua_pop(engine->L, 1);
@@ -847,14 +837,22 @@ static int engine_loadconf(struct engine *engine, const char *config_path)
return ret;
}
-int engine_start(struct engine *engine, const char *config_path)
+int engine_load_defaults(struct engine *engine)
{
- /* Load configuration. */
- int ret = engine_loadconf(engine, config_path);
+ /* Load defaults */
+ static const char config_bytecode[] = {
+ #include "daemon/lua/config.inc"
+ };
+ int ret = l_dobytecode(engine->L, config_bytecode, sizeof(config_bytecode), "config");
if (ret != 0) {
- return ret;
+ fprintf(stderr, "%s\n", lua_tostring(engine->L, -1));
+ lua_pop(engine->L, 1);
}
+ return ret;
+}
+int engine_start(struct engine *engine)
+{
/* Clean up stack and restart GC */
lua_settop(engine->L, 0);
lua_gc(engine->L, LUA_GCCOLLECT, 0);
diff --git a/daemon/engine.h b/daemon/engine.h
index 25ee30a1..dea87c11 100644
--- a/daemon/engine.h
+++ b/daemon/engine.h
@@ -83,12 +83,13 @@ int engine_pcall(struct lua_State *L, int argc);
int engine_ipc(struct engine *engine, const char *expr);
-/** Start the lua engine and execute the config.
- *
- * @note Special path "-" means that even default config won't be done
- * (like listening on localhost).
- */
-int engine_start(struct engine *engine, const char *config_path);
+
+int engine_load_sandbox(struct engine *engine);
+int engine_loadconf(struct engine *engine, const char *config_path);
+int engine_load_defaults(struct engine *engine);
+
+/** Start the lua engine and execute the config. */
+int engine_start(struct engine *engine);
void engine_stop(struct engine *engine);
int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref);
int engine_unregister(struct engine *engine, const char *name);
diff --git a/daemon/lua/config.lua b/daemon/lua/config.lua
index cc6e2f2f..36f89e67 100644
--- a/daemon/lua/config.lua
+++ b/daemon/lua/config.lua
@@ -18,3 +18,13 @@ end
if kres.context().root_hints.nsset.root == nil then
_hint_root_file()
end
+
+if not trust_anchors.keysets['\0'] and trust_anchors.keyfile_default then
+ if io.open(trust_anchors.keyfile_default, 'r') then
+ trust_anchors.config(trust_anchors.keyfile_default, true)
+ else
+ panic("cannot open default trust anchor file:'%s'",
+ trust_anchors.keyfile_default
+ )
+ end
+end
diff --git a/daemon/lua/trust_anchors.lua.in b/daemon/lua/trust_anchors.lua.in
index d21a34d2..d2755b80 100644
--- a/daemon/lua/trust_anchors.lua.in
+++ b/daemon/lua/trust_anchors.lua.in
@@ -367,9 +367,16 @@ update = function (keyset, new_keys, is_initial)
end
local add_file = function (path, unmanaged)
- -- Bootstrap if requested and keyfile doesn't exist
+ if not unmanaged then
+ if not io.open(path .. '.lock', 'w') then
+ error("[ ta ] ERROR: write access needed to keyfile dir '"..path.."'")
+ end
+ os.remove(path .. ".lock")
+ end
+ -- Bootstrap if requested and keyfile doesn't exist
if not unmanaged and not io.open(path, 'r') then
+ log("[ ta ] keyfile '%s': doesn't exist, bootstrapping", path);
local tas, msg = bootstrap(trust_anchors.bootstrap_url, trust_anchors.bootstrap_ca)
if not tas then
msg = msg .. '\n'
@@ -394,14 +401,15 @@ local add_file = function (path, unmanaged)
end
-- Parse the file and check its sanity
- local keyset, err = keyset_read(path)
- if not unmanaged then keyset.filename = path end
+ local keyset, err = keyset_read(path)
if not keyset then
panic("[ ta ] ERROR: failed to read anchors from '%s' (%s)", path, err)
end
+ if not unmanaged then keyset.filename = path end
if not keyset[1] then
panic("[ ta ] ERROR: failed to read anchors from '%s'", path)
end
+ if not unmanaged then keyset.filename = path end
local owner = keyset[1].owner
for _, ta in ipairs(keyset) do
if ta.owner ~= owner then
@@ -446,6 +454,8 @@ trust_anchors = {
bootstrap_url = 'https://data.iana.org/root-anchors/root-anchors.xml',
bootstrap_ca = '@ETCDIR@/icann-ca.pem',
+ -- change empty string to nil
+ keyfile_default = ('@KEYFILE_DEFAULT@' ~= '' and '@KEYFILE_DEFAULT@') or nil,
-- Load keys from a file, 5011-managed by default.
-- If managed and the file doesn't exist, try bootstrapping the root into it.
diff --git a/daemon/main.c b/daemon/main.c
index 43290001..0fc44afb 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -39,6 +39,7 @@
#include "daemon/engine.h"
#include "daemon/bindings.h"
#include "daemon/tls.h"
+#include "lib/dnssec/ta.h"
/* We can fork early on Linux 3.9+ and do SO_REUSEPORT for better performance. */
#if defined(UV_VERSION_HEX) && defined(SO_REUSEPORT) && defined(__linux__)
@@ -347,7 +348,8 @@ static void help(int argc, char *argv[])
" -S, --fd=[fd] Listen on given fd (handed out by supervisor).\n"
" -T, --tlsfd=[fd] Listen using TLS on given fd (handed out by supervisor).\n"
" -c, --config=[path] Config file path (relative to [rundir]) (default: config).\n"
- " -k, --keyfile=[path] File containing trust anchors (DS or DNSKEY).\n"
+ " -k, --keyfile=[path] File with root domain trust anchors (DS or DNSKEY), automatically updated.\n"
+ " -K, --keyfile-ro=[path] File with read-only root domain trust anchors, for use with an external updater.\n"
" -m, --moduledir=[path] Override the default module path (" MODULEDIR ").\n"
" -f, --forks=N Start N forks sharing the configuration.\n"
" -q, --quiet Quiet output, no prompt in interactive mode.\n"
@@ -422,79 +424,21 @@ static void free_sd_socket_names(char **socket_names, int count)
}
#endif
-static int init_keyfile(struct engine *engine, const char *keyfile)
+static int init_keyfile(struct engine *engine, const char *keyfile, bool keyfile_unmanaged)
{
- auto_free char *dirname_storage = strdup(keyfile);
- if (!dirname_storage) {
- return kr_error(ENOMEM);
- }
-
- /* Resolve absolute path to the keyfile directory */
- auto_free char *keyfile_dir = malloc(PATH_MAX);
- if (!keyfile_dir) {
- return kr_error(ENOMEM);
- }
- if (realpath(dirname(dirname_storage), keyfile_dir) == NULL) {
- kr_log_error("[ ta ]: keyfile '%s' directory: %s\n", keyfile, strerror(errno));
- return kr_error(ENOTDIR);
- }
-
- auto_free char *basename_storage = strdup(keyfile);
- if (!basename_storage) {
- return kr_error(ENOMEM);
- }
-
- char *_filename = basename(basename_storage);
- int dirlen = strlen(keyfile_dir);
- int namelen = strlen(_filename);
- if (dirlen + 1 + namelen >= PATH_MAX) {
- kr_log_error("[ ta ]: keyfile '%s' PATH_MAX exceeded\n",
- keyfile);
- return kr_error(ENAMETOOLONG);
- }
- keyfile_dir[dirlen++] = '/';
- keyfile_dir[dirlen] = '\0';
-
- auto_free char *keyfile_path = malloc(dirlen + namelen + 1);
- if (!keyfile_path) {
- return kr_error(ENOMEM);
- }
- memcpy(keyfile_path, keyfile_dir, dirlen);
- memcpy(keyfile_path + dirlen, _filename, namelen + 1);
-
- int unmanaged = 0;
-
- /* Note: config has been executed, so access() is OK,
- * as we've dropped privileges already if configured. */
- if (access(keyfile_path, F_OK) != 0) {
- kr_log_info("[ ta ] keyfile '%s': doesn't exist, bootstrapping\n", keyfile_path);
- if (access(keyfile_dir, W_OK) != 0) {
- kr_log_error("[ ta ] keyfile '%s': write access to '%s' needed\n", keyfile_path, keyfile_dir);
- return kr_error(EPERM);
- }
- } else if (access(keyfile_path, R_OK) == 0) {
- if ((access(keyfile_path, W_OK) != 0) || (access(keyfile_dir, W_OK) != 0)) {
- kr_log_error("[ ta ] keyfile '%s': not writeable, starting in unmanaged mode\n", keyfile_path);
- unmanaged = 1;
- }
- } else {
- kr_log_error("[ ta ] keyfile '%s': %s\n", keyfile_path, strerror(errno));
- return kr_error(EPERM);
- }
-
- auto_free char *cmd = afmt("trust_anchors.config('%s',%s)", keyfile_path, unmanaged?"true":"nil");
+ auto_free char *cmd = afmt("trust_anchors.config('%s',%s)",
+ keyfile, keyfile_unmanaged ? "true" : "nil");
if (!cmd) {
+ kr_log_error("[system] not enough memory\n");
return kr_error(ENOMEM);
}
-
int lua_ret = engine_cmd(engine->L, cmd, false);
if (lua_ret != 0) {
if (lua_gettop(engine->L) > 0) {
- kr_log_error("%s", lua_tostring(engine->L, -1));
- lua_settop(engine->L, 0);
+ kr_log_error("%s\n", lua_tostring(engine->L, -1));
} else {
kr_log_error("[ ta ] keyfile '%s': failed to load (%s)\n",
- keyfile_path, lua_strerror(lua_ret));
+ keyfile, lua_strerror(lua_ret));
}
return kr_error(EIO);
}
@@ -515,6 +459,7 @@ int main(int argc, char **argv)
array_t(int) tls_fd_set;
array_init(tls_fd_set);
char *keyfile = NULL;
+ int keyfile_unmanaged = 0;
char *moduledir = MODULEDIR;
const char *config = NULL;
int control_fd = -1;
@@ -528,6 +473,7 @@ int main(int argc, char **argv)
{"tlsfd", required_argument, 0, 'T'},
{"config", required_argument, 0, 'c'},
{"keyfile",required_argument, 0, 'k'},
+ {"keyfile-ro",required_argument, 0, 'K'},
{"forks",required_argument, 0, 'f'},
{"moduledir", required_argument, 0, 'm'},
{"verbose", no_argument, 0, 'v'},
@@ -536,7 +482,7 @@ int main(int argc, char **argv)
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
- while ((c = getopt_long(argc, argv, "a:t:S:T:c:f:m:k:vqVh", opts, &li)) != -1) {
+ while ((c = getopt_long(argc, argv, "a:t:S:T:c:f:m:K:k:vqVh", opts, &li)) != -1) {
switch (c)
{
case 'a':
@@ -563,7 +509,13 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
break;
+ case 'K':
+ keyfile_unmanaged = 1;
case 'k':
+ if (keyfile != NULL) {
+ kr_log_error("[system] error only one of '--keyfile' and '--keyfile-ro' allowed\n");
+ return EXIT_FAILURE;
+ }
keyfile = optarg;
break;
case 'm':
@@ -748,14 +700,18 @@ int main(int argc, char **argv)
worker->loop = loop;
loop->data = worker;
- ret = engine_start(&engine, config);
+ ret = engine_load_sandbox(&engine);
+ if (ret == 0 && config != NULL && strcmp(config, "-") !=0) {
+ ret = engine_loadconf(&engine, config);
+ }
+
if (ret != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
if (keyfile) {
- ret = init_keyfile(&engine, keyfile);
+ ret = init_keyfile(&engine, keyfile, keyfile_unmanaged);
if (ret != 0) {
kr_log_error("[system] failed to initialized keyfile: %s\n", kr_strerror(ret));
ret = EXIT_FAILURE;
@@ -763,6 +719,21 @@ int main(int argc, char **argv)
}
}
+ if (config == NULL || strcmp(config, "-") !=0) {
+ ret = engine_load_defaults(&engine);
+ }
+
+ if (ret != 0) {
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
+ ret = engine_start(&engine);
+ if (ret != 0) {
+ ret = EXIT_FAILURE;
+ goto cleanup;
+ }
+
/* Run the event loop */
ret = run_worker(loop, &engine, &ipc_set, fork_id == 0, control_fd);
if (ret != 0) {