Commit 214b5388 authored by Evan Hunt's avatar Evan Hunt
Browse files

[v9_11] prevent reload failure due to LMDB database perms

4638.	[bug]		Reloading or reconfiguring named could fail on
			some platforms when LMDB was in use. [RT #45203]

(cherry picked from commit bf05e66b)
parent dd5375de
4638. [bug] Reloading or reconfiguring named could fail on
some platforms when LMDB was in use. [RT #45203]
4636. [bug] Normalize rpz policy zone names when checking for
existence. [RT #45358]
......
......@@ -484,6 +484,12 @@ nzd_writable(dns_view_t *view);
static isc_result_t
nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
static isc_result_t
nzd_env_reopen(dns_view_t *view);
static void
nzd_env_close(dns_view_t *view);
static isc_result_t
nzd_close(MDB_txn **txnp, isc_boolean_t commit);
......@@ -6714,12 +6720,21 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
return (ISC_R_NOMEMORY);
}
/*
* We attach the parser that was used for config as well
* as the one that will be used for added zones, to avoid
* a shutdown race later.
*/
memset(nzcfg, 0, sizeof(*nzcfg));
cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
isc_mem_attach(view->mctx, &nzcfg->mctx);
cfg_aclconfctx_attach(actx, &nzcfg->actx);
result = dns_view_setnewzones(view, allow, nzcfg,
newzone_cfgctx_destroy, mapsize);
if (result != ISC_R_SUCCESS) {
isc_mem_put(view->mctx, nzcfg, sizeof(*nzcfg));
dns_view_setnewzones(view, ISC_FALSE, NULL, NULL, 0ULL);
return (result);
}
......@@ -6727,16 +6742,6 @@ setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
if (vconfig != NULL)
cfg_obj_attach(vconfig, &nzcfg->vconfig);
/*
* We attach the parser that was used for config as well
* as the one that will be used for added zones, to avoid
* a shutdown race later.
*/
cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
cfg_parser_attach(ns_g_addparser, &nzcfg->add_parser);
isc_mem_attach(view->mctx, &nzcfg->mctx);
cfg_aclconfctx_attach(actx, &nzcfg->actx);
result = count_newzones(view, nzcfg, num_zones);
return (result);
}
......@@ -7864,6 +7869,21 @@ load_configuration(const char *filename, ns_server_t *server,
}
}
/*
* If we're using LMDB, we may have created newzones databases
* as root, making it impossible to reopen them later after
* switching to a new userid. We close them now, and reopen
* after relinquishing privileges them.
*/
if (first_time) {
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
nzd_env_close(view);
}
}
/*
* Relinquish root privileges.
*/
......@@ -7879,6 +7899,20 @@ load_configuration(const char *filename, ns_server_t *server,
"the working directory is not writable");
}
#ifdef HAVE_LMDB
/*
* Reopen NZD databases.
*/
if (first_time) {
for (view = ISC_LIST_HEAD(server->viewlist);
view != NULL;
view = ISC_LIST_NEXT(view, link))
{
nzd_env_reopen(view);
}
}
#endif /* HAVE_LMDB */
/*
* Configure the logging system.
*
......@@ -11209,6 +11243,93 @@ nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
return (ISC_R_SUCCESS);
}
/*
* nzd_env_close() and nzd_env_reopen are a kluge to address the
* problem of an NZD file possibly being created before we drop
* root privileges.
*/
static void
nzd_env_close(dns_view_t *view) {
if (view->new_zone_dbenv != NULL) {
const char *dbpath = NULL;
char lockpath[PATH_MAX];
int ret;
if (mdb_env_get_path(view->new_zone_dbenv, &dbpath) == 0) {
snprintf(lockpath, sizeof(lockpath), "%s-lock",
dbpath);
}
mdb_env_close((MDB_env *) view->new_zone_dbenv);
view->new_zone_dbenv = NULL;
/*
* Database files must be owned by the eventual user, not
* by root.
*/
ret = chown(dbpath, ns_os_uid(), -1);
UNUSED(ret);
/*
* Some platforms need the lockfile not to exist when we
* reopen the environment.
*/
(void) isc_file_remove(lockpath);
}
}
static isc_result_t
nzd_env_reopen(dns_view_t *view) {
isc_result_t result;
MDB_env *env = NULL;
int status;
if (view->new_zone_db == NULL) {
return (ISC_R_SUCCESS);
}
nzd_env_close(view);
status = mdb_env_create(&env);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_create failed: %s",
mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
if (view->new_zone_mapsize != 0ULL) {
status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_set_mapsize failed: %s",
mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
}
status = mdb_env_open(env, view->new_zone_db,
MDB_NOSUBDIR|MDB_CREATE, 0600);
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_open of '%s' failed: %s",
view->new_zone_db, mdb_strerror(status));
CHECK(ISC_R_FAILURE);
}
view->new_zone_dbenv = env;
env = NULL;
cleanup:
if (env != NULL) {
mdb_env_close(env);
}
return (result);
}
static isc_result_t
nzd_close(MDB_txn **txnp, isc_boolean_t commit) {
isc_result_t result = ISC_R_SUCCESS;
......@@ -12491,7 +12612,6 @@ ns_server_showzone(ns_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
static void
newzone_cfgctx_destroy(void **cfgp) {
ns_cfgctx_t *cfg;
isc_mem_t *mctx;
REQUIRE(cfgp != NULL && *cfgp != NULL);
......@@ -12513,8 +12633,7 @@ newzone_cfgctx_destroy(void **cfgp) {
if (cfg->actx != NULL)
cfg_aclconfctx_detach(&cfg->actx);
mctx = cfg->mctx;
isc_mem_putanddetach(&mctx, cfg, sizeof(*cfg));
isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
*cfgp = NULL;
}
......
......@@ -11,6 +11,8 @@
/*! \file */
#include <pwd.h>
#include <isc/types.h>
void
......@@ -34,6 +36,9 @@ ns_os_inituserinfo(const char *username);
void
ns_os_changeuser(void);
uid_t
ns_os_uid(void);
void
ns_os_adjustnofile(void);
......
......@@ -601,6 +601,13 @@ ns_os_changeuser(void) {
#endif
}
uid_t
ns_os_uid(void) {
if (runas_pw == NULL)
return (0);
return (runas_pw->pw_uid);
}
void
ns_os_adjustnofile(void) {
#ifdef HAVE_LINUXTHREADS
......
......@@ -32,6 +32,9 @@ ns_os_inituserinfo(const char *username);
void
ns_os_changeuser(void);
unsigned int
ns_os_uid(void);
void
ns_os_adjustnofile(void);
......
......@@ -163,6 +163,11 @@ void
ns_os_changeuser(void) {
}
unsigned int
ns_os_uid(void) {
return (0);
}
void
ns_os_adjustnofile(void) {
}
......
......@@ -137,6 +137,12 @@
<section xml:id="relnotes_bugs"><info><title>Bug Fixes</title></info>
<itemizedlist>
<listitem>
<para>
Reloading or reconfiguring <command>named</command> could
fail on some platforms when LMDB was in use. [RT #45203]
</para>
</listitem>
<listitem>
<para>
Due to some incorrectly deleted code, when BIND was
......@@ -147,7 +153,6 @@
server restart. This has been corrected. [RT #45185]
</para>
</listitem>
<listitem>
<para>
Semicolons are no longer escaped when printing CAA and
......
......@@ -212,6 +212,7 @@ struct dns_view {
char * new_zone_file;
char * new_zone_db;
void * new_zone_dbenv;
isc_uint64_t new_zone_mapsize;
void * new_zone_config;
void (*cfg_destroy)(void **);
isc_mutex_t new_zone_lock;
......
......@@ -237,6 +237,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->new_zone_file = NULL;
view->new_zone_db = NULL;
view->new_zone_dbenv = NULL;
view->new_zone_mapsize = 0ULL;
view->new_zone_config = NULL;
view->cfg_destroy = NULL;
view->fail_ttl = 0;
......@@ -1988,7 +1989,7 @@ isc_result_t
dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
void (*cfg_destroy)(void **), isc_uint64_t mapsize)
{
isc_result_t result;
isc_result_t result = ISC_R_SUCCESS;
char buffer[1024];
#ifdef HAVE_LMDB
MDB_env *env = NULL;
......@@ -2027,27 +2028,21 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
if (!allow)
return (ISC_R_SUCCESS);
result = isc_file_sanitize(NULL, view->name, "nzf",
buffer, sizeof(buffer));
if (result != ISC_R_SUCCESS)
goto out;
CHECK(isc_file_sanitize(NULL, view->name, "nzf",
buffer, sizeof(buffer)));
view->new_zone_file = isc_mem_strdup(view->mctx, buffer);
if (view->new_zone_file == NULL) {
result = ISC_R_NOMEMORY;
goto out;
CHECK(ISC_R_NOMEMORY);
}
#ifdef HAVE_LMDB
result = isc_file_sanitize(NULL, view->name, "nzd",
buffer, sizeof(buffer));
if (result != ISC_R_SUCCESS)
goto out;
CHECK(isc_file_sanitize(NULL, view->name, "nzd",
buffer, sizeof(buffer)));
view->new_zone_db = isc_mem_strdup(view->mctx, buffer);
if (view->new_zone_db == NULL) {
result = ISC_R_NOMEMORY;
goto out;
CHECK(ISC_R_NOMEMORY);
}
status = mdb_env_create(&env);
......@@ -2056,19 +2051,18 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_create failed: %s",
mdb_strerror(status));
result = ISC_R_FAILURE;
goto out;
CHECK(ISC_R_FAILURE);
}
if (mapsize != 0ULL) {
status = mdb_env_set_mapsize(env, mapsize);
view->new_zone_mapsize = mapsize;
if (status != 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_set_mapsize failed: %s",
mdb_strerror(status));
result = ISC_R_FAILURE;
goto out;
CHECK(ISC_R_FAILURE);
}
}
......@@ -2079,8 +2073,7 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
"mdb_env_open of '%s' failed: %s",
view->new_zone_db, mdb_strerror(status));
result = ISC_R_FAILURE;
goto out;
CHECK(ISC_R_FAILURE);
}
view->new_zone_dbenv = env;
......@@ -2090,7 +2083,7 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx,
view->new_zone_config = cfgctx;
view->cfg_destroy = cfg_destroy;
out:
cleanup:
if (result != ISC_R_SUCCESS) {
if (view->new_zone_file != NULL) {
isc_mem_free(view->mctx, view->new_zone_file);
......
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