"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/dns/dlz.c" (7 Sep 2020, 15434 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


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.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Portions 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 /*
   13  * Copyright (C) 2002 Stichting NLnet, Netherlands, stichting@nlnet.nl.
   14  *
   15  * Permission to use, copy, modify, and distribute this software for any
   16  * purpose with or without fee is hereby granted, provided that the
   17  * above copyright notice and this permission notice appear in all
   18  * copies.
   19  *
   20  * THE SOFTWARE IS PROVIDED "AS IS" AND STICHTING NLNET
   21  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   23  * STICHTING NLNET BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
   24  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
   25  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
   26  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
   27  * USE OR PERFORMANCE OF THIS SOFTWARE.
   28  *
   29  * The development of Dynamically Loadable Zones (DLZ) for Bind 9 was
   30  * conceived and contributed by Rob Butler.
   31  *
   32  * Permission to use, copy, modify, and distribute this software for any
   33  * purpose with or without fee is hereby granted, provided that the
   34  * above copyright notice and this permission notice appear in all
   35  * copies.
   36  *
   37  * THE SOFTWARE IS PROVIDED "AS IS" AND ROB BUTLER
   38  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
   39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
   40  * ROB BUTLER BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
   41  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
   42  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
   43  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
   44  * USE OR PERFORMANCE OF THIS SOFTWARE.
   45  */
   46 
   47 
   48 /*! \file */
   49 
   50 /***
   51  *** Imports
   52  ***/
   53 
   54 #include <config.h>
   55 
   56 #include <stdbool.h>
   57 
   58 #include <dns/db.h>
   59 #include <dns/dlz.h>
   60 #include <dns/fixedname.h>
   61 #include <dns/log.h>
   62 #include <dns/master.h>
   63 #include <dns/ssu.h>
   64 #include <dns/zone.h>
   65 
   66 
   67 #include <isc/buffer.h>
   68 #include <isc/commandline.h>
   69 #include <isc/magic.h>
   70 #include <isc/mem.h>
   71 #include <isc/once.h>
   72 #include <isc/rwlock.h>
   73 #include <isc/string.h>
   74 #include <isc/util.h>
   75 
   76 /***
   77  *** Supported DLZ DB Implementations Registry
   78  ***/
   79 
   80 static ISC_LIST(dns_dlzimplementation_t) dlz_implementations;
   81 static isc_rwlock_t dlz_implock;
   82 static isc_once_t once = ISC_ONCE_INIT;
   83 
   84 static void
   85 dlz_initialize(void) {
   86     RUNTIME_CHECK(isc_rwlock_init(&dlz_implock, 0, 0) == ISC_R_SUCCESS);
   87     ISC_LIST_INIT(dlz_implementations);
   88 }
   89 
   90 /*%
   91  * Searches the dlz_implementations list for a driver matching name.
   92  */
   93 static inline dns_dlzimplementation_t *
   94 dlz_impfind(const char *name) {
   95     dns_dlzimplementation_t *imp;
   96 
   97     for (imp = ISC_LIST_HEAD(dlz_implementations);
   98          imp != NULL;
   99          imp = ISC_LIST_NEXT(imp, link))
  100         if (strcasecmp(name, imp->name) == 0)
  101             return (imp);
  102     return (NULL);
  103 }
  104 
  105 /***
  106  *** Basic DLZ Methods
  107  ***/
  108 
  109 isc_result_t
  110 dns_dlzallowzonexfr(dns_view_t *view, dns_name_t *name,
  111             isc_sockaddr_t *clientaddr, dns_db_t **dbp)
  112 {
  113     isc_result_t result = ISC_R_NOTFOUND;
  114     dns_dlzallowzonexfr_t allowzonexfr;
  115     dns_dlzdb_t *dlzdb;
  116 
  117     /*
  118      * Performs checks to make sure data is as we expect it to be.
  119      */
  120     REQUIRE(name != NULL);
  121     REQUIRE(dbp != NULL && *dbp == NULL);
  122 
  123     /*
  124      * Find a driver in which the zone exists and transfer is supported
  125      */
  126     for (dlzdb = ISC_LIST_HEAD(view->dlz_searched);
  127          dlzdb != NULL;
  128          dlzdb = ISC_LIST_NEXT(dlzdb, link))
  129     {
  130         REQUIRE(DNS_DLZ_VALID(dlzdb));
  131 
  132         allowzonexfr = dlzdb->implementation->methods->allowzonexfr;
  133         result = (*allowzonexfr)(dlzdb->implementation->driverarg,
  134                      dlzdb->dbdata, dlzdb->mctx,
  135                      view->rdclass, name, clientaddr, dbp);
  136 
  137         /*
  138          * if ISC_R_NOPERM, we found the right database but
  139          * the zone may not transfer.
  140          */
  141         if (result == ISC_R_SUCCESS || result == ISC_R_NOPERM)
  142             return (result);
  143     }
  144 
  145     if (result == ISC_R_NOTIMPLEMENTED)
  146         result = ISC_R_NOTFOUND;
  147 
  148     return (result);
  149 }
  150 
  151 isc_result_t
  152 dns_dlzcreate(isc_mem_t *mctx, const char *dlzname, const char *drivername,
  153           unsigned int argc, char *argv[], dns_dlzdb_t **dbp)
  154 {
  155     dns_dlzimplementation_t *impinfo;
  156     isc_result_t result;
  157     dns_dlzdb_t *db = NULL;
  158 
  159     /*
  160      * initialize the dlz_implementations list, this is guaranteed
  161      * to only really happen once.
  162      */
  163     RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
  164 
  165     /*
  166      * Performs checks to make sure data is as we expect it to be.
  167      */
  168     REQUIRE(dbp != NULL && *dbp == NULL);
  169     REQUIRE(dlzname != NULL);
  170     REQUIRE(drivername != NULL);
  171     REQUIRE(mctx != NULL);
  172 
  173     /* write log message */
  174     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  175               DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
  176               "Loading '%s' using driver %s", dlzname, drivername);
  177 
  178     /* lock the dlz_implementations list so we can search it. */
  179     RWLOCK(&dlz_implock, isc_rwlocktype_read);
  180 
  181     /* search for the driver implementation  */
  182     impinfo = dlz_impfind(drivername);
  183     if (impinfo == NULL) {
  184         RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
  185 
  186         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  187                   DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
  188                   "unsupported DLZ database driver '%s'."
  189                   "  %s not loaded.",
  190                   drivername, dlzname);
  191 
  192         return (ISC_R_NOTFOUND);
  193     }
  194 
  195     /* Allocate memory to hold the DLZ database driver */
  196     db = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
  197     if (db == NULL) {
  198         RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
  199         return (ISC_R_NOMEMORY);
  200     }
  201 
  202     /* Make sure memory region is set to all 0's */
  203     memset(db, 0, sizeof(dns_dlzdb_t));
  204 
  205     ISC_LINK_INIT(db, link);
  206     db->implementation = impinfo;
  207     if (dlzname != NULL)
  208         db->dlzname = isc_mem_strdup(mctx, dlzname);
  209 
  210     /* Create a new database using implementation 'drivername'. */
  211     result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,
  212                          impinfo->driverarg,
  213                          &db->dbdata));
  214 
  215     /* mark the DLZ driver as valid */
  216     if (result == ISC_R_SUCCESS) {
  217         RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
  218         db->magic = DNS_DLZ_MAGIC;
  219         isc_mem_attach(mctx, &db->mctx);
  220         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  221                   DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
  222                   "DLZ driver loaded successfully.");
  223         *dbp = db;
  224         return (ISC_R_SUCCESS);
  225     } else {
  226         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  227                   DNS_LOGMODULE_DLZ, ISC_LOG_ERROR,
  228                   "DLZ driver failed to load.");
  229     }
  230 
  231     /* impinfo->methods->create failed. */
  232     RWUNLOCK(&dlz_implock, isc_rwlocktype_read);
  233     isc_mem_put(mctx, db, sizeof(dns_dlzdb_t));
  234     return (result);
  235 }
  236 
  237 void
  238 dns_dlzdestroy(dns_dlzdb_t **dbp) {
  239     dns_dlzdestroy_t destroy;
  240     dns_dlzdb_t *db;
  241 
  242     /* Write debugging message to log */
  243     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  244               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
  245               "Unloading DLZ driver.");
  246 
  247     /*
  248      * Perform checks to make sure data is as we expect it to be.
  249      */
  250     REQUIRE(dbp != NULL && DNS_DLZ_VALID(*dbp));
  251 
  252     db = *dbp;
  253     *dbp = NULL;
  254 
  255     if (db->ssutable != NULL)
  256         dns_ssutable_detach(&db->ssutable);
  257 
  258     /* call the drivers destroy method */
  259     if (db->dlzname != NULL)
  260         isc_mem_free(db->mctx, db->dlzname);
  261     destroy = db->implementation->methods->destroy;
  262     (*destroy)(db->implementation->driverarg, db->dbdata);
  263     /* return memory and detach */
  264     isc_mem_putanddetach(&db->mctx, db, sizeof(dns_dlzdb_t));
  265 }
  266 
  267 /*%
  268  * Registers a DLZ driver.  This basically just adds the dlz
  269  * driver to the list of available drivers in the dlz_implementations list.
  270  */
  271 isc_result_t
  272 dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods,
  273         void *driverarg, isc_mem_t *mctx,
  274         dns_dlzimplementation_t **dlzimp)
  275 {
  276 
  277     dns_dlzimplementation_t *dlz_imp;
  278 
  279     /* Write debugging message to log */
  280     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  281               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
  282               "Registering DLZ driver '%s'", drivername);
  283 
  284     /*
  285      * Performs checks to make sure data is as we expect it to be.
  286      */
  287     REQUIRE(drivername != NULL);
  288     REQUIRE(methods != NULL);
  289     REQUIRE(methods->create != NULL);
  290     REQUIRE(methods->destroy != NULL);
  291     REQUIRE(methods->findzone != NULL);
  292     REQUIRE(mctx != NULL);
  293     REQUIRE(dlzimp != NULL && *dlzimp == NULL);
  294 
  295     /*
  296      * initialize the dlz_implementations list, this is guaranteed
  297      * to only really happen once.
  298      */
  299     RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
  300 
  301     /* lock the dlz_implementations list so we can modify it. */
  302     RWLOCK(&dlz_implock, isc_rwlocktype_write);
  303 
  304     /*
  305      * check that another already registered driver isn't using
  306      * the same name
  307      */
  308     dlz_imp = dlz_impfind(drivername);
  309     if (dlz_imp != NULL) {
  310         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  311                   DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
  312                   "DLZ Driver '%s' already registered",
  313                   drivername);
  314         RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
  315         return (ISC_R_EXISTS);
  316     }
  317 
  318     /*
  319      * Allocate memory for a dlz_implementation object.  Error if
  320      * we cannot.
  321      */
  322     dlz_imp = isc_mem_get(mctx, sizeof(dns_dlzimplementation_t));
  323     if (dlz_imp == NULL) {
  324         RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
  325         return (ISC_R_NOMEMORY);
  326     }
  327 
  328     /* Make sure memory region is set to all 0's */
  329     memset(dlz_imp, 0, sizeof(dns_dlzimplementation_t));
  330 
  331     /* Store the data passed into this method */
  332     dlz_imp->name = drivername;
  333     dlz_imp->methods = methods;
  334     dlz_imp->mctx = NULL;
  335     dlz_imp->driverarg = driverarg;
  336 
  337     /* attach the new dlz_implementation object to a memory context */
  338     isc_mem_attach(mctx, &dlz_imp->mctx);
  339 
  340     /*
  341      * prepare the dlz_implementation object to be put in a list,
  342      * and append it to the list
  343      */
  344     ISC_LINK_INIT(dlz_imp, link);
  345     ISC_LIST_APPEND(dlz_implementations, dlz_imp, link);
  346 
  347     /* Unlock the dlz_implementations list.  */
  348     RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
  349 
  350     /* Pass back the dlz_implementation that we created. */
  351     *dlzimp = dlz_imp;
  352 
  353     return (ISC_R_SUCCESS);
  354 }
  355 
  356 /*%
  357  * Tokenize the string "s" into whitespace-separated words,
  358  * return the number of words in '*argcp' and an array
  359  * of pointers to the words in '*argvp'.  The caller
  360  * must free the array using isc_mem_put().  The string
  361  * is modified in-place.
  362  */
  363 isc_result_t
  364 dns_dlzstrtoargv(isc_mem_t *mctx, char *s,
  365          unsigned int *argcp, char ***argvp)
  366 {
  367     return(isc_commandline_strtoargv(mctx, s, argcp, argvp, 0));
  368 }
  369 
  370 /*%
  371  * Unregisters a DLZ driver.  This basically just removes the dlz
  372  * driver from the list of available drivers in the dlz_implementations list.
  373  */
  374 void
  375 dns_dlzunregister(dns_dlzimplementation_t **dlzimp) {
  376     dns_dlzimplementation_t *dlz_imp;
  377     isc_mem_t *mctx;
  378 
  379     /* Write debugging message to log */
  380     isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  381               DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(2),
  382               "Unregistering DLZ driver.");
  383 
  384     /*
  385      * Performs checks to make sure data is as we expect it to be.
  386      */
  387     REQUIRE(dlzimp != NULL && *dlzimp != NULL);
  388 
  389     /*
  390      * initialize the dlz_implementations list, this is guaranteed
  391      * to only really happen once.
  392      */
  393     RUNTIME_CHECK(isc_once_do(&once, dlz_initialize) == ISC_R_SUCCESS);
  394 
  395     dlz_imp = *dlzimp;
  396 
  397     /* lock the dlz_implementations list so we can modify it. */
  398     RWLOCK(&dlz_implock, isc_rwlocktype_write);
  399 
  400     /* remove the dlz_implementation object from the list */
  401     ISC_LIST_UNLINK(dlz_implementations, dlz_imp, link);
  402     mctx = dlz_imp->mctx;
  403 
  404     /*
  405      * Return the memory back to the available memory pool and
  406      * remove it from the memory context.
  407      */
  408     isc_mem_put(mctx, dlz_imp, sizeof(dns_dlzimplementation_t));
  409     isc_mem_detach(&mctx);
  410 
  411     /* Unlock the dlz_implementations list. */
  412     RWUNLOCK(&dlz_implock, isc_rwlocktype_write);
  413 }
  414 
  415 /*
  416  * Create a writeable DLZ zone. This can be called by DLZ drivers
  417  * during configure() to create a zone that can be updated. The zone
  418  * type is set to dns_zone_dlz, which is equivalent to a master zone
  419  *
  420  * This function uses a callback setup in dns_dlzconfigure() to call
  421  * into the server zone code to setup the remaining pieces of server
  422  * specific functionality on the zone
  423  */
  424 isc_result_t
  425 dns_dlz_writeablezone(dns_view_t *view, dns_dlzdb_t *dlzdb,
  426               const char *zone_name)
  427 {
  428     dns_zone_t *zone = NULL;
  429     dns_zone_t *dupzone = NULL;
  430     isc_result_t result;
  431     isc_buffer_t buffer;
  432     dns_fixedname_t fixorigin;
  433     dns_name_t *origin;
  434 
  435     REQUIRE(DNS_DLZ_VALID(dlzdb));
  436 
  437     REQUIRE(dlzdb->configure_callback != NULL);
  438 
  439     isc_buffer_constinit(&buffer, zone_name, strlen(zone_name));
  440     isc_buffer_add(&buffer, strlen(zone_name));
  441     dns_fixedname_init(&fixorigin);
  442     result = dns_name_fromtext(dns_fixedname_name(&fixorigin),
  443                    &buffer, dns_rootname, 0, NULL);
  444     if (result != ISC_R_SUCCESS)
  445         goto cleanup;
  446     origin = dns_fixedname_name(&fixorigin);
  447 
  448     if (!dlzdb->search) {
  449         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  450                   DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
  451                   "DLZ %s has 'search no;', but attempted to "
  452                   "register writeable zone %s.",
  453                   dlzdb->dlzname, zone_name);
  454         result = ISC_R_SUCCESS;
  455         goto cleanup;
  456     }
  457 
  458     /* See if the zone already exists */
  459     result = dns_view_findzone(view, origin, &dupzone);
  460     if (result == ISC_R_SUCCESS) {
  461         dns_zone_detach(&dupzone);
  462         result = ISC_R_EXISTS;
  463         goto cleanup;
  464     }
  465     INSIST(dupzone == NULL);
  466 
  467     /* Create it */
  468     result = dns_zone_create(&zone, view->mctx);
  469     if (result != ISC_R_SUCCESS)
  470         goto cleanup;
  471     result = dns_zone_setorigin(zone, origin);
  472     if (result != ISC_R_SUCCESS)
  473         goto cleanup;
  474     dns_zone_setview(zone, view);
  475 
  476     dns_zone_setadded(zone, true);
  477 
  478     if (dlzdb->ssutable == NULL) {
  479         result = dns_ssutable_createdlz(dlzdb->mctx,
  480                         &dlzdb->ssutable, dlzdb);
  481         if (result != ISC_R_SUCCESS)
  482             goto cleanup;
  483     }
  484     dns_zone_setssutable(zone, dlzdb->ssutable);
  485 
  486     result = dlzdb->configure_callback(view, dlzdb, zone);
  487     if (result != ISC_R_SUCCESS)
  488         goto cleanup;
  489 
  490     result = dns_view_addzone(view, zone);
  491 
  492 
  493  cleanup:
  494     if (zone != NULL)
  495         dns_zone_detach(&zone);
  496 
  497     return (result);
  498 }
  499 
  500 /*%
  501  * Configure a DLZ driver. This is optional, and if supplied gives
  502  * the backend an opportunity to configure parameters related to DLZ.
  503  */
  504 isc_result_t
  505 dns_dlzconfigure(dns_view_t *view, dns_dlzdb_t *dlzdb,
  506          dlzconfigure_callback_t callback)
  507 {
  508     dns_dlzimplementation_t *impl;
  509     isc_result_t result;
  510 
  511     REQUIRE(DNS_DLZ_VALID(dlzdb));
  512     REQUIRE(dlzdb->implementation != NULL);
  513 
  514     impl = dlzdb->implementation;
  515 
  516     if (impl->methods->configure == NULL)
  517         return (ISC_R_SUCCESS);
  518 
  519     dlzdb->configure_callback = callback;
  520 
  521     result = impl->methods->configure(impl->driverarg, dlzdb->dbdata,
  522                       view, dlzdb);
  523     return (result);
  524 }
  525 
  526 bool
  527 dns_dlz_ssumatch(dns_dlzdb_t *dlzdatabase, dns_name_t *signer,
  528          dns_name_t *name, isc_netaddr_t *tcpaddr,
  529          dns_rdatatype_t type, const dst_key_t *key)
  530 {
  531     dns_dlzimplementation_t *impl;
  532     bool r;
  533 
  534     REQUIRE(dlzdatabase != NULL);
  535     REQUIRE(dlzdatabase->implementation != NULL);
  536     REQUIRE(dlzdatabase->implementation->methods != NULL);
  537     impl = dlzdatabase->implementation;
  538 
  539     if (impl->methods->ssumatch == NULL) {
  540         isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
  541                   DNS_LOGMODULE_DLZ, ISC_LOG_INFO,
  542                   "No ssumatch method for DLZ database");
  543         return (false);
  544     }
  545 
  546     r = impl->methods->ssumatch(signer, name, tcpaddr, type, key,
  547                     impl->driverarg, dlzdatabase->dbdata);
  548     return (r);
  549 }