"Fossies" - the Fresh Open Source Software Archive

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