"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/bin/named/unix/dlz_dlopen_driver.c" (4 Sep 2020, 14992 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 "dlz_dlopen_driver.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 #include <inttypes.h>
   13 #include <stdbool.h>
   14 #include <stdio.h>
   15 #include <stdlib.h>
   16 #include <string.h>
   17 #if HAVE_DLFCN_H
   18 #include <dlfcn.h>
   19 #endif /* if HAVE_DLFCN_H */
   20 
   21 #include <isc/mem.h>
   22 #include <isc/print.h>
   23 #include <isc/result.h>
   24 #include <isc/util.h>
   25 
   26 #include <dns/dlz_dlopen.h>
   27 #include <dns/log.h>
   28 #include <dns/result.h>
   29 
   30 #include <dlz/dlz_dlopen_driver.h>
   31 #include <named/globals.h>
   32 
   33 #ifdef ISC_DLZ_DLOPEN
   34 static dns_sdlzimplementation_t *dlz_dlopen = NULL;
   35 
   36 typedef struct dlopen_data {
   37     isc_mem_t *mctx;
   38     char *dl_path;
   39     char *dlzname;
   40     void *dl_handle;
   41     void *dbdata;
   42     unsigned int flags;
   43     isc_mutex_t lock;
   44     int version;
   45     bool in_configure;
   46 
   47     dlz_dlopen_version_t *dlz_version;
   48     dlz_dlopen_create_t *dlz_create;
   49     dlz_dlopen_findzonedb_t *dlz_findzonedb;
   50     dlz_dlopen_lookup_t *dlz_lookup;
   51     dlz_dlopen_authority_t *dlz_authority;
   52     dlz_dlopen_allnodes_t *dlz_allnodes;
   53     dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr;
   54     dlz_dlopen_newversion_t *dlz_newversion;
   55     dlz_dlopen_closeversion_t *dlz_closeversion;
   56     dlz_dlopen_configure_t *dlz_configure;
   57     dlz_dlopen_ssumatch_t *dlz_ssumatch;
   58     dlz_dlopen_addrdataset_t *dlz_addrdataset;
   59     dlz_dlopen_subrdataset_t *dlz_subrdataset;
   60     dlz_dlopen_delrdataset_t *dlz_delrdataset;
   61     dlz_dlopen_destroy_t *dlz_destroy;
   62 } dlopen_data_t;
   63 
   64 /* Modules can choose whether they are lock-safe or not. */
   65 #define MAYBE_LOCK(cd)                                            \
   66     do {                                                      \
   67         if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
   68             !cd->in_configure)                            \
   69             LOCK(&cd->lock);                          \
   70     } while (0)
   71 
   72 #define MAYBE_UNLOCK(cd)                                          \
   73     do {                                                      \
   74         if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
   75             !cd->in_configure)                            \
   76             UNLOCK(&cd->lock);                        \
   77     } while (0)
   78 
   79 /*
   80  * Log a message at the given level.
   81  */
   82 static void
   83 dlopen_log(int level, const char *fmt, ...) {
   84     va_list ap;
   85     va_start(ap, fmt);
   86     isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ,
   87                ISC_LOG_DEBUG(level), fmt, ap);
   88     va_end(ap);
   89 }
   90 
   91 /*
   92  * SDLZ methods
   93  */
   94 
   95 static isc_result_t
   96 dlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
   97             dns_sdlzallnodes_t *allnodes) {
   98     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
   99     isc_result_t result;
  100 
  101     UNUSED(driverarg);
  102 
  103     if (cd->dlz_allnodes == NULL) {
  104         return (ISC_R_NOPERM);
  105     }
  106 
  107     MAYBE_LOCK(cd);
  108     result = cd->dlz_allnodes(zone, cd->dbdata, allnodes);
  109     MAYBE_UNLOCK(cd);
  110     return (result);
  111 }
  112 
  113 static isc_result_t
  114 dlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
  115             const char *client) {
  116     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  117     isc_result_t result;
  118 
  119     UNUSED(driverarg);
  120 
  121     if (cd->dlz_allowzonexfr == NULL) {
  122         return (ISC_R_NOPERM);
  123     }
  124 
  125     MAYBE_LOCK(cd);
  126     result = cd->dlz_allowzonexfr(cd->dbdata, name, client);
  127     MAYBE_UNLOCK(cd);
  128     return (result);
  129 }
  130 
  131 static isc_result_t
  132 dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata,
  133              dns_sdlzlookup_t *lookup) {
  134     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  135     isc_result_t result;
  136 
  137     UNUSED(driverarg);
  138 
  139     if (cd->dlz_authority == NULL) {
  140         return (ISC_R_NOTIMPLEMENTED);
  141     }
  142 
  143     MAYBE_LOCK(cd);
  144     result = cd->dlz_authority(zone, cd->dbdata, lookup);
  145     MAYBE_UNLOCK(cd);
  146     return (result);
  147 }
  148 
  149 static isc_result_t
  150 dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name,
  151               dns_clientinfomethods_t *methods,
  152               dns_clientinfo_t *clientinfo) {
  153     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  154     isc_result_t result;
  155 
  156     UNUSED(driverarg);
  157 
  158     MAYBE_LOCK(cd);
  159     result = cd->dlz_findzonedb(cd->dbdata, name, methods, clientinfo);
  160     MAYBE_UNLOCK(cd);
  161     return (result);
  162 }
  163 
  164 static isc_result_t
  165 dlopen_dlz_lookup(const char *zone, const char *name, void *driverarg,
  166           void *dbdata, dns_sdlzlookup_t *lookup,
  167           dns_clientinfomethods_t *methods,
  168           dns_clientinfo_t *clientinfo) {
  169     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  170     isc_result_t result;
  171 
  172     UNUSED(driverarg);
  173 
  174     MAYBE_LOCK(cd);
  175     result = cd->dlz_lookup(zone, name, cd->dbdata, lookup, methods,
  176                 clientinfo);
  177     MAYBE_UNLOCK(cd);
  178     return (result);
  179 }
  180 
  181 /*
  182  * Load a symbol from the library
  183  */
  184 static void *
  185 dl_load_symbol(dlopen_data_t *cd, const char *symbol, bool mandatory) {
  186     void *ptr = dlsym(cd->dl_handle, symbol);
  187     if (ptr == NULL && mandatory) {
  188         dlopen_log(ISC_LOG_ERROR,
  189                "dlz_dlopen: library '%s' is missing "
  190                "required symbol '%s'",
  191                cd->dl_path, symbol);
  192     }
  193     return (ptr);
  194 }
  195 
  196 /*
  197  * Called at startup for each dlopen zone in named.conf
  198  */
  199 static isc_result_t
  200 dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
  201           void *driverarg, void **dbdata) {
  202     dlopen_data_t *cd;
  203     isc_mem_t *mctx = NULL;
  204     isc_result_t result = ISC_R_FAILURE;
  205     int dlopen_flags = 0;
  206 
  207     UNUSED(driverarg);
  208 
  209     if (argc < 2) {
  210         dlopen_log(ISC_LOG_ERROR,
  211                "dlz_dlopen driver for '%s' needs a path to "
  212                "the shared library",
  213                dlzname);
  214         return (ISC_R_FAILURE);
  215     }
  216 
  217     isc_mem_create(&mctx);
  218 
  219     cd = isc_mem_get(mctx, sizeof(*cd));
  220     memset(cd, 0, sizeof(*cd));
  221 
  222     cd->mctx = mctx;
  223 
  224     cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]);
  225 
  226     cd->dlzname = isc_mem_strdup(cd->mctx, dlzname);
  227 
  228     /* Initialize the lock */
  229     isc_mutex_init(&cd->lock);
  230 
  231     /* Open the library */
  232     dlopen_flags = RTLD_NOW | RTLD_GLOBAL;
  233 
  234 #if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__
  235     /*
  236      * If RTLD_DEEPBIND is available then use it. This can avoid
  237      * issues with a module using a different version of a system
  238      * library than one that bind9 uses. For example, bind9 may link
  239      * to MIT kerberos, but the module may use Heimdal. If we don't
  240      * use RTLD_DEEPBIND then we could end up with Heimdal functions
  241      * calling MIT functions, which leads to bizarre results (usually
  242      * a segfault).
  243      */
  244     dlopen_flags |= RTLD_DEEPBIND;
  245 #endif /* if defined(RTLD_DEEPBIND) && !__SANITIZE_ADDRESS__ */
  246 
  247     cd->dl_handle = dlopen(cd->dl_path, dlopen_flags);
  248     if (cd->dl_handle == NULL) {
  249         dlopen_log(ISC_LOG_ERROR,
  250                "dlz_dlopen failed to open library '%s' - %s",
  251                cd->dl_path, dlerror());
  252         result = ISC_R_FAILURE;
  253         goto failed;
  254     }
  255 
  256     /* Find the symbols */
  257     cd->dlz_version =
  258         (dlz_dlopen_version_t *)dl_load_symbol(cd, "dlz_version", true);
  259     cd->dlz_create = (dlz_dlopen_create_t *)dl_load_symbol(cd, "dlz_create",
  260                                    true);
  261     cd->dlz_lookup = (dlz_dlopen_lookup_t *)dl_load_symbol(cd, "dlz_lookup",
  262                                    true);
  263     cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)dl_load_symbol(
  264         cd, "dlz_findzonedb", true);
  265 
  266     if (cd->dlz_create == NULL || cd->dlz_version == NULL ||
  267         cd->dlz_lookup == NULL || cd->dlz_findzonedb == NULL)
  268     {
  269         /* We're missing a required symbol */
  270         result = ISC_R_FAILURE;
  271         goto failed;
  272     }
  273 
  274     cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)dl_load_symbol(
  275         cd, "dlz_allowzonexfr", false);
  276     cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)dl_load_symbol(
  277         cd, "dlz_allnodes", (cd->dlz_allowzonexfr != NULL));
  278     cd->dlz_authority = (dlz_dlopen_authority_t *)dl_load_symbol(
  279         cd, "dlz_authority", false);
  280     cd->dlz_newversion = (dlz_dlopen_newversion_t *)dl_load_symbol(
  281         cd, "dlz_newversion", false);
  282     cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)dl_load_symbol(
  283         cd, "dlz_closeversion", (cd->dlz_newversion != NULL));
  284     cd->dlz_configure = (dlz_dlopen_configure_t *)dl_load_symbol(
  285         cd, "dlz_configure", false);
  286     cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)dl_load_symbol(
  287         cd, "dlz_ssumatch", false);
  288     cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)dl_load_symbol(
  289         cd, "dlz_addrdataset", false);
  290     cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)dl_load_symbol(
  291         cd, "dlz_subrdataset", false);
  292     cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)dl_load_symbol(
  293         cd, "dlz_delrdataset", false);
  294     cd->dlz_destroy = (dlz_dlopen_destroy_t *)dl_load_symbol(
  295         cd, "dlz_destroy", false);
  296 
  297     /* Check the version of the API is the same */
  298     cd->version = cd->dlz_version(&cd->flags);
  299     if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) ||
  300         cd->version > DLZ_DLOPEN_VERSION)
  301     {
  302         dlopen_log(ISC_LOG_ERROR,
  303                "dlz_dlopen: %s: incorrect driver API version %d, "
  304                "requires %d",
  305                cd->dl_path, cd->version, DLZ_DLOPEN_VERSION);
  306         result = ISC_R_FAILURE;
  307         goto failed;
  308     }
  309 
  310     /*
  311      * Call the library's create function. Note that this is an
  312      * extended version of dlz create, with the addition of
  313      * named function pointers for helper functions that the
  314      * driver will need. This avoids the need for the backend to
  315      * link the BIND9 libraries
  316      */
  317     MAYBE_LOCK(cd);
  318     result = cd->dlz_create(dlzname, argc - 1, argv + 1, &cd->dbdata, "log",
  319                 dlopen_log, "putrr", dns_sdlz_putrr,
  320                 "putnamedrr", dns_sdlz_putnamedrr,
  321                 "writeable_zone", dns_dlz_writeablezone, NULL);
  322     MAYBE_UNLOCK(cd);
  323     if (result != ISC_R_SUCCESS) {
  324         goto failed;
  325     }
  326 
  327     *dbdata = cd;
  328 
  329     return (ISC_R_SUCCESS);
  330 
  331 failed:
  332     dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname);
  333     if (cd->dl_path != NULL) {
  334         isc_mem_free(mctx, cd->dl_path);
  335     }
  336     if (cd->dlzname != NULL) {
  337         isc_mem_free(mctx, cd->dlzname);
  338     }
  339     if (dlopen_flags != 0) {
  340         isc_mutex_destroy(&cd->lock);
  341     }
  342 #ifdef HAVE_DLCLOSE
  343     if (cd->dl_handle) {
  344         dlclose(cd->dl_handle);
  345     }
  346 #endif /* ifdef HAVE_DLCLOSE */
  347     isc_mem_put(mctx, cd, sizeof(*cd));
  348     isc_mem_destroy(&mctx);
  349     return (result);
  350 }
  351 
  352 /*
  353  * Called when bind is shutting down
  354  */
  355 static void
  356 dlopen_dlz_destroy(void *driverarg, void *dbdata) {
  357     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  358     isc_mem_t *mctx;
  359 
  360     UNUSED(driverarg);
  361 
  362     if (cd->dlz_destroy) {
  363         MAYBE_LOCK(cd);
  364         cd->dlz_destroy(cd->dbdata);
  365         MAYBE_UNLOCK(cd);
  366     }
  367 
  368     if (cd->dl_path) {
  369         isc_mem_free(cd->mctx, cd->dl_path);
  370     }
  371     if (cd->dlzname) {
  372         isc_mem_free(cd->mctx, cd->dlzname);
  373     }
  374 
  375 #ifdef HAVE_DLCLOSE
  376     if (cd->dl_handle) {
  377         dlclose(cd->dl_handle);
  378     }
  379 #endif /* ifdef HAVE_DLCLOSE */
  380 
  381     isc_mutex_destroy(&cd->lock);
  382 
  383     mctx = cd->mctx;
  384     isc_mem_put(mctx, cd, sizeof(*cd));
  385     isc_mem_destroy(&mctx);
  386 }
  387 
  388 /*
  389  * Called to start a transaction
  390  */
  391 static isc_result_t
  392 dlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata,
  393               void **versionp) {
  394     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  395     isc_result_t result;
  396 
  397     UNUSED(driverarg);
  398 
  399     if (cd->dlz_newversion == NULL) {
  400         return (ISC_R_NOTIMPLEMENTED);
  401     }
  402 
  403     MAYBE_LOCK(cd);
  404     result = cd->dlz_newversion(zone, cd->dbdata, versionp);
  405     MAYBE_UNLOCK(cd);
  406     return (result);
  407 }
  408 
  409 /*
  410  * Called to end a transaction
  411  */
  412 static void
  413 dlopen_dlz_closeversion(const char *zone, bool commit, void *driverarg,
  414             void *dbdata, void **versionp) {
  415     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  416 
  417     UNUSED(driverarg);
  418 
  419     if (cd->dlz_newversion == NULL) {
  420         *versionp = NULL;
  421         return;
  422     }
  423 
  424     MAYBE_LOCK(cd);
  425     cd->dlz_closeversion(zone, commit, cd->dbdata, versionp);
  426     MAYBE_UNLOCK(cd);
  427 }
  428 
  429 /*
  430  * Called on startup to configure any writeable zones
  431  */
  432 static isc_result_t
  433 dlopen_dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *driverarg,
  434              void *dbdata) {
  435     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  436     isc_result_t result;
  437 
  438     UNUSED(driverarg);
  439 
  440     if (cd->dlz_configure == NULL) {
  441         return (ISC_R_SUCCESS);
  442     }
  443 
  444     MAYBE_LOCK(cd);
  445     cd->in_configure = true;
  446     result = cd->dlz_configure(view, dlzdb, cd->dbdata);
  447     cd->in_configure = false;
  448     MAYBE_UNLOCK(cd);
  449 
  450     return (result);
  451 }
  452 
  453 /*
  454  * Check for authority to change a name.
  455  */
  456 static bool
  457 dlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
  458             const char *type, const char *key, uint32_t keydatalen,
  459             unsigned char *keydata, void *driverarg, void *dbdata) {
  460     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  461     bool ret;
  462 
  463     UNUSED(driverarg);
  464 
  465     if (cd->dlz_ssumatch == NULL) {
  466         return (false);
  467     }
  468 
  469     MAYBE_LOCK(cd);
  470     ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen,
  471                    keydata, cd->dbdata);
  472     MAYBE_UNLOCK(cd);
  473 
  474     return (ret);
  475 }
  476 
  477 /*
  478  * Add an rdataset.
  479  */
  480 static isc_result_t
  481 dlopen_dlz_addrdataset(const char *name, const char *rdatastr, void *driverarg,
  482                void *dbdata, void *version) {
  483     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  484     isc_result_t result;
  485 
  486     UNUSED(driverarg);
  487 
  488     if (cd->dlz_addrdataset == NULL) {
  489         return (ISC_R_NOTIMPLEMENTED);
  490     }
  491 
  492     MAYBE_LOCK(cd);
  493     result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version);
  494     MAYBE_UNLOCK(cd);
  495 
  496     return (result);
  497 }
  498 
  499 /*
  500  * Subtract an rdataset.
  501  */
  502 static isc_result_t
  503 dlopen_dlz_subrdataset(const char *name, const char *rdatastr, void *driverarg,
  504                void *dbdata, void *version) {
  505     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  506     isc_result_t result;
  507 
  508     UNUSED(driverarg);
  509 
  510     if (cd->dlz_subrdataset == NULL) {
  511         return (ISC_R_NOTIMPLEMENTED);
  512     }
  513 
  514     MAYBE_LOCK(cd);
  515     result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version);
  516     MAYBE_UNLOCK(cd);
  517 
  518     return (result);
  519 }
  520 
  521 /*
  522  * Delete a rdataset.
  523  */
  524 static isc_result_t
  525 dlopen_dlz_delrdataset(const char *name, const char *type, void *driverarg,
  526                void *dbdata, void *version) {
  527     dlopen_data_t *cd = (dlopen_data_t *)dbdata;
  528     isc_result_t result;
  529 
  530     UNUSED(driverarg);
  531 
  532     if (cd->dlz_delrdataset == NULL) {
  533         return (ISC_R_NOTIMPLEMENTED);
  534     }
  535 
  536     MAYBE_LOCK(cd);
  537     result = cd->dlz_delrdataset(name, type, cd->dbdata, version);
  538     MAYBE_UNLOCK(cd);
  539 
  540     return (result);
  541 }
  542 
  543 static dns_sdlzmethods_t dlz_dlopen_methods = {
  544     dlopen_dlz_create,   dlopen_dlz_destroy,    dlopen_dlz_findzonedb,
  545     dlopen_dlz_lookup,   dlopen_dlz_authority,  dlopen_dlz_allnodes,
  546     dlopen_dlz_allowzonexfr, dlopen_dlz_newversion, dlopen_dlz_closeversion,
  547     dlopen_dlz_configure,    dlopen_dlz_ssumatch,   dlopen_dlz_addrdataset,
  548     dlopen_dlz_subrdataset,  dlopen_dlz_delrdataset
  549 };
  550 #endif /* ifdef ISC_DLZ_DLOPEN */
  551 
  552 /*
  553  * Register driver with BIND
  554  */
  555 isc_result_t
  556 dlz_dlopen_init(isc_mem_t *mctx) {
  557 #ifndef ISC_DLZ_DLOPEN
  558     UNUSED(mctx);
  559     return (ISC_R_NOTIMPLEMENTED);
  560 #else  /* ifndef ISC_DLZ_DLOPEN */
  561     isc_result_t result;
  562 
  563     dlopen_log(2, "Registering DLZ_dlopen driver");
  564 
  565     result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL,
  566                   DNS_SDLZFLAG_RELATIVEOWNER |
  567                       DNS_SDLZFLAG_RELATIVERDATA |
  568                       DNS_SDLZFLAG_THREADSAFE,
  569                   mctx, &dlz_dlopen);
  570 
  571     if (result != ISC_R_SUCCESS) {
  572         UNEXPECTED_ERROR(__FILE__, __LINE__,
  573                  "dns_sdlzregister() failed: %s",
  574                  isc_result_totext(result));
  575         result = ISC_R_UNEXPECTED;
  576     }
  577 
  578     return (result);
  579 #endif /* ifndef ISC_DLZ_DLOPEN */
  580 }
  581 
  582 /*
  583  * Unregister the driver
  584  */
  585 void
  586 dlz_dlopen_clear(void) {
  587 #ifdef ISC_DLZ_DLOPEN
  588     dlopen_log(2, "Unregistering DLZ_dlopen driver");
  589     if (dlz_dlopen != NULL) {
  590         dns_sdlzunregister(&dlz_dlopen);
  591     }
  592 #endif /* ifdef ISC_DLZ_DLOPEN */
  593 }