diff --git a/CHANGES b/CHANGES index 8e4793e527..8b18cf2b26 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +4638. [bug] Reloading or reconfiguring named could fail on + some platforms when LMDB was in use. [RT #45203] + 4637. [func] "nsec3hash -r" option ("rdata order") takes arguments in the same order as they appear in NSEC3 or NSEC3PARAM records, so that NSEC3 parameters can diff --git a/bin/named/server.c b/bin/named/server.c index 97708a514a..e3ac7e56ba 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -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); @@ -6727,12 +6733,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, ISC_TRUE, 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); } @@ -6740,16 +6755,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); } @@ -7936,6 +7941,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. */ @@ -7951,6 +7971,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. * @@ -11317,6 +11351,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; @@ -12659,7 +12780,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); @@ -12681,8 +12801,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; } diff --git a/bin/named/unix/include/named/os.h b/bin/named/unix/include/named/os.h index c04354cc04..26de282f99 100644 --- a/bin/named/unix/include/named/os.h +++ b/bin/named/unix/include/named/os.h @@ -11,6 +11,8 @@ /*! \file */ +#include + #include 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); diff --git a/bin/named/unix/os.c b/bin/named/unix/os.c index 27705c1cf4..24066cb66d 100644 --- a/bin/named/unix/os.c +++ b/bin/named/unix/os.c @@ -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 diff --git a/bin/named/win32/include/named/os.h b/bin/named/win32/include/named/os.h index af71da7458..297b2d2108 100644 --- a/bin/named/win32/include/named/os.h +++ b/bin/named/win32/include/named/os.h @@ -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); diff --git a/bin/named/win32/os.c b/bin/named/win32/os.c index 251cdd2e48..fc9b6f3eff 100644 --- a/bin/named/win32/os.c +++ b/bin/named/win32/os.c @@ -163,6 +163,11 @@ void ns_os_changeuser(void) { } +unsigned int +ns_os_uid(void) { + return (0); +} + void ns_os_adjustnofile(void) { } diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 02c5bdc5b5..ea87d05a86 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -412,6 +412,12 @@
Bug Fixes + + + Reloading or reconfiguring named could + fail on some platforms when LMDB was in use. [RT #45203] + + Due to some incorrectly deleted code, when BIND was @@ -422,7 +428,6 @@ server restart. This has been corrected. [RT #45185] - Semicolons are no longer escaped when printing CAA and diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index e70b3f6f76..a586dc8add 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -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; diff --git a/lib/dns/view.c b/lib/dns/view.c index aa88a65d96..819484525d 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -236,6 +236,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; @@ -2038,7 +2039,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; @@ -2078,27 +2079,21 @@ dns_view_setnewzones(dns_view_t *view, isc_boolean_t allow, void *cfgctx, return (ISC_R_SUCCESS); } - result = nz_legacy(view->new_zone_dir, view->name, "nzf", - buffer, sizeof(buffer)); - if (result != ISC_R_SUCCESS) - goto out; + CHECK(nz_legacy(view->new_zone_dir, 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 = nz_legacy(view->new_zone_dir, view->name, "nzd", - buffer, sizeof(buffer)); - if (result != ISC_R_SUCCESS) - goto out; + CHECK(nz_legacy(view->new_zone_dir, 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); @@ -2107,19 +2102,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); } } @@ -2130,8 +2124,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; @@ -2141,7 +2134,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);