"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/dns/dyndb.c" (4 Sep 2020, 11639 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dyndb.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 #if HAVE_DLFCN_H
   13 #include <dlfcn.h>
   14 #elif _WIN32
   15 #include <windows.h>
   16 #endif /* if HAVE_DLFCN_H */
   17 
   18 #include <string.h>
   19 
   20 #include <isc/buffer.h>
   21 #include <isc/mem.h>
   22 #include <isc/mutex.h>
   23 #include <isc/once.h>
   24 #include <isc/region.h>
   25 #include <isc/result.h>
   26 #include <isc/task.h>
   27 #include <isc/types.h>
   28 #include <isc/util.h>
   29 
   30 #include <dns/dyndb.h>
   31 #include <dns/log.h>
   32 #include <dns/types.h>
   33 #include <dns/view.h>
   34 #include <dns/zone.h>
   35 
   36 #define CHECK(op)                            \
   37     do {                                 \
   38         result = (op);               \
   39         if (result != ISC_R_SUCCESS) \
   40             goto cleanup;        \
   41     } while (0)
   42 
   43 typedef struct dyndb_implementation dyndb_implementation_t;
   44 struct dyndb_implementation {
   45     isc_mem_t *mctx;
   46     void *handle;
   47     dns_dyndb_register_t *register_func;
   48     dns_dyndb_destroy_t *destroy_func;
   49     char *name;
   50     void *inst;
   51     LINK(dyndb_implementation_t) link;
   52 };
   53 
   54 /*
   55  * List of dyndb implementations. Locked by dyndb_lock.
   56  *
   57  * These are stored here so they can be cleaned up on shutdown.
   58  * (The order in which they are stored is not important.)
   59  */
   60 static LIST(dyndb_implementation_t) dyndb_implementations;
   61 
   62 /* Locks dyndb_implementations. */
   63 static isc_mutex_t dyndb_lock;
   64 static isc_once_t once = ISC_ONCE_INIT;
   65 
   66 static void
   67 dyndb_initialize(void) {
   68     isc_mutex_init(&dyndb_lock);
   69     INIT_LIST(dyndb_implementations);
   70 }
   71 
   72 static dyndb_implementation_t *
   73 impfind(const char *name) {
   74     dyndb_implementation_t *imp;
   75 
   76     for (imp = ISC_LIST_HEAD(dyndb_implementations); imp != NULL;
   77          imp = ISC_LIST_NEXT(imp, link))
   78     {
   79         if (strcasecmp(name, imp->name) == 0) {
   80             return (imp);
   81         }
   82     }
   83     return (NULL);
   84 }
   85 
   86 #if HAVE_DLFCN_H && HAVE_DLOPEN
   87 static isc_result_t
   88 load_symbol(void *handle, const char *filename, const char *symbol_name,
   89         void **symbolp) {
   90     const char *errmsg;
   91     void *symbol;
   92 
   93     REQUIRE(handle != NULL);
   94     REQUIRE(symbolp != NULL && *symbolp == NULL);
   95 
   96     symbol = dlsym(handle, symbol_name);
   97     if (symbol == NULL) {
   98         errmsg = dlerror();
   99         if (errmsg == NULL) {
  100             errmsg = "returned function pointer is NULL";
  101         }
  102         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  103                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  104                   "failed to lookup symbol %s in "
  105                   "dyndb module '%s': %s",
  106                   symbol_name, filename, errmsg);
  107         return (ISC_R_FAILURE);
  108     }
  109     dlerror();
  110 
  111     *symbolp = symbol;
  112 
  113     return (ISC_R_SUCCESS);
  114 }
  115 
  116 static isc_result_t
  117 load_library(isc_mem_t *mctx, const char *filename, const char *instname,
  118          dyndb_implementation_t **impp) {
  119     isc_result_t result;
  120     void *handle = NULL;
  121     dyndb_implementation_t *imp = NULL;
  122     dns_dyndb_register_t *register_func = NULL;
  123     dns_dyndb_destroy_t *destroy_func = NULL;
  124     dns_dyndb_version_t *version_func = NULL;
  125     int version, flags;
  126 
  127     REQUIRE(impp != NULL && *impp == NULL);
  128 
  129     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB,
  130               ISC_LOG_INFO, "loading DynDB instance '%s' driver '%s'",
  131               instname, filename);
  132 
  133     flags = RTLD_NOW | RTLD_LOCAL;
  134 #if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__
  135     flags |= RTLD_DEEPBIND;
  136 #endif /* if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__ */
  137 
  138     handle = dlopen(filename, flags);
  139     if (handle == NULL) {
  140         CHECK(ISC_R_FAILURE);
  141     }
  142 
  143     /* Clear dlerror */
  144     dlerror();
  145 
  146     CHECK(load_symbol(handle, filename, "dyndb_version",
  147               (void **)&version_func));
  148 
  149     version = version_func(NULL);
  150     if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) ||
  151         version > DNS_DYNDB_VERSION)
  152     {
  153         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  154                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  155                   "driver API version mismatch: %d/%d", version,
  156                   DNS_DYNDB_VERSION);
  157         CHECK(ISC_R_FAILURE);
  158     }
  159 
  160     CHECK(load_symbol(handle, filename, "dyndb_init",
  161               (void **)&register_func));
  162     CHECK(load_symbol(handle, filename, "dyndb_destroy",
  163               (void **)&destroy_func));
  164 
  165     imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t));
  166 
  167     imp->mctx = NULL;
  168     isc_mem_attach(mctx, &imp->mctx);
  169     imp->handle = handle;
  170     imp->register_func = register_func;
  171     imp->destroy_func = destroy_func;
  172     imp->name = isc_mem_strdup(mctx, instname);
  173 
  174     imp->inst = NULL;
  175     INIT_LINK(imp, link);
  176 
  177     *impp = imp;
  178     imp = NULL;
  179 
  180 cleanup:
  181     if (result != ISC_R_SUCCESS) {
  182         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  183                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  184                   "failed to dynamically load instance '%s' "
  185                   "driver '%s': %s (%s)",
  186                   instname, filename, dlerror(),
  187                   isc_result_totext(result));
  188     }
  189     if (imp != NULL) {
  190         isc_mem_putanddetach(&imp->mctx, imp,
  191                      sizeof(dyndb_implementation_t));
  192     }
  193     if (result != ISC_R_SUCCESS && handle != NULL) {
  194         dlclose(handle);
  195     }
  196 
  197     return (result);
  198 }
  199 
  200 static void
  201 unload_library(dyndb_implementation_t **impp) {
  202     dyndb_implementation_t *imp;
  203 
  204     REQUIRE(impp != NULL && *impp != NULL);
  205 
  206     imp = *impp;
  207     *impp = NULL;
  208 
  209     isc_mem_free(imp->mctx, imp->name);
  210     isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
  211 }
  212 #elif _WIN32
  213 static isc_result_t
  214 load_symbol(HMODULE handle, const char *filename, const char *symbol_name,
  215         void **symbolp) {
  216     void *symbol;
  217 
  218     REQUIRE(handle != NULL);
  219     REQUIRE(symbolp != NULL && *symbolp == NULL);
  220 
  221     symbol = GetProcAddress(handle, symbol_name);
  222     if (symbol == NULL) {
  223         int errstatus = GetLastError();
  224         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  225                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  226                   "failed to lookup symbol %s in "
  227                   "dyndb module '%s': %d",
  228                   symbol_name, filename, errstatus);
  229         return (ISC_R_FAILURE);
  230     }
  231 
  232     *symbolp = symbol;
  233 
  234     return (ISC_R_SUCCESS);
  235 }
  236 
  237 static isc_result_t
  238 load_library(isc_mem_t *mctx, const char *filename, const char *instname,
  239          dyndb_implementation_t **impp) {
  240     isc_result_t result;
  241     HMODULE handle;
  242     dyndb_implementation_t *imp = NULL;
  243     dns_dyndb_register_t *register_func = NULL;
  244     dns_dyndb_destroy_t *destroy_func = NULL;
  245     dns_dyndb_version_t *version_func = NULL;
  246     int version;
  247 
  248     REQUIRE(impp != NULL && *impp == NULL);
  249 
  250     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB,
  251               ISC_LOG_INFO, "loading DynDB instance '%s' driver '%s'",
  252               instname, filename);
  253 
  254     handle = LoadLibraryA(filename);
  255     if (handle == NULL) {
  256         CHECK(ISC_R_FAILURE);
  257     }
  258 
  259     CHECK(load_symbol(handle, filename, "dyndb_version",
  260               (void **)&version_func));
  261 
  262     version = version_func(NULL);
  263     if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) ||
  264         version > DNS_DYNDB_VERSION)
  265     {
  266         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  267                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  268                   "driver API version mismatch: %d/%d", version,
  269                   DNS_DYNDB_VERSION);
  270         CHECK(ISC_R_FAILURE);
  271     }
  272 
  273     CHECK(load_symbol(handle, filename, "dyndb_init",
  274               (void **)&register_func));
  275     CHECK(load_symbol(handle, filename, "dyndb_destroy",
  276               (void **)&destroy_func));
  277 
  278     imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t));
  279 
  280     imp->mctx = NULL;
  281     isc_mem_attach(mctx, &imp->mctx);
  282     imp->handle = handle;
  283     imp->register_func = register_func;
  284     imp->destroy_func = destroy_func;
  285     imp->name = isc_mem_strdup(mctx, instname);
  286 
  287     imp->inst = NULL;
  288     INIT_LINK(imp, link);
  289 
  290     *impp = imp;
  291     imp = NULL;
  292 
  293 cleanup:
  294     if (result != ISC_R_SUCCESS) {
  295         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  296                   DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR,
  297                   "failed to dynamically load instance '%s' "
  298                   "driver '%s': %d (%s)",
  299                   instname, filename, GetLastError(),
  300                   isc_result_totext(result));
  301     }
  302     if (imp != NULL) {
  303         isc_mem_putanddetach(&imp->mctx, imp,
  304                      sizeof(dyndb_implementation_t));
  305     }
  306     if (result != ISC_R_SUCCESS && handle != NULL) {
  307         FreeLibrary(handle);
  308     }
  309 
  310     return (result);
  311 }
  312 
  313 static void
  314 unload_library(dyndb_implementation_t **impp) {
  315     dyndb_implementation_t *imp;
  316 
  317     REQUIRE(impp != NULL && *impp != NULL);
  318 
  319     imp = *impp;
  320     *impp = NULL;
  321 
  322     isc_mem_free(imp->mctx, imp->name);
  323     isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t));
  324 }
  325 #else  /* HAVE_DLFCN_H || _WIN32 */
  326 static isc_result_t
  327 load_library(isc_mem_t *mctx, const char *filename, const char *instname,
  328          dyndb_implementation_t **impp) {
  329     UNUSED(mctx);
  330     UNUSED(filename);
  331     UNUSED(instname);
  332     UNUSED(impp);
  333 
  334     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB,
  335               ISC_LOG_ERROR,
  336               "dynamic database support is not implemented");
  337 
  338     return (ISC_R_NOTIMPLEMENTED);
  339 }
  340 
  341 static void
  342 unload_library(dyndb_implementation_t **impp) {
  343     UNUSED(impp);
  344 }
  345 #endif /* HAVE_DLFCN_H */
  346 
  347 isc_result_t
  348 dns_dyndb_load(const char *libname, const char *name, const char *parameters,
  349            const char *file, unsigned long line, isc_mem_t *mctx,
  350            const dns_dyndbctx_t *dctx) {
  351     isc_result_t result;
  352     dyndb_implementation_t *implementation = NULL;
  353 
  354     REQUIRE(DNS_DYNDBCTX_VALID(dctx));
  355     REQUIRE(name != NULL);
  356 
  357     RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
  358 
  359     LOCK(&dyndb_lock);
  360 
  361     /* duplicate instance names are not allowed */
  362     if (impfind(name) != NULL) {
  363         CHECK(ISC_R_EXISTS);
  364     }
  365 
  366     CHECK(load_library(mctx, libname, name, &implementation));
  367     CHECK(implementation->register_func(mctx, name, parameters, file, line,
  368                         dctx, &implementation->inst));
  369 
  370     APPEND(dyndb_implementations, implementation, link);
  371     result = ISC_R_SUCCESS;
  372 
  373 cleanup:
  374     if (result != ISC_R_SUCCESS) {
  375         if (implementation != NULL) {
  376             unload_library(&implementation);
  377         }
  378     }
  379 
  380     UNLOCK(&dyndb_lock);
  381     return (result);
  382 }
  383 
  384 void
  385 dns_dyndb_cleanup(bool exiting) {
  386     dyndb_implementation_t *elem;
  387     dyndb_implementation_t *prev;
  388 
  389     RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS);
  390 
  391     LOCK(&dyndb_lock);
  392     elem = TAIL(dyndb_implementations);
  393     while (elem != NULL) {
  394         prev = PREV(elem, link);
  395         UNLINK(dyndb_implementations, elem, link);
  396         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  397                   DNS_LOGMODULE_DYNDB, ISC_LOG_INFO,
  398                   "unloading DynDB instance '%s'", elem->name);
  399         elem->destroy_func(&elem->inst);
  400         ENSURE(elem->inst == NULL);
  401         unload_library(&elem);
  402         elem = prev;
  403     }
  404     UNLOCK(&dyndb_lock);
  405 
  406     if (exiting) {
  407         isc_mutex_destroy(&dyndb_lock);
  408     }
  409 }
  410 
  411 isc_result_t
  412 dns_dyndb_createctx(isc_mem_t *mctx, const void *hashinit, isc_log_t *lctx,
  413             dns_view_t *view, dns_zonemgr_t *zmgr, isc_task_t *task,
  414             isc_timermgr_t *tmgr, dns_dyndbctx_t **dctxp) {
  415     dns_dyndbctx_t *dctx;
  416 
  417     REQUIRE(dctxp != NULL && *dctxp == NULL);
  418 
  419     dctx = isc_mem_get(mctx, sizeof(*dctx));
  420 
  421     memset(dctx, 0, sizeof(*dctx));
  422     if (view != NULL) {
  423         dns_view_attach(view, &dctx->view);
  424     }
  425     if (zmgr != NULL) {
  426         dns_zonemgr_attach(zmgr, &dctx->zmgr);
  427     }
  428     if (task != NULL) {
  429         isc_task_attach(task, &dctx->task);
  430     }
  431     dctx->timermgr = tmgr;
  432     dctx->hashinit = hashinit;
  433     dctx->lctx = lctx;
  434     dctx->refvar = &isc_bind9;
  435 
  436     isc_mem_attach(mctx, &dctx->mctx);
  437     dctx->magic = DNS_DYNDBCTX_MAGIC;
  438 
  439     *dctxp = dctx;
  440 
  441     return (ISC_R_SUCCESS);
  442 }
  443 
  444 void
  445 dns_dyndb_destroyctx(dns_dyndbctx_t **dctxp) {
  446     dns_dyndbctx_t *dctx;
  447 
  448     REQUIRE(dctxp != NULL && DNS_DYNDBCTX_VALID(*dctxp));
  449 
  450     dctx = *dctxp;
  451     *dctxp = NULL;
  452 
  453     dctx->magic = 0;
  454 
  455     if (dctx->view != NULL) {
  456         dns_view_detach(&dctx->view);
  457     }
  458     if (dctx->zmgr != NULL) {
  459         dns_zonemgr_detach(&dctx->zmgr);
  460     }
  461     if (dctx->task != NULL) {
  462         isc_task_detach(&dctx->task);
  463     }
  464     dctx->timermgr = NULL;
  465     dctx->lctx = NULL;
  466 
  467     isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
  468 }