"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/bin/named/update.c" (7 Sep 2020, 96722 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 "update.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 <config.h>
   13 
   14 #include <inttypes.h>
   15 #include <stdbool.h>
   16 
   17 #include <isc/netaddr.h>
   18 #include <isc/print.h>
   19 #include <isc/serial.h>
   20 #include <isc/stats.h>
   21 #include <isc/string.h>
   22 #include <isc/taskpool.h>
   23 #include <isc/util.h>
   24 
   25 #include <dns/db.h>
   26 #include <dns/dbiterator.h>
   27 #include <dns/diff.h>
   28 #include <dns/dnssec.h>
   29 #include <dns/events.h>
   30 #include <dns/fixedname.h>
   31 #include <dns/journal.h>
   32 #include <dns/keyvalues.h>
   33 #include <dns/message.h>
   34 #include <dns/nsec.h>
   35 #include <dns/nsec3.h>
   36 #include <dns/private.h>
   37 #include <dns/rdataclass.h>
   38 #include <dns/rdataset.h>
   39 #include <dns/rdatasetiter.h>
   40 #include <dns/rdatastruct.h>
   41 #include <dns/rdatatype.h>
   42 #include <dns/soa.h>
   43 #include <dns/ssu.h>
   44 #include <dns/tsig.h>
   45 #include <dns/update.h>
   46 #include <dns/view.h>
   47 #include <dns/zone.h>
   48 #include <dns/zt.h>
   49 
   50 #include <named/client.h>
   51 #include <named/log.h>
   52 #include <named/server.h>
   53 #include <named/update.h>
   54 
   55 /*! \file
   56  * \brief
   57  * This module implements dynamic update as in RFC2136.
   58  */
   59 
   60 /*
   61  *  XXX TODO:
   62  * - document strict minimality
   63  */
   64 
   65 /**************************************************************************/
   66 
   67 /*%
   68  * Log level for tracing dynamic update protocol requests.
   69  */
   70 #define LOGLEVEL_PROTOCOL   ISC_LOG_INFO
   71 
   72 /*%
   73  * Log level for low-level debug tracing.
   74  */
   75 #define LOGLEVEL_DEBUG      ISC_LOG_DEBUG(8)
   76 
   77 /*%
   78  * Check an operation for failure.  These macros all assume that
   79  * the function using them has a 'result' variable and a 'failure'
   80  * label.
   81  */
   82 #define CHECK(op) \
   83     do { result = (op); \
   84         if (result != ISC_R_SUCCESS) goto failure; \
   85     } while (0)
   86 
   87 /*%
   88  * Fail unconditionally with result 'code', which must not
   89  * be ISC_R_SUCCESS.  The reason for failure presumably has
   90  * been logged already.
   91  *
   92  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
   93  * from complaining about "end-of-loop code not reached".
   94  */
   95 
   96 #define FAIL(code) \
   97     do {                            \
   98         result = (code);                \
   99         if (result != ISC_R_SUCCESS) goto failure;  \
  100     } while (0)
  101 
  102 /*%
  103  * Fail unconditionally and log as a client error.
  104  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
  105  * from complaining about "end-of-loop code not reached".
  106  */
  107 #define FAILC(code, msg) \
  108     do {                            \
  109         const char *_what = "failed";           \
  110         result = (code);                \
  111         switch (result) {               \
  112         case DNS_R_NXDOMAIN:                \
  113         case DNS_R_YXDOMAIN:                \
  114         case DNS_R_YXRRSET:             \
  115         case DNS_R_NXRRSET:             \
  116             _what = "unsuccessful";         \
  117         }                       \
  118         update_log(client, zone, LOGLEVEL_PROTOCOL, \
  119                "update %s: %s (%s)", _what,     \
  120                msg, isc_result_totext(result)); \
  121         if (result != ISC_R_SUCCESS) goto failure;  \
  122     } while (0)
  123 #define PREREQFAILC(code, msg) \
  124     do {                            \
  125         inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
  126         FAILC(code, msg);               \
  127     } while (0)
  128 
  129 #define FAILN(code, name, msg) \
  130     do {                                \
  131         const char *_what = "failed";               \
  132         result = (code);                    \
  133         switch (result) {                   \
  134         case DNS_R_NXDOMAIN:                    \
  135         case DNS_R_YXDOMAIN:                    \
  136         case DNS_R_YXRRSET:                 \
  137         case DNS_R_NXRRSET:                 \
  138             _what = "unsuccessful";             \
  139         }                           \
  140         if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {   \
  141             char _nbuf[DNS_NAME_FORMATSIZE];        \
  142             dns_name_format(name, _nbuf, sizeof(_nbuf));    \
  143             update_log(client, zone, LOGLEVEL_PROTOCOL, \
  144                    "update %s: %s: %s (%s)", _what, _nbuf, \
  145                    msg, isc_result_totext(result)); \
  146         }                           \
  147         if (result != ISC_R_SUCCESS) goto failure;      \
  148     } while (0)
  149 #define PREREQFAILN(code, name, msg) \
  150     do {                                \
  151         inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
  152         FAILN(code, name, msg);                 \
  153     } while (0)
  154 
  155 #define FAILNT(code, name, type, msg) \
  156     do {                                \
  157         const char *_what = "failed";               \
  158         result = (code);                    \
  159         switch (result) {                   \
  160         case DNS_R_NXDOMAIN:                    \
  161         case DNS_R_YXDOMAIN:                    \
  162         case DNS_R_YXRRSET:                 \
  163         case DNS_R_NXRRSET:                 \
  164             _what = "unsuccessful";             \
  165         }                           \
  166         if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {   \
  167             char _nbuf[DNS_NAME_FORMATSIZE];        \
  168             char _tbuf[DNS_RDATATYPE_FORMATSIZE];       \
  169             dns_name_format(name, _nbuf, sizeof(_nbuf));    \
  170             dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
  171             update_log(client, zone, LOGLEVEL_PROTOCOL, \
  172                    "update %s: %s/%s: %s (%s)",     \
  173                    _what, _nbuf, _tbuf, msg,        \
  174                    isc_result_totext(result));      \
  175         }                           \
  176         if (result != ISC_R_SUCCESS) goto failure;      \
  177     } while (0)
  178 #define PREREQFAILNT(code, name, type, msg)             \
  179     do {                                \
  180         inc_stats(zone, dns_nsstatscounter_updatebadprereq); \
  181         FAILNT(code, name, type, msg);              \
  182     } while (0)
  183 
  184 /*%
  185  * Fail unconditionally and log as a server error.
  186  * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
  187  * from complaining about "end-of-loop code not reached".
  188  */
  189 #define FAILS(code, msg) \
  190     do {                            \
  191         result = (code);                \
  192         update_log(client, zone, LOGLEVEL_PROTOCOL, \
  193                "error: %s: %s",         \
  194                msg, isc_result_totext(result)); \
  195         if (result != ISC_R_SUCCESS) goto failure;  \
  196     } while (0)
  197 
  198 /*
  199  * Return TRUE if NS_CLIENTATTR_TCP is set in the attributes other FALSE.
  200  */
  201 #define TCPCLIENT(client) (((client)->attributes & NS_CLIENTATTR_TCP) != 0)
  202 
  203 /**************************************************************************/
  204 
  205 typedef struct rr rr_t;
  206 
  207 struct rr {
  208     /* dns_name_t name; */
  209     uint32_t        ttl;
  210     dns_rdata_t     rdata;
  211 };
  212 
  213 typedef struct update_event update_event_t;
  214 
  215 struct update_event {
  216     ISC_EVENT_COMMON(update_event_t);
  217     dns_zone_t      *zone;
  218     isc_result_t        result;
  219     dns_message_t       *answer;
  220 };
  221 
  222 /*%
  223  * Prepare an RR for the addition of the new RR 'ctx->update_rr',
  224  * with TTL 'ctx->update_rr_ttl', to its rdataset, by deleting
  225  * the RRs if it is replaced by the new RR or has a conflicting TTL.
  226  * The necessary changes are appended to ctx->del_diff and ctx->add_diff;
  227  * we need to do all deletions before any additions so that we don't run
  228  * into transient states with conflicting TTLs.
  229  */
  230 
  231 typedef struct {
  232     dns_db_t *db;
  233     dns_dbversion_t *ver;
  234     dns_diff_t *diff;
  235     dns_name_t *name;
  236     dns_name_t *oldname;
  237     dns_rdata_t *update_rr;
  238     dns_ttl_t update_rr_ttl;
  239     bool ignore_add;
  240     dns_diff_t del_diff;
  241     dns_diff_t add_diff;
  242 } add_rr_prepare_ctx_t;
  243 
  244 /**************************************************************************/
  245 /*
  246  * Forward declarations.
  247  */
  248 
  249 static void update_action(isc_task_t *task, isc_event_t *event);
  250 static void updatedone_action(isc_task_t *task, isc_event_t *event);
  251 static isc_result_t send_forward_event(ns_client_t *client, dns_zone_t *zone);
  252 static void forward_done(isc_task_t *task, isc_event_t *event);
  253 static isc_result_t add_rr_prepare_action(void *data, rr_t *rr);
  254 
  255 /**************************************************************************/
  256 
  257 static void
  258 update_log(ns_client_t *client, dns_zone_t *zone,
  259        int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
  260 
  261 static void
  262 update_log(ns_client_t *client, dns_zone_t *zone,
  263        int level, const char *fmt, ...)
  264 {
  265     va_list ap;
  266     char message[4096];
  267     char namebuf[DNS_NAME_FORMATSIZE];
  268     char classbuf[DNS_RDATACLASS_FORMATSIZE];
  269 
  270     if (client == NULL) {
  271         return;
  272     }
  273 
  274     if (isc_log_wouldlog(ns_g_lctx, level) == false) {
  275         return;
  276     }
  277 
  278     va_start(ap, fmt);
  279     vsnprintf(message, sizeof(message), fmt, ap);
  280     va_end(ap);
  281 
  282     if (zone != NULL) {
  283         dns_name_format(dns_zone_getorigin(zone), namebuf,
  284                 sizeof(namebuf));
  285         dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
  286                       sizeof(classbuf));
  287 
  288         ns_client_log(client, NS_LOGCATEGORY_UPDATE,
  289                   NS_LOGMODULE_UPDATE,
  290                   level, "updating zone '%s/%s': %s",
  291                   namebuf, classbuf, message);
  292     } else {
  293         ns_client_log(client, NS_LOGCATEGORY_UPDATE,
  294                   NS_LOGMODULE_UPDATE,
  295                   level, "%s", message);
  296     }
  297 
  298 }
  299 
  300 static void
  301 update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
  302     update_log(arg, zone, level, "%s", message);
  303 }
  304 
  305 /*%
  306  * Increment updated-related statistics counters.
  307  */
  308 static inline void
  309 inc_stats(dns_zone_t *zone, isc_statscounter_t counter) {
  310     isc_stats_increment(ns_g_server->nsstats, counter);
  311 
  312     if (zone != NULL) {
  313         isc_stats_t *zonestats = dns_zone_getrequeststats(zone);
  314         if (zonestats != NULL)
  315             isc_stats_increment(zonestats, counter);
  316     }
  317 }
  318 
  319 /*%
  320  * Check if we could have queried for the contents of this zone or
  321  * if the zone is potentially updateable.
  322  * If the zone can potentially be updated and the check failed then
  323  * log a error otherwise we log a informational message.
  324  */
  325 static isc_result_t
  326 checkqueryacl(ns_client_t *client, dns_acl_t *queryacl, dns_name_t *zonename,
  327           dns_acl_t *updateacl, dns_ssutable_t *ssutable)
  328 {
  329     char namebuf[DNS_NAME_FORMATSIZE];
  330     char classbuf[DNS_RDATACLASS_FORMATSIZE];
  331     int level;
  332     isc_result_t result;
  333 
  334     result = ns_client_checkaclsilent(client, NULL, queryacl, true);
  335     if (result != ISC_R_SUCCESS) {
  336         dns_name_format(zonename, namebuf, sizeof(namebuf));
  337         dns_rdataclass_format(client->view->rdclass, classbuf,
  338                       sizeof(classbuf));
  339 
  340         level = (updateacl == NULL && ssutable == NULL) ?
  341                 ISC_LOG_INFO : ISC_LOG_ERROR;
  342 
  343         ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
  344                   NS_LOGMODULE_UPDATE, level,
  345                   "update '%s/%s' denied due to allow-query",
  346                   namebuf, classbuf);
  347     } else if (updateacl == NULL && ssutable == NULL) {
  348         dns_name_format(zonename, namebuf, sizeof(namebuf));
  349         dns_rdataclass_format(client->view->rdclass, classbuf,
  350                       sizeof(classbuf));
  351 
  352         result = DNS_R_REFUSED;
  353         ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
  354                   NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
  355                   "update '%s/%s' denied", namebuf, classbuf);
  356     }
  357     return (result);
  358 }
  359 
  360 /*%
  361  * Override the default acl logging when checking whether a client
  362  * can update the zone or whether we can forward the request to the
  363  * master based on IP address.
  364  *
  365  * 'message' contains the type of operation that is being attempted.
  366  * 'slave' indicates if this is a slave zone.  If 'acl' is NULL then
  367  * log at debug=3.
  368  * If the zone has no access controls configured ('acl' == NULL &&
  369  * 'has_ssutable == ISC_FALS) log the attempt at info, otherwise
  370  * at error.
  371  *
  372  * If the request was signed log that we received it.
  373  */
  374 static isc_result_t
  375 checkupdateacl(ns_client_t *client, dns_acl_t *acl, const char *message,
  376            dns_name_t *zonename, bool slave,
  377            bool has_ssutable)
  378 {
  379     char namebuf[DNS_NAME_FORMATSIZE];
  380     char classbuf[DNS_RDATACLASS_FORMATSIZE];
  381     int level = ISC_LOG_ERROR;
  382     const char *msg = "denied";
  383     isc_result_t result;
  384 
  385     if (slave && acl == NULL) {
  386         result = DNS_R_NOTIMP;
  387         level = ISC_LOG_DEBUG(3);
  388         msg = "disabled";
  389     } else {
  390         result = ns_client_checkaclsilent(client, NULL, acl, false);
  391         if (result == ISC_R_SUCCESS) {
  392             level = ISC_LOG_DEBUG(3);
  393             msg = "approved";
  394         } else if (acl == NULL && !has_ssutable) {
  395             level = ISC_LOG_INFO;
  396         }
  397     }
  398 
  399     if (client->signer != NULL) {
  400         dns_name_format(client->signer, namebuf, sizeof(namebuf));
  401         ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
  402                   NS_LOGMODULE_UPDATE, ISC_LOG_INFO,
  403                   "signer \"%s\" %s", namebuf, msg);
  404     }
  405 
  406     dns_name_format(zonename, namebuf, sizeof(namebuf));
  407     dns_rdataclass_format(client->view->rdclass, classbuf,
  408                   sizeof(classbuf));
  409 
  410     ns_client_log(client, NS_LOGCATEGORY_UPDATE_SECURITY,
  411               NS_LOGMODULE_UPDATE, level, "%s '%s/%s' %s",
  412               message, namebuf, classbuf, msg);
  413     return (result);
  414 }
  415 
  416 /*%
  417  * Update a single RR in version 'ver' of 'db' and log the
  418  * update in 'diff'.
  419  *
  420  * Ensures:
  421  * \li  '*tuple' == NULL.  Either the tuple is freed, or its
  422  *  ownership has been transferred to the diff.
  423  */
  424 static isc_result_t
  425 do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
  426          dns_diff_t *diff)
  427 {
  428     dns_diff_t temp_diff;
  429     isc_result_t result;
  430 
  431     /*
  432      * Create a singleton diff.
  433      */
  434     dns_diff_init(diff->mctx, &temp_diff);
  435     ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
  436 
  437     /*
  438      * Apply it to the database.
  439      */
  440     result = dns_diff_apply(&temp_diff, db, ver);
  441     ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
  442     if (result != ISC_R_SUCCESS) {
  443         dns_difftuple_free(tuple);
  444         return (result);
  445     }
  446 
  447     /*
  448      * Merge it into the current pending journal entry.
  449      */
  450     dns_diff_appendminimal(diff, tuple);
  451 
  452     /*
  453      * Do not clear temp_diff.
  454      */
  455     return (ISC_R_SUCCESS);
  456 }
  457 
  458 /*%
  459  * Perform the updates in 'updates' in version 'ver' of 'db' and log the
  460  * update in 'diff'.
  461  *
  462  * Ensures:
  463  * \li  'updates' is empty.
  464  */
  465 static isc_result_t
  466 do_diff(dns_diff_t *updates, dns_db_t *db, dns_dbversion_t *ver,
  467     dns_diff_t *diff)
  468 {
  469     isc_result_t result;
  470     while (! ISC_LIST_EMPTY(updates->tuples)) {
  471         dns_difftuple_t *t = ISC_LIST_HEAD(updates->tuples);
  472         ISC_LIST_UNLINK(updates->tuples, t, link);
  473         CHECK(do_one_tuple(&t, db, ver, diff));
  474     }
  475     return (ISC_R_SUCCESS);
  476 
  477  failure:
  478     dns_diff_clear(diff);
  479     return (result);
  480 }
  481 
  482 static isc_result_t
  483 update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
  484           dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
  485           dns_rdata_t *rdata)
  486 {
  487     dns_difftuple_t *tuple = NULL;
  488     isc_result_t result;
  489     result = dns_difftuple_create(diff->mctx, op,
  490                       name, ttl, rdata, &tuple);
  491     if (result != ISC_R_SUCCESS)
  492         return (result);
  493     return (do_one_tuple(&tuple, db, ver, diff));
  494 }
  495 
  496 /**************************************************************************/
  497 /*
  498  * Callback-style iteration over rdatasets and rdatas.
  499  *
  500  * foreach_rrset() can be used to iterate over the RRsets
  501  * of a name and call a callback function with each
  502  * one.  Similarly, foreach_rr() can be used to iterate
  503  * over the individual RRs at name, optionally restricted
  504  * to RRs of a given type.
  505  *
  506  * The callback functions are called "actions" and take
  507  * two arguments: a void pointer for passing arbitrary
  508  * context information, and a pointer to the current RRset
  509  * or RR.  By convention, their names end in "_action".
  510  */
  511 
  512 /*
  513  * XXXRTH  We might want to make this public somewhere in libdns.
  514  */
  515 
  516 /*%
  517  * Function type for foreach_rrset() iterator actions.
  518  */
  519 typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
  520 
  521 /*%
  522  * Function type for foreach_rr() iterator actions.
  523  */
  524 typedef isc_result_t rr_func(void *data, rr_t *rr);
  525 
  526 /*%
  527  * Internal context struct for foreach_node_rr().
  528  */
  529 typedef struct {
  530     rr_func *   rr_action;
  531     void *      rr_action_data;
  532 } foreach_node_rr_ctx_t;
  533 
  534 /*%
  535  * Internal helper function for foreach_node_rr().
  536  */
  537 static isc_result_t
  538 foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
  539     isc_result_t result;
  540     foreach_node_rr_ctx_t *ctx = data;
  541     for (result = dns_rdataset_first(rdataset);
  542          result == ISC_R_SUCCESS;
  543          result = dns_rdataset_next(rdataset))
  544     {
  545         rr_t rr = { 0, DNS_RDATA_INIT };
  546 
  547         dns_rdataset_current(rdataset, &rr.rdata);
  548         rr.ttl = rdataset->ttl;
  549         result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
  550         if (result != ISC_R_SUCCESS)
  551             return (result);
  552     }
  553     if (result != ISC_R_NOMORE)
  554         return (result);
  555     return (ISC_R_SUCCESS);
  556 }
  557 
  558 /*%
  559  * For each rdataset of 'name' in 'ver' of 'db', call 'action'
  560  * with the rdataset and 'action_data' as arguments.  If the name
  561  * does not exist, do nothing.
  562  *
  563  * If 'action' returns an error, abort iteration and return the error.
  564  */
  565 static isc_result_t
  566 foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  567           rrset_func *action, void *action_data)
  568 {
  569     isc_result_t result;
  570     dns_dbnode_t *node;
  571     dns_rdatasetiter_t *iter;
  572     dns_clientinfomethods_t cm;
  573     dns_clientinfo_t ci;
  574     dns_dbversion_t *oldver = NULL;
  575 
  576     dns_clientinfomethods_init(&cm, ns_client_sourceip);
  577 
  578     /*
  579      * Only set the clientinfo 'versionp' if the new version is
  580      * different from the current version
  581      */
  582     dns_db_currentversion(db, &oldver);
  583     dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
  584     dns_db_closeversion(db, &oldver, false);
  585 
  586     node = NULL;
  587     result = dns_db_findnodeext(db, name, false, &cm, &ci, &node);
  588     if (result == ISC_R_NOTFOUND)
  589         return (ISC_R_SUCCESS);
  590     if (result != ISC_R_SUCCESS)
  591         return (result);
  592 
  593     iter = NULL;
  594     result = dns_db_allrdatasets(db, node, ver,
  595                      (isc_stdtime_t) 0, &iter);
  596     if (result != ISC_R_SUCCESS)
  597         goto cleanup_node;
  598 
  599     for (result = dns_rdatasetiter_first(iter);
  600          result == ISC_R_SUCCESS;
  601          result = dns_rdatasetiter_next(iter))
  602     {
  603         dns_rdataset_t rdataset;
  604 
  605         dns_rdataset_init(&rdataset);
  606         dns_rdatasetiter_current(iter, &rdataset);
  607 
  608         result = (*action)(action_data, &rdataset);
  609 
  610         dns_rdataset_disassociate(&rdataset);
  611         if (result != ISC_R_SUCCESS)
  612             goto cleanup_iterator;
  613     }
  614     if (result == ISC_R_NOMORE)
  615         result = ISC_R_SUCCESS;
  616 
  617  cleanup_iterator:
  618     dns_rdatasetiter_destroy(&iter);
  619 
  620  cleanup_node:
  621     dns_db_detachnode(db, &node);
  622 
  623     return (result);
  624 }
  625 
  626 /*%
  627  * For each RR of 'name' in 'ver' of 'db', call 'action'
  628  * with the RR and 'action_data' as arguments.  If the name
  629  * does not exist, do nothing.
  630  *
  631  * If 'action' returns an error, abort iteration
  632  * and return the error.
  633  */
  634 static isc_result_t
  635 foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  636         rr_func *rr_action, void *rr_action_data)
  637 {
  638     foreach_node_rr_ctx_t ctx;
  639     ctx.rr_action = rr_action;
  640     ctx.rr_action_data = rr_action_data;
  641     return (foreach_rrset(db, ver, name,
  642                   foreach_node_rr_action, &ctx));
  643 }
  644 
  645 
  646 /*%
  647  * For each of the RRs specified by 'db', 'ver', 'name', 'type',
  648  * (which can be dns_rdatatype_any to match any type), and 'covers', call
  649  * 'action' with the RR and 'action_data' as arguments. If the name
  650  * does not exist, or if no RRset of the given type exists at the name,
  651  * do nothing.
  652  *
  653  * If 'action' returns an error, abort iteration and return the error.
  654  */
  655 static isc_result_t
  656 foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  657        dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
  658        void *rr_action_data)
  659 {
  660 
  661     isc_result_t result;
  662     dns_dbnode_t *node;
  663     dns_rdataset_t rdataset;
  664     dns_clientinfomethods_t cm;
  665     dns_clientinfo_t ci;
  666     dns_dbversion_t *oldver = NULL;
  667     dns_fixedname_t fixed;
  668 
  669     dns_clientinfomethods_init(&cm, ns_client_sourceip);
  670 
  671     /*
  672      * Only set the clientinfo 'versionp' if the new version is
  673      * different from the current version
  674      */
  675     dns_db_currentversion(db, &oldver);
  676     dns_clientinfo_init(&ci, NULL, (ver != oldver) ? ver : NULL);
  677     dns_db_closeversion(db, &oldver, false);
  678 
  679     if (type == dns_rdatatype_any)
  680         return (foreach_node_rr(db, ver, name,
  681                     rr_action, rr_action_data));
  682 
  683     node = NULL;
  684     if (type == dns_rdatatype_nsec3 ||
  685         (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
  686         result = dns_db_findnsec3node(db, name, false, &node);
  687     else
  688         result = dns_db_findnodeext(db, name, false,
  689                         &cm, &ci, &node);
  690     if (result == ISC_R_NOTFOUND)
  691         return (ISC_R_SUCCESS);
  692     if (result != ISC_R_SUCCESS)
  693         return (result);
  694 
  695     dns_rdataset_init(&rdataset);
  696     result = dns_db_findrdataset(db, node, ver, type, covers,
  697                      (isc_stdtime_t) 0, &rdataset, NULL);
  698     if (result == ISC_R_NOTFOUND) {
  699         result = ISC_R_SUCCESS;
  700         goto cleanup_node;
  701     }
  702     if (result != ISC_R_SUCCESS)
  703         goto cleanup_node;
  704 
  705     if (rr_action == add_rr_prepare_action) {
  706         add_rr_prepare_ctx_t *ctx = rr_action_data;
  707 
  708         ctx->oldname = dns_fixedname_initname(&fixed);
  709         dns_name_copy(name, ctx->oldname, NULL);
  710         dns_rdataset_getownercase(&rdataset, ctx->oldname);
  711     }
  712 
  713     for (result = dns_rdataset_first(&rdataset);
  714          result == ISC_R_SUCCESS;
  715          result = dns_rdataset_next(&rdataset))
  716     {
  717         rr_t rr = { 0, DNS_RDATA_INIT };
  718         dns_rdataset_current(&rdataset, &rr.rdata);
  719         rr.ttl = rdataset.ttl;
  720         result = (*rr_action)(rr_action_data, &rr);
  721         if (result != ISC_R_SUCCESS)
  722             goto cleanup_rdataset;
  723     }
  724     if (result != ISC_R_NOMORE)
  725         goto cleanup_rdataset;
  726     result = ISC_R_SUCCESS;
  727 
  728  cleanup_rdataset:
  729     dns_rdataset_disassociate(&rdataset);
  730  cleanup_node:
  731     dns_db_detachnode(db, &node);
  732 
  733     return (result);
  734 }
  735 
  736 /**************************************************************************/
  737 /*
  738  * Various tests on the database contents (for prerequisites, etc).
  739  */
  740 
  741 /*%
  742  * Function type for predicate functions that compare a database RR 'db_rr'
  743  * against an update RR 'update_rr'.
  744  */
  745 typedef bool rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
  746 
  747 /*%
  748  * Helper function for rrset_exists().
  749  */
  750 static isc_result_t
  751 rrset_exists_action(void *data, rr_t *rr) {
  752     UNUSED(data);
  753     UNUSED(rr);
  754     return (ISC_R_EXISTS);
  755 }
  756 
  757 /*%
  758  * Utility macro for RR existence checking functions.
  759  *
  760  * If the variable 'result' has the value ISC_R_EXISTS or
  761  * ISC_R_SUCCESS, set *exists to true or false,
  762  * respectively, and return success.
  763  *
  764  * If 'result' has any other value, there was a failure.
  765  * Return the failure result code and do not set *exists.
  766  *
  767  * This would be more readable as "do { if ... } while(0)",
  768  * but that form generates tons of warnings on Solaris 2.6.
  769  */
  770 #define RETURN_EXISTENCE_FLAG               \
  771     return ((result == ISC_R_EXISTS) ?      \
  772         (*exists = true, ISC_R_SUCCESS) :   \
  773         ((result == ISC_R_SUCCESS) ?        \
  774          (*exists = false, ISC_R_SUCCESS) : \
  775          result))
  776 
  777 /*%
  778  * Set '*exists' to true iff an rrset of the given type exists,
  779  * to false otherwise.
  780  */
  781 static isc_result_t
  782 rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  783          dns_rdatatype_t type, dns_rdatatype_t covers,
  784          bool *exists)
  785 {
  786     isc_result_t result;
  787     result = foreach_rr(db, ver, name, type, covers,
  788                 rrset_exists_action, NULL);
  789     RETURN_EXISTENCE_FLAG;
  790 }
  791 
  792 /*%
  793  * Helper function for cname_incompatible_rrset_exists.
  794  */
  795 static isc_result_t
  796 cname_compatibility_action(void *data, dns_rdataset_t *rrset) {
  797     UNUSED(data);
  798     if (rrset->type != dns_rdatatype_cname &&
  799         ! dns_rdatatype_atcname(rrset->type))
  800     {
  801         return (ISC_R_EXISTS);
  802     }
  803     return (ISC_R_SUCCESS);
  804 }
  805 
  806 /*%
  807  * Check whether there is an rrset incompatible with adding a CNAME RR,
  808  * i.e., anything but another CNAME (which can be replaced) or a
  809  * DNSSEC RR (which can coexist).
  810  *
  811  * If such an incompatible rrset exists, set '*exists' to true.
  812  * Otherwise, set it to false.
  813  */
  814 static isc_result_t
  815 cname_incompatible_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
  816                 dns_name_t *name, bool *exists) {
  817     isc_result_t result;
  818     result = foreach_rrset(db, ver, name,
  819                    cname_compatibility_action, NULL);
  820     RETURN_EXISTENCE_FLAG;
  821 }
  822 
  823 /*%
  824  * Helper function for rr_count().
  825  */
  826 static isc_result_t
  827 count_rr_action(void *data, rr_t *rr) {
  828     int *countp = data;
  829     UNUSED(rr);
  830     (*countp)++;
  831     return (ISC_R_SUCCESS);
  832 }
  833 
  834 /*%
  835  * Count the number of RRs of 'type' belonging to 'name' in 'ver' of 'db'.
  836  */
  837 static isc_result_t
  838 rr_count(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  839      dns_rdatatype_t type, dns_rdatatype_t covers, int *countp)
  840 {
  841     *countp = 0;
  842     return (foreach_rr(db, ver, name, type, covers,
  843                count_rr_action, countp));
  844 }
  845 
  846 /*%
  847  * Context struct and helper function for name_exists().
  848  */
  849 
  850 static isc_result_t
  851 name_exists_action(void *data, dns_rdataset_t *rrset) {
  852     UNUSED(data);
  853     UNUSED(rrset);
  854     return (ISC_R_EXISTS);
  855 }
  856 
  857 /*%
  858  * Set '*exists' to true iff the given name exists, to false otherwise.
  859  */
  860 static isc_result_t
  861 name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  862         bool *exists)
  863 {
  864     isc_result_t result;
  865     result = foreach_rrset(db, ver, name,
  866                    name_exists_action, NULL);
  867     RETURN_EXISTENCE_FLAG;
  868 }
  869 
  870 /*
  871  *  'ssu_check_t' is used to pass the arguments to
  872  *  dns_ssutable_checkrules() to the callback function
  873  *  ssu_checkrule().
  874  */
  875 typedef struct {
  876     /* The ownername of the record to be updated. */
  877     dns_name_t *name;
  878 
  879     /* The signature's name if the request was signed. */
  880     dns_name_t *signer;
  881 
  882     /* The address of the client. */
  883     isc_netaddr_t *addr;
  884 
  885     /* Whether the request was sent via TCP. */
  886     bool tcp;
  887 
  888     /* The ssu table to check against. */
  889     dns_ssutable_t *table;
  890 
  891     /* the key used for TKEY requests */
  892     dst_key_t *key;
  893 } ssu_check_t;
  894 
  895 static isc_result_t
  896 ssu_checkrule(void *data, dns_rdataset_t *rrset) {
  897     ssu_check_t *ssuinfo = data;
  898     bool result;
  899 
  900     /*
  901      * If we're deleting all records, it's ok to delete RRSIG and NSEC even
  902      * if we're normally not allowed to.
  903      */
  904     if (rrset->type == dns_rdatatype_rrsig ||
  905         rrset->type == dns_rdatatype_nsec)
  906         return (ISC_R_SUCCESS);
  907     result = dns_ssutable_checkrules2(ssuinfo->table, ssuinfo->signer,
  908                       ssuinfo->name, ssuinfo->addr,
  909                       ssuinfo->tcp, &ns_g_server->aclenv,
  910                       rrset->type, ssuinfo->key);
  911     return (result == true ? ISC_R_SUCCESS : ISC_R_FAILURE);
  912 }
  913 
  914 static bool
  915 ssu_checkall(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
  916          dns_ssutable_t *ssutable, dns_name_t *signer,
  917          isc_netaddr_t *addr, bool tcp, dst_key_t *key)
  918 {
  919     isc_result_t result;
  920     ssu_check_t ssuinfo;
  921 
  922     ssuinfo.name = name;
  923     ssuinfo.table = ssutable;
  924     ssuinfo.signer = signer;
  925     ssuinfo.addr = addr;
  926     ssuinfo.tcp = tcp;
  927     ssuinfo.key = key;
  928     result = foreach_rrset(db, ver, name, ssu_checkrule, &ssuinfo);
  929     return (result == ISC_R_SUCCESS);
  930 }
  931 
  932 /**************************************************************************/
  933 /*
  934  * Checking of "RRset exists (value dependent)" prerequisites.
  935  *
  936  * In the RFC2136 section 3.2.5, this is the pseudocode involving
  937  * a variable called "temp", a mapping of <name, type> tuples to rrsets.
  938  *
  939  * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
  940  * where each tuple has op==DNS_DIFFOP_EXISTS.
  941  */
  942 
  943 
  944 /*%
  945  * Append a tuple asserting the existence of the RR with
  946  * 'name' and 'rdata' to 'diff'.
  947  */
  948 static isc_result_t
  949 temp_append(dns_diff_t *diff, dns_name_t *name, dns_rdata_t *rdata) {
  950     isc_result_t result;
  951     dns_difftuple_t *tuple = NULL;
  952 
  953     REQUIRE(DNS_DIFF_VALID(diff));
  954     CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_EXISTS,
  955                    name, 0, rdata, &tuple));
  956     ISC_LIST_APPEND(diff->tuples, tuple, link);
  957  failure:
  958     return (result);
  959 }
  960 
  961 /*%
  962  * Compare two rdatasets represented as sorted lists of tuples.
  963  * All list elements must have the same owner name and type.
  964  * Return ISC_R_SUCCESS if the rdatasets are equal, rcode(dns_rcode_nxrrset)
  965  * if not.
  966  */
  967 static isc_result_t
  968 temp_check_rrset(dns_difftuple_t *a, dns_difftuple_t *b) {
  969     for (;;) {
  970         if (a == NULL || b == NULL)
  971             break;
  972         INSIST(a->op == DNS_DIFFOP_EXISTS &&
  973                b->op == DNS_DIFFOP_EXISTS);
  974         INSIST(a->rdata.type == b->rdata.type);
  975         INSIST(dns_name_equal(&a->name, &b->name));
  976         if (dns_rdata_casecompare(&a->rdata, &b->rdata) != 0)
  977             return (DNS_R_NXRRSET);
  978         a = ISC_LIST_NEXT(a, link);
  979         b = ISC_LIST_NEXT(b, link);
  980     }
  981     if (a != NULL || b != NULL)
  982         return (DNS_R_NXRRSET);
  983     return (ISC_R_SUCCESS);
  984 }
  985 
  986 /*%
  987  * A comparison function defining the sorting order for the entries
  988  * in the "temp" data structure.  The major sort key is the owner name,
  989  * followed by the type and rdata.
  990  */
  991 static int
  992 temp_order(const void *av, const void *bv) {
  993     dns_difftuple_t const * const *ap = av;
  994     dns_difftuple_t const * const *bp = bv;
  995     dns_difftuple_t const *a = *ap;
  996     dns_difftuple_t const *b = *bp;
  997     int r;
  998     r = dns_name_compare(&a->name, &b->name);
  999     if (r != 0)
 1000         return (r);
 1001     r = (b->rdata.type - a->rdata.type);
 1002     if (r != 0)
 1003         return (r);
 1004     r = dns_rdata_casecompare(&a->rdata, &b->rdata);
 1005     return (r);
 1006 }
 1007 
 1008 /*%
 1009  * Check the "RRset exists (value dependent)" prerequisite information
 1010  * in 'temp' against the contents of the database 'db'.
 1011  *
 1012  * Return ISC_R_SUCCESS if the prerequisites are satisfied,
 1013  * rcode(dns_rcode_nxrrset) if not.
 1014  *
 1015  * 'temp' must be pre-sorted.
 1016  */
 1017 
 1018 static isc_result_t
 1019 temp_check(isc_mem_t *mctx, dns_diff_t *temp, dns_db_t *db,
 1020        dns_dbversion_t *ver, dns_name_t *tmpname, dns_rdatatype_t *typep)
 1021 {
 1022     isc_result_t result;
 1023     dns_name_t *name;
 1024     dns_dbnode_t *node;
 1025     dns_difftuple_t *t;
 1026     dns_diff_t trash;
 1027 
 1028     dns_diff_init(mctx, &trash);
 1029 
 1030     /*
 1031      * For each name and type in the prerequisites,
 1032      * construct a sorted rdata list of the corresponding
 1033      * database contents, and compare the lists.
 1034      */
 1035     t = ISC_LIST_HEAD(temp->tuples);
 1036     while (t != NULL) {
 1037         name = &t->name;
 1038         (void)dns_name_copy(name, tmpname, NULL);
 1039         *typep = t->rdata.type;
 1040 
 1041         /* A new unique name begins here. */
 1042         node = NULL;
 1043         result = dns_db_findnode(db, name, false, &node);
 1044         if (result == ISC_R_NOTFOUND) {
 1045             dns_diff_clear(&trash);
 1046             return (DNS_R_NXRRSET);
 1047         }
 1048         if (result != ISC_R_SUCCESS) {
 1049             dns_diff_clear(&trash);
 1050             return (result);
 1051         }
 1052 
 1053         /* A new unique type begins here. */
 1054         while (t != NULL && dns_name_equal(&t->name, name)) {
 1055             dns_rdatatype_t type, covers;
 1056             dns_rdataset_t rdataset;
 1057             dns_diff_t d_rrs; /* Database RRs with
 1058                         this name and type */
 1059             dns_diff_t u_rrs; /* Update RRs with
 1060                         this name and type */
 1061 
 1062             *typep = type = t->rdata.type;
 1063             if (type == dns_rdatatype_rrsig ||
 1064                 type == dns_rdatatype_sig)
 1065                 covers = dns_rdata_covers(&t->rdata);
 1066             else if (type == dns_rdatatype_any) {
 1067                 dns_db_detachnode(db, &node);
 1068                 dns_diff_clear(&trash);
 1069                 return (DNS_R_NXRRSET);
 1070             } else
 1071                 covers = 0;
 1072 
 1073             /*
 1074              * Collect all database RRs for this name and type
 1075              * onto d_rrs and sort them.
 1076              */
 1077             dns_rdataset_init(&rdataset);
 1078             result = dns_db_findrdataset(db, node, ver, type,
 1079                              covers, (isc_stdtime_t) 0,
 1080                              &rdataset, NULL);
 1081             if (result != ISC_R_SUCCESS) {
 1082                 dns_db_detachnode(db, &node);
 1083                 dns_diff_clear(&trash);
 1084                 return (DNS_R_NXRRSET);
 1085             }
 1086 
 1087             dns_diff_init(mctx, &d_rrs);
 1088             dns_diff_init(mctx, &u_rrs);
 1089 
 1090             for (result = dns_rdataset_first(&rdataset);
 1091                  result == ISC_R_SUCCESS;
 1092                  result = dns_rdataset_next(&rdataset))
 1093             {
 1094                 dns_rdata_t rdata = DNS_RDATA_INIT;
 1095                 dns_rdataset_current(&rdataset, &rdata);
 1096                 result = temp_append(&d_rrs, name, &rdata);
 1097                 if (result != ISC_R_SUCCESS)
 1098                     goto failure;
 1099             }
 1100             if (result != ISC_R_NOMORE)
 1101                 goto failure;
 1102             result = dns_diff_sort(&d_rrs, temp_order);
 1103             if (result != ISC_R_SUCCESS)
 1104                 goto failure;
 1105 
 1106             /*
 1107              * Collect all update RRs for this name and type
 1108              * onto u_rrs.  No need to sort them here -
 1109              * they are already sorted.
 1110              */
 1111             while (t != NULL &&
 1112                    dns_name_equal(&t->name, name) &&
 1113                    t->rdata.type == type)
 1114             {
 1115                 dns_difftuple_t *next =
 1116                     ISC_LIST_NEXT(t, link);
 1117                 ISC_LIST_UNLINK(temp->tuples, t, link);
 1118                 ISC_LIST_APPEND(u_rrs.tuples, t, link);
 1119                 t = next;
 1120             }
 1121 
 1122             /* Compare the two sorted lists. */
 1123             result = temp_check_rrset(ISC_LIST_HEAD(u_rrs.tuples),
 1124                           ISC_LIST_HEAD(d_rrs.tuples));
 1125             if (result != ISC_R_SUCCESS)
 1126                 goto failure;
 1127 
 1128             /*
 1129              * We are done with the tuples, but we can't free
 1130              * them yet because "name" still points into one
 1131              * of them.  Move them on a temporary list.
 1132              */
 1133             ISC_LIST_APPENDLIST(trash.tuples, u_rrs.tuples, link);
 1134             ISC_LIST_APPENDLIST(trash.tuples, d_rrs.tuples, link);
 1135             dns_rdataset_disassociate(&rdataset);
 1136 
 1137             continue;
 1138 
 1139             failure:
 1140             dns_diff_clear(&d_rrs);
 1141             dns_diff_clear(&u_rrs);
 1142             dns_diff_clear(&trash);
 1143             dns_rdataset_disassociate(&rdataset);
 1144             dns_db_detachnode(db, &node);
 1145             return (result);
 1146         }
 1147 
 1148         dns_db_detachnode(db, &node);
 1149     }
 1150 
 1151     dns_diff_clear(&trash);
 1152     return (ISC_R_SUCCESS);
 1153 }
 1154 
 1155 /**************************************************************************/
 1156 /*
 1157  * Conditional deletion of RRs.
 1158  */
 1159 
 1160 /*%
 1161  * Context structure for delete_if().
 1162  */
 1163 
 1164 typedef struct {
 1165     rr_predicate *predicate;
 1166     dns_db_t *db;
 1167     dns_dbversion_t *ver;
 1168     dns_diff_t *diff;
 1169     dns_name_t *name;
 1170     dns_rdata_t *update_rr;
 1171 } conditional_delete_ctx_t;
 1172 
 1173 /*%
 1174  * Predicate functions for delete_if().
 1175  */
 1176 
 1177 /*%
 1178  * Return true iff 'db_rr' is neither a SOA nor an NS RR nor
 1179  * an RRSIG nor an NSEC3PARAM nor a NSEC.
 1180  */
 1181 static bool
 1182 type_not_soa_nor_ns_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
 1183     UNUSED(update_rr);
 1184     return ((db_rr->type != dns_rdatatype_soa &&
 1185          db_rr->type != dns_rdatatype_ns &&
 1186          db_rr->type != dns_rdatatype_nsec3param &&
 1187          db_rr->type != dns_rdatatype_rrsig &&
 1188          db_rr->type != dns_rdatatype_nsec) ?
 1189         true : false);
 1190 }
 1191 
 1192 /*%
 1193  * Return true iff 'db_rr' is neither a RRSIG nor a NSEC.
 1194  */
 1195 static bool
 1196 type_not_dnssec(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
 1197     UNUSED(update_rr);
 1198     return ((db_rr->type != dns_rdatatype_rrsig &&
 1199          db_rr->type != dns_rdatatype_nsec) ?
 1200         true : false);
 1201 }
 1202 
 1203 /*%
 1204  * Return true always.
 1205  */
 1206 static bool
 1207 true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
 1208     UNUSED(update_rr);
 1209     UNUSED(db_rr);
 1210     return (true);
 1211 }
 1212 
 1213 /*%
 1214  * Return true iff the two RRs have identical rdata.
 1215  */
 1216 static bool
 1217 rr_equal_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
 1218     /*
 1219      * XXXRTH  This is not a problem, but we should consider creating
 1220      *         dns_rdata_equal() (that used dns_name_equal()), since it
 1221      *         would be faster.  Not a priority.
 1222      */
 1223     return (dns_rdata_casecompare(update_rr, db_rr) == 0 ?
 1224         true : false);
 1225 }
 1226 
 1227 /*%
 1228  * Return true iff 'update_rr' should replace 'db_rr' according
 1229  * to the special RFC2136 rules for CNAME, SOA, and WKS records.
 1230  *
 1231  * RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
 1232  * make little sense, so we replace those, too.
 1233  *
 1234  * Additionally replace RRSIG that have been generated by the same key
 1235  * for the same type.  This simplifies refreshing a offline KSK by not
 1236  * requiring that the old RRSIG be deleted.  It also simplifies key
 1237  * rollover by only requiring that the new RRSIG be added.
 1238  */
 1239 static bool
 1240 replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
 1241     dns_rdata_rrsig_t updatesig, dbsig;
 1242     isc_result_t result;
 1243 
 1244     if (db_rr->type != update_rr->type)
 1245         return (false);
 1246     if (db_rr->type == dns_rdatatype_cname)
 1247         return (true);
 1248     if (db_rr->type == dns_rdatatype_dname)
 1249         return (true);
 1250     if (db_rr->type == dns_rdatatype_soa)
 1251         return (true);
 1252     if (db_rr->type == dns_rdatatype_nsec)
 1253         return (true);
 1254     if (db_rr->type == dns_rdatatype_rrsig) {
 1255         /*
 1256          * Replace existing RRSIG with the same keyid,
 1257          * covered and algorithm.
 1258          */
 1259         result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
 1260         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 1261         result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
 1262         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 1263         if (dbsig.keyid == updatesig.keyid &&
 1264             dbsig.covered == updatesig.covered &&
 1265             dbsig.algorithm == updatesig.algorithm)
 1266             return (true);
 1267     }
 1268     if (db_rr->type == dns_rdatatype_wks) {
 1269         /*
 1270          * Compare the address and protocol fields only.  These
 1271          * form the first five bytes of the RR data.  Do a
 1272          * raw binary comparison; unpacking the WKS RRs using
 1273          * dns_rdata_tostruct() might be cleaner in some ways.
 1274          */
 1275         INSIST(db_rr->length >= 5 && update_rr->length >= 5);
 1276         return (memcmp(db_rr->data, update_rr->data, 5) == 0 ?
 1277             true : false);
 1278     }
 1279 
 1280     if (db_rr->type == dns_rdatatype_nsec3param) {
 1281         if (db_rr->length != update_rr->length)
 1282             return (false);
 1283         INSIST(db_rr->length >= 4 && update_rr->length >= 4);
 1284         /*
 1285          * Replace NSEC3PARAM records that only differ by the
 1286          * flags field.
 1287          */
 1288         if (db_rr->data[0] == update_rr->data[0] &&
 1289             memcmp(db_rr->data+2, update_rr->data+2,
 1290                update_rr->length - 2) == 0)
 1291             return (true);
 1292     }
 1293     return (false);
 1294 }
 1295 
 1296 /*%
 1297  * Internal helper function for delete_if().
 1298  */
 1299 static isc_result_t
 1300 delete_if_action(void *data, rr_t *rr) {
 1301     conditional_delete_ctx_t *ctx = data;
 1302     if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
 1303         isc_result_t result;
 1304         result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
 1305                        DNS_DIFFOP_DEL, ctx->name,
 1306                        rr->ttl, &rr->rdata);
 1307         return (result);
 1308     } else {
 1309         return (ISC_R_SUCCESS);
 1310     }
 1311 }
 1312 
 1313 /*%
 1314  * Conditionally delete RRs.  Apply 'predicate' to the RRs
 1315  * specified by 'db', 'ver', 'name', and 'type' (which can
 1316  * be dns_rdatatype_any to match any type).  Delete those
 1317  * RRs for which the predicate returns true, and log the
 1318  * deletions in 'diff'.
 1319  */
 1320 static isc_result_t
 1321 delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
 1322       dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
 1323       dns_rdata_t *update_rr, dns_diff_t *diff)
 1324 {
 1325     conditional_delete_ctx_t ctx;
 1326     ctx.predicate = predicate;
 1327     ctx.db = db;
 1328     ctx.ver = ver;
 1329     ctx.diff = diff;
 1330     ctx.name = name;
 1331     ctx.update_rr = update_rr;
 1332     return (foreach_rr(db, ver, name, type, covers,
 1333                delete_if_action, &ctx));
 1334 }
 1335 
 1336 /**************************************************************************/
 1337 
 1338 static isc_result_t
 1339 add_rr_prepare_action(void *data, rr_t *rr) {
 1340     isc_result_t result = ISC_R_SUCCESS;
 1341     add_rr_prepare_ctx_t *ctx = data;
 1342     dns_difftuple_t *tuple = NULL;
 1343     bool equal, case_equal, ttl_equal;
 1344 
 1345     /*
 1346      * Are the new and old cases equal?
 1347      */
 1348     case_equal = dns_name_caseequal(ctx->name, ctx->oldname);
 1349 
 1350     /*
 1351      * Are the ttl's equal?
 1352      */
 1353     ttl_equal = rr->ttl == ctx->update_rr_ttl;
 1354 
 1355     /*
 1356      * If the update RR is a "duplicate" of a existing RR,
 1357      * the update should be silently ignored.
 1358      */
 1359     equal = !dns_rdata_casecompare(&rr->rdata, ctx->update_rr);
 1360     if (equal && case_equal && ttl_equal) {
 1361         ctx->ignore_add = true;
 1362         return (ISC_R_SUCCESS);
 1363     }
 1364 
 1365     /*
 1366      * If this RR is "equal" to the update RR, it should
 1367      * be deleted before the update RR is added.
 1368      */
 1369     if (replaces_p(ctx->update_rr, &rr->rdata)) {
 1370         CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
 1371                        ctx->oldname, rr->ttl, &rr->rdata,
 1372                        &tuple));
 1373         dns_diff_append(&ctx->del_diff, &tuple);
 1374         return (ISC_R_SUCCESS);
 1375     }
 1376 
 1377     /*
 1378      * If this RR differs in TTL or case from the update RR,
 1379      * its TTL and case must be adjusted.
 1380      */
 1381     if (!ttl_equal || !case_equal) {
 1382         CHECK(dns_difftuple_create(ctx->del_diff.mctx, DNS_DIFFOP_DEL,
 1383                        ctx->oldname, rr->ttl, &rr->rdata,
 1384                        &tuple));
 1385         dns_diff_append(&ctx->del_diff, &tuple);
 1386         if (!equal) {
 1387             CHECK(dns_difftuple_create(ctx->add_diff.mctx,
 1388                            DNS_DIFFOP_ADD, ctx->name,
 1389                            ctx->update_rr_ttl,
 1390                            &rr->rdata, &tuple));
 1391             dns_diff_append(&ctx->add_diff, &tuple);
 1392         }
 1393     }
 1394  failure:
 1395     return (result);
 1396 }
 1397 
 1398 /**************************************************************************/
 1399 /*
 1400  * Miscellaneous subroutines.
 1401  */
 1402 
 1403 /*%
 1404  * Extract a single update RR from 'section' of dynamic update message
 1405  * 'msg', with consistency checking.
 1406  *
 1407  * Stores the owner name, rdata, and TTL of the update RR at 'name',
 1408  * 'rdata', and 'ttl', respectively.
 1409  */
 1410 static void
 1411 get_current_rr(dns_message_t *msg, dns_section_t section,
 1412            dns_rdataclass_t zoneclass, dns_name_t **name,
 1413            dns_rdata_t *rdata, dns_rdatatype_t *covers,
 1414            dns_ttl_t *ttl, dns_rdataclass_t *update_class)
 1415 {
 1416     dns_rdataset_t *rdataset;
 1417     isc_result_t result;
 1418     dns_message_currentname(msg, section, name);
 1419     rdataset = ISC_LIST_HEAD((*name)->list);
 1420     INSIST(rdataset != NULL);
 1421     INSIST(ISC_LIST_NEXT(rdataset, link) == NULL);
 1422     *covers = rdataset->covers;
 1423     *ttl = rdataset->ttl;
 1424     result = dns_rdataset_first(rdataset);
 1425     INSIST(result == ISC_R_SUCCESS);
 1426     dns_rdataset_current(rdataset, rdata);
 1427     INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
 1428     *update_class = rdata->rdclass;
 1429     rdata->rdclass = zoneclass;
 1430 }
 1431 
 1432 /*%
 1433  * Increment the SOA serial number of database 'db', version 'ver'.
 1434  * Replace the SOA record in the database, and log the
 1435  * change in 'diff'.
 1436  */
 1437 
 1438     /*
 1439      * XXXRTH  Failures in this routine will be worth logging, when
 1440      *         we have a logging system.  Failure to find the zonename
 1441      *     or the SOA rdataset warrant at least an UNEXPECTED_ERROR().
 1442      */
 1443 
 1444 static isc_result_t
 1445 update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
 1446           isc_mem_t *mctx, dns_updatemethod_t method)
 1447 {
 1448     dns_difftuple_t *deltuple = NULL;
 1449     dns_difftuple_t *addtuple = NULL;
 1450     uint32_t serial;
 1451     isc_result_t result;
 1452 
 1453     CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
 1454     CHECK(dns_difftuple_copy(deltuple, &addtuple));
 1455     addtuple->op = DNS_DIFFOP_ADD;
 1456 
 1457     serial = dns_soa_getserial(&addtuple->rdata);
 1458     serial = dns_update_soaserial(serial, method);
 1459     dns_soa_setserial(serial, &addtuple->rdata);
 1460     CHECK(do_one_tuple(&deltuple, db, ver, diff));
 1461     CHECK(do_one_tuple(&addtuple, db, ver, diff));
 1462     result = ISC_R_SUCCESS;
 1463 
 1464  failure:
 1465     if (addtuple != NULL)
 1466         dns_difftuple_free(&addtuple);
 1467     if (deltuple != NULL)
 1468         dns_difftuple_free(&deltuple);
 1469     return (result);
 1470 }
 1471 
 1472 /*%
 1473  * Check that the new SOA record at 'update_rdata' does not
 1474  * illegally cause the SOA serial number to decrease or stay
 1475  * unchanged relative to the existing SOA in 'db'.
 1476  *
 1477  * Sets '*ok' to true if the update is legal, false if not.
 1478  *
 1479  * William King points out that RFC2136 is inconsistent about
 1480  * the case where the serial number stays unchanged:
 1481  *
 1482  *   section 3.4.2.2 requires a server to ignore a SOA update request
 1483  *   if the serial number on the update SOA is less_than_or_equal to
 1484  *   the zone SOA serial.
 1485  *
 1486  *   section 3.6 requires a server to ignore a SOA update request if
 1487  *   the serial is less_than the zone SOA serial.
 1488  *
 1489  * Paul says 3.4.2.2 is correct.
 1490  *
 1491  */
 1492 static isc_result_t
 1493 check_soa_increment(dns_db_t *db, dns_dbversion_t *ver,
 1494             dns_rdata_t *update_rdata, bool *ok)
 1495 {
 1496     uint32_t db_serial;
 1497     uint32_t update_serial;
 1498     isc_result_t result;
 1499 
 1500     update_serial = dns_soa_getserial(update_rdata);
 1501 
 1502     result = dns_db_getsoaserial(db, ver, &db_serial);
 1503     if (result != ISC_R_SUCCESS)
 1504         return (result);
 1505 
 1506     if (DNS_SERIAL_GE(db_serial, update_serial)) {
 1507         *ok = false;
 1508     } else {
 1509         *ok = true;
 1510     }
 1511 
 1512     return (ISC_R_SUCCESS);
 1513 
 1514 }
 1515 
 1516 /**************************************************************************/
 1517 /*%
 1518  * The actual update code in all its glory.  We try to follow
 1519  * the RFC2136 pseudocode as closely as possible.
 1520  */
 1521 
 1522 static isc_result_t
 1523 send_update_event(ns_client_t *client, dns_zone_t *zone) {
 1524     isc_result_t result = ISC_R_SUCCESS;
 1525     update_event_t *event = NULL;
 1526     isc_task_t *zonetask = NULL;
 1527     ns_client_t *evclient;
 1528 
 1529     event = (update_event_t *)
 1530         isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
 1531                    update_action, NULL, sizeof(*event));
 1532     if (event == NULL)
 1533         FAIL(ISC_R_NOMEMORY);
 1534     event->zone = zone;
 1535     event->result = ISC_R_SUCCESS;
 1536 
 1537     evclient = NULL;
 1538     ns_client_attach(client, &evclient);
 1539     INSIST(client->nupdates == 0);
 1540     client->nupdates++;
 1541     event->ev_arg = evclient;
 1542 
 1543     dns_zone_gettask(zone, &zonetask);
 1544     isc_task_send(zonetask, ISC_EVENT_PTR(&event));
 1545 
 1546  failure:
 1547     if (event != NULL)
 1548         isc_event_free(ISC_EVENT_PTR(&event));
 1549     return (result);
 1550 }
 1551 
 1552 static void
 1553 respond(ns_client_t *client, isc_result_t result) {
 1554     isc_result_t msg_result;
 1555 
 1556     msg_result = dns_message_reply(client->message, true);
 1557     if (msg_result != ISC_R_SUCCESS)
 1558         goto msg_failure;
 1559     client->message->rcode = dns_result_torcode(result);
 1560 
 1561     ns_client_send(client);
 1562     return;
 1563 
 1564  msg_failure:
 1565     isc_log_write(ns_g_lctx, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
 1566               ISC_LOG_ERROR,
 1567               "could not create update response message: %s",
 1568               isc_result_totext(msg_result));
 1569     ns_client_next(client, msg_result);
 1570 }
 1571 
 1572 void
 1573 ns_update_start(ns_client_t *client, isc_result_t sigresult) {
 1574     dns_message_t *request = client->message;
 1575     isc_result_t result;
 1576     dns_name_t *zonename;
 1577     dns_rdataset_t *zone_rdataset;
 1578     dns_zone_t *zone = NULL, *raw = NULL;
 1579 
 1580     /*
 1581      * Interpret the zone section.
 1582      */
 1583     result = dns_message_firstname(request, DNS_SECTION_ZONE);
 1584     if (result != ISC_R_SUCCESS)
 1585         FAILC(DNS_R_FORMERR, "update zone section empty");
 1586 
 1587     /*
 1588      * The zone section must contain exactly one "question", and
 1589      * it must be of type SOA.
 1590      */
 1591     zonename = NULL;
 1592     dns_message_currentname(request, DNS_SECTION_ZONE, &zonename);
 1593     zone_rdataset = ISC_LIST_HEAD(zonename->list);
 1594     if (zone_rdataset->type != dns_rdatatype_soa)
 1595         FAILC(DNS_R_FORMERR,
 1596               "update zone section contains non-SOA");
 1597     if (ISC_LIST_NEXT(zone_rdataset, link) != NULL)
 1598         FAILC(DNS_R_FORMERR,
 1599               "update zone section contains multiple RRs");
 1600 
 1601     /* The zone section must have exactly one name. */
 1602     result = dns_message_nextname(request, DNS_SECTION_ZONE);
 1603     if (result != ISC_R_NOMORE)
 1604         FAILC(DNS_R_FORMERR,
 1605               "update zone section contains multiple RRs");
 1606 
 1607     result = dns_zt_find(client->view->zonetable, zonename, 0, NULL,
 1608                  &zone);
 1609     if (result != ISC_R_SUCCESS)
 1610         FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
 1611 
 1612     /*
 1613      * If there is a raw (unsigned) zone associated with this
 1614      * zone then it processes the UPDATE request.
 1615      */
 1616     dns_zone_getraw(zone, &raw);
 1617     if (raw != NULL) {
 1618         dns_zone_detach(&zone);
 1619         dns_zone_attach(raw, &zone);
 1620         dns_zone_detach(&raw);
 1621     }
 1622 
 1623     switch(dns_zone_gettype(zone)) {
 1624     case dns_zone_master:
 1625     case dns_zone_dlz:
 1626         /*
 1627          * We can now fail due to a bad signature as we now know
 1628          * that we are the master.
 1629          */
 1630         if (sigresult != ISC_R_SUCCESS)
 1631             FAIL(sigresult);
 1632         CHECK(send_update_event(client, zone));
 1633         break;
 1634     case dns_zone_slave:
 1635         CHECK(checkupdateacl(client, dns_zone_getforwardacl(zone),
 1636                      "update forwarding", zonename, true,
 1637                      false));
 1638         CHECK(send_forward_event(client, zone));
 1639         break;
 1640     default:
 1641         FAILC(DNS_R_NOTAUTH, "not authoritative for update zone");
 1642     }
 1643     return;
 1644 
 1645  failure:
 1646     if (result == DNS_R_REFUSED) {
 1647         INSIST(dns_zone_gettype(zone) == dns_zone_slave);
 1648         inc_stats(zone, dns_nsstatscounter_updaterej);
 1649     }
 1650     /*
 1651      * We failed without having sent an update event to the zone.
 1652      * We are still in the client task context, so we can
 1653      * simply give an error response without switching tasks.
 1654      */
 1655     respond(client, result);
 1656     if (zone != NULL)
 1657         dns_zone_detach(&zone);
 1658 }
 1659 
 1660 /*%
 1661  * DS records are not allowed to exist without corresponding NS records,
 1662  * RFC 3658, 2.2 Protocol Change,
 1663  * "DS RRsets MUST NOT appear at non-delegation points or at a zone's apex".
 1664  */
 1665 
 1666 static isc_result_t
 1667 remove_orphaned_ds(dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff) {
 1668     isc_result_t result;
 1669     bool ns_exists;
 1670     dns_difftuple_t *tupple;
 1671     dns_diff_t temp_diff;
 1672 
 1673     dns_diff_init(diff->mctx, &temp_diff);
 1674 
 1675     for (tupple = ISC_LIST_HEAD(diff->tuples);
 1676          tupple != NULL;
 1677          tupple = ISC_LIST_NEXT(tupple, link)) {
 1678         if (!((tupple->op == DNS_DIFFOP_DEL &&
 1679                tupple->rdata.type == dns_rdatatype_ns) ||
 1680               (tupple->op == DNS_DIFFOP_ADD &&
 1681                tupple->rdata.type == dns_rdatatype_ds)))
 1682             continue;
 1683         CHECK(rrset_exists(db, newver, &tupple->name,
 1684                    dns_rdatatype_ns, 0, &ns_exists));
 1685         if (ns_exists &&
 1686             !dns_name_equal(&tupple->name, dns_db_origin(db)))
 1687             continue;
 1688         CHECK(delete_if(true_p, db, newver, &tupple->name,
 1689                 dns_rdatatype_ds, 0, NULL, &temp_diff));
 1690     }
 1691     result = ISC_R_SUCCESS;
 1692 
 1693  failure:
 1694     for (tupple = ISC_LIST_HEAD(temp_diff.tuples);
 1695          tupple != NULL;
 1696          tupple = ISC_LIST_HEAD(temp_diff.tuples)) {
 1697         ISC_LIST_UNLINK(temp_diff.tuples, tupple, link);
 1698         dns_diff_appendminimal(diff, &tupple);
 1699     }
 1700     return (result);
 1701 }
 1702 
 1703 /*
 1704  * This implements the post load integrity checks for mx records.
 1705  */
 1706 static isc_result_t
 1707 check_mx(ns_client_t *client, dns_zone_t *zone,
 1708      dns_db_t *db, dns_dbversion_t *newver, dns_diff_t *diff)
 1709 {
 1710     char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:123.123.123.123.")];
 1711     char ownerbuf[DNS_NAME_FORMATSIZE];
 1712     char namebuf[DNS_NAME_FORMATSIZE];
 1713     char altbuf[DNS_NAME_FORMATSIZE];
 1714     dns_difftuple_t *t;
 1715     dns_fixedname_t fixed;
 1716     dns_name_t *foundname;
 1717     dns_rdata_mx_t mx;
 1718     dns_rdata_t rdata;
 1719     bool ok = true;
 1720     bool isaddress;
 1721     isc_result_t result;
 1722     struct in6_addr addr6;
 1723     struct in_addr addr;
 1724     unsigned int options;
 1725 
 1726     foundname = dns_fixedname_initname(&fixed);
 1727     dns_rdata_init(&rdata);
 1728     options = dns_zone_getoptions(zone);
 1729 
 1730     for (t = ISC_LIST_HEAD(diff->tuples);
 1731          t != NULL;
 1732          t = ISC_LIST_NEXT(t, link)) {
 1733         if (t->op != DNS_DIFFOP_ADD ||
 1734             t->rdata.type != dns_rdatatype_mx)
 1735             continue;
 1736 
 1737         result = dns_rdata_tostruct(&t->rdata, &mx, NULL);
 1738         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 1739         /*
 1740          * Check if we will error out if we attempt to reload the
 1741          * zone.
 1742          */
 1743         dns_name_format(&mx.mx, namebuf, sizeof(namebuf));
 1744         dns_name_format(&t->name, ownerbuf, sizeof(ownerbuf));
 1745         isaddress = false;
 1746         if ((options & DNS_ZONEOPT_CHECKMX) != 0 &&
 1747             strlcpy(tmp, namebuf, sizeof(tmp)) < sizeof(tmp)) {
 1748             if (tmp[strlen(tmp) - 1] == '.')
 1749                 tmp[strlen(tmp) - 1] = '\0';
 1750             if (inet_aton(tmp, &addr) == 1 ||
 1751                 inet_pton(AF_INET6, tmp, &addr6) == 1)
 1752                 isaddress = true;
 1753         }
 1754 
 1755         if (isaddress && (options & DNS_ZONEOPT_CHECKMXFAIL) != 0) {
 1756             update_log(client, zone, ISC_LOG_ERROR,
 1757                    "%s/MX: '%s': %s",
 1758                    ownerbuf, namebuf,
 1759                    dns_result_totext(DNS_R_MXISADDRESS));
 1760             ok = false;
 1761         } else if (isaddress) {
 1762             update_log(client, zone, ISC_LOG_WARNING,
 1763                    "%s/MX: warning: '%s': %s",
 1764                    ownerbuf, namebuf,
 1765                    dns_result_totext(DNS_R_MXISADDRESS));
 1766         }
 1767 
 1768         /*
 1769          * Check zone integrity checks.
 1770          */
 1771         if ((options & DNS_ZONEOPT_CHECKINTEGRITY) == 0)
 1772             continue;
 1773         result = dns_db_find(db, &mx.mx, newver, dns_rdatatype_a,
 1774                      0, 0, NULL, foundname, NULL, NULL);
 1775         if (result == ISC_R_SUCCESS)
 1776             continue;
 1777 
 1778         if (result == DNS_R_NXRRSET) {
 1779             result = dns_db_find(db, &mx.mx, newver,
 1780                          dns_rdatatype_aaaa,
 1781                          0, 0, NULL, foundname,
 1782                          NULL, NULL);
 1783             if (result == ISC_R_SUCCESS)
 1784                 continue;
 1785         }
 1786 
 1787         if (result == DNS_R_NXRRSET || result == DNS_R_NXDOMAIN) {
 1788             update_log(client, zone, ISC_LOG_ERROR,
 1789                    "%s/MX '%s' has no address records "
 1790                    "(A or AAAA)", ownerbuf, namebuf);
 1791             ok = false;
 1792         } else if (result == DNS_R_CNAME) {
 1793             update_log(client, zone, ISC_LOG_ERROR,
 1794                    "%s/MX '%s' is a CNAME (illegal)",
 1795                    ownerbuf, namebuf);
 1796             ok = false;
 1797         } else if (result == DNS_R_DNAME) {
 1798             dns_name_format(foundname, altbuf, sizeof altbuf);
 1799             update_log(client, zone, ISC_LOG_ERROR,
 1800                    "%s/MX '%s' is below a DNAME '%s' (illegal)",
 1801                    ownerbuf, namebuf, altbuf);
 1802             ok = false;
 1803         }
 1804     }
 1805     return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
 1806 }
 1807 
 1808 static isc_result_t
 1809 rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
 1810       const dns_rdata_t *rdata, bool *flag)
 1811 {
 1812     dns_rdataset_t rdataset;
 1813     dns_dbnode_t *node = NULL;
 1814     isc_result_t result;
 1815 
 1816     dns_rdataset_init(&rdataset);
 1817     if (rdata->type == dns_rdatatype_nsec3)
 1818         CHECK(dns_db_findnsec3node(db, name, false, &node));
 1819     else
 1820         CHECK(dns_db_findnode(db, name, false, &node));
 1821     result = dns_db_findrdataset(db, node, ver, rdata->type, 0,
 1822                      (isc_stdtime_t) 0, &rdataset, NULL);
 1823     if (result == ISC_R_NOTFOUND) {
 1824         *flag = false;
 1825         result = ISC_R_SUCCESS;
 1826         goto failure;
 1827     }
 1828 
 1829     for (result = dns_rdataset_first(&rdataset);
 1830          result == ISC_R_SUCCESS;
 1831          result = dns_rdataset_next(&rdataset)) {
 1832         dns_rdata_t myrdata = DNS_RDATA_INIT;
 1833         dns_rdataset_current(&rdataset, &myrdata);
 1834         if (!dns_rdata_casecompare(&myrdata, rdata))
 1835             break;
 1836     }
 1837     dns_rdataset_disassociate(&rdataset);
 1838     if (result == ISC_R_SUCCESS) {
 1839         *flag = true;
 1840     } else if (result == ISC_R_NOMORE) {
 1841         *flag = false;
 1842         result = ISC_R_SUCCESS;
 1843     }
 1844 
 1845  failure:
 1846     if (node != NULL)
 1847         dns_db_detachnode(db, &node);
 1848     return (result);
 1849 }
 1850 
 1851 static isc_result_t
 1852 get_iterations(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype,
 1853            unsigned int *iterationsp)
 1854 {
 1855     dns_dbnode_t *node = NULL;
 1856     dns_rdata_nsec3param_t nsec3param;
 1857     dns_rdataset_t rdataset;
 1858     isc_result_t result;
 1859     unsigned int iterations = 0;
 1860 
 1861     dns_rdataset_init(&rdataset);
 1862 
 1863     result = dns_db_getoriginnode(db, &node);
 1864     if (result != ISC_R_SUCCESS)
 1865         return (result);
 1866     result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param,
 1867                      0, (isc_stdtime_t) 0, &rdataset, NULL);
 1868     if (result == ISC_R_NOTFOUND)
 1869         goto try_private;
 1870     if (result != ISC_R_SUCCESS)
 1871         goto failure;
 1872 
 1873     for (result = dns_rdataset_first(&rdataset);
 1874          result == ISC_R_SUCCESS;
 1875          result = dns_rdataset_next(&rdataset)) {
 1876         dns_rdata_t rdata = DNS_RDATA_INIT;
 1877         dns_rdataset_current(&rdataset, &rdata);
 1878         CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
 1879         if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
 1880             continue;
 1881         if (nsec3param.iterations > iterations)
 1882             iterations = nsec3param.iterations;
 1883     }
 1884     if (result != ISC_R_NOMORE)
 1885         goto failure;
 1886 
 1887     dns_rdataset_disassociate(&rdataset);
 1888 
 1889  try_private:
 1890     if (privatetype == 0)
 1891         goto success;
 1892 
 1893     result = dns_db_findrdataset(db, node, ver, privatetype,
 1894                      0, (isc_stdtime_t) 0, &rdataset, NULL);
 1895     if (result == ISC_R_NOTFOUND)
 1896         goto success;
 1897     if (result != ISC_R_SUCCESS)
 1898         goto failure;
 1899 
 1900     for (result = dns_rdataset_first(&rdataset);
 1901          result == ISC_R_SUCCESS;
 1902          result = dns_rdataset_next(&rdataset)) {
 1903         unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
 1904         dns_rdata_t private = DNS_RDATA_INIT;
 1905         dns_rdata_t rdata = DNS_RDATA_INIT;
 1906 
 1907         dns_rdataset_current(&rdataset, &rdata);
 1908         if (!dns_nsec3param_fromprivate(&private, &rdata,
 1909                         buf, sizeof(buf)))
 1910             continue;
 1911         CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
 1912         if ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0)
 1913             continue;
 1914         if (nsec3param.iterations > iterations)
 1915             iterations = nsec3param.iterations;
 1916     }
 1917     if (result != ISC_R_NOMORE)
 1918         goto failure;
 1919 
 1920  success:
 1921     *iterationsp = iterations;
 1922     result = ISC_R_SUCCESS;
 1923 
 1924  failure:
 1925     if (node != NULL)
 1926         dns_db_detachnode(db, &node);
 1927     if (dns_rdataset_isassociated(&rdataset))
 1928         dns_rdataset_disassociate(&rdataset);
 1929     return (result);
 1930 }
 1931 
 1932 /*
 1933  * Prevent the zone entering a inconsistent state where
 1934  * NSEC only DNSKEYs are present with NSEC3 chains.
 1935  */
 1936 static isc_result_t
 1937 check_dnssec(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
 1938          dns_dbversion_t *ver, dns_diff_t *diff)
 1939 {
 1940     dns_difftuple_t *tuple;
 1941     bool nseconly = false, nsec3 = false;
 1942     isc_result_t result;
 1943     unsigned int iterations = 0, max;
 1944     dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 1945 
 1946     /* Scan the tuples for an NSEC-only DNSKEY or an NSEC3PARAM */
 1947     for (tuple = ISC_LIST_HEAD(diff->tuples);
 1948          tuple != NULL;
 1949          tuple = ISC_LIST_NEXT(tuple, link)) {
 1950         if (tuple->op != DNS_DIFFOP_ADD)
 1951             continue;
 1952 
 1953         if (tuple->rdata.type == dns_rdatatype_dnskey) {
 1954             uint8_t alg;
 1955             alg = tuple->rdata.data[3];
 1956             if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 ||
 1957                 alg == DST_ALG_DSA || alg == DST_ALG_ECC) {
 1958                 nseconly = true;
 1959                 break;
 1960             }
 1961         } else if (tuple->rdata.type == dns_rdatatype_nsec3param) {
 1962             nsec3 = true;
 1963             break;
 1964         }
 1965     }
 1966 
 1967     /* Check existing DB for NSEC-only DNSKEY */
 1968     if (!nseconly) {
 1969         result = dns_nsec_nseconly(db, ver, &nseconly);
 1970 
 1971         /*
 1972          * An NSEC3PARAM update can proceed without a DNSKEY (it
 1973          * will trigger a delayed change), so we can ignore
 1974          * ISC_R_NOTFOUND here.
 1975          */
 1976         if (result == ISC_R_NOTFOUND)
 1977             result = ISC_R_SUCCESS;
 1978 
 1979         CHECK(result);
 1980     }
 1981 
 1982     /* Check existing DB for NSEC3 */
 1983     if (!nsec3)
 1984         CHECK(dns_nsec3_activex(db, ver, false,
 1985                     privatetype, &nsec3));
 1986 
 1987     /* Refuse to allow NSEC3 with NSEC-only keys */
 1988     if (nseconly && nsec3) {
 1989         update_log(client, zone, ISC_LOG_ERROR,
 1990                "NSEC only DNSKEYs and NSEC3 chains not allowed");
 1991         result = DNS_R_REFUSED;
 1992         goto failure;
 1993     }
 1994 
 1995     /* Verify NSEC3 params */
 1996     CHECK(get_iterations(db, ver, privatetype, &iterations));
 1997     CHECK(dns_nsec3_maxiterations(db, ver, client->mctx, &max));
 1998     if (max != 0 && iterations > max) {
 1999         update_log(client, zone, ISC_LOG_ERROR,
 2000                "too many NSEC3 iterations (%u) for "
 2001                "weakest DNSKEY (%u)", iterations, max);
 2002         result = DNS_R_REFUSED;
 2003         goto failure;
 2004     }
 2005 
 2006  failure:
 2007     return (result);
 2008 }
 2009 
 2010 /*
 2011  * Delay NSEC3PARAM changes as they need to be applied to the whole zone.
 2012  */
 2013 static isc_result_t
 2014 add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
 2015                dns_dbversion_t *ver, dns_diff_t *diff)
 2016 {
 2017     isc_result_t result = ISC_R_SUCCESS;
 2018     dns_difftuple_t *tuple, *newtuple = NULL, *next;
 2019     dns_rdata_t rdata = DNS_RDATA_INIT;
 2020     unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1];
 2021     dns_diff_t temp_diff;
 2022     dns_diffop_t op;
 2023     bool flag;
 2024     dns_name_t *name = dns_zone_getorigin(zone);
 2025     dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 2026     uint32_t ttl = 0;
 2027     bool ttl_good = false;
 2028 
 2029     update_log(client, zone, ISC_LOG_DEBUG(3),
 2030             "checking for NSEC3PARAM changes");
 2031 
 2032     dns_diff_init(diff->mctx, &temp_diff);
 2033 
 2034     /*
 2035      * Extract NSEC3PARAM tuples from list.
 2036      */
 2037     for (tuple = ISC_LIST_HEAD(diff->tuples);
 2038          tuple != NULL;
 2039          tuple = next) {
 2040 
 2041         next = ISC_LIST_NEXT(tuple, link);
 2042 
 2043         if (tuple->rdata.type != dns_rdatatype_nsec3param ||
 2044             !dns_name_equal(name, &tuple->name))
 2045             continue;
 2046         ISC_LIST_UNLINK(diff->tuples, tuple, link);
 2047         ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
 2048     }
 2049 
 2050     /*
 2051      * Extract TTL changes pairs, we don't need to convert these to
 2052      * delayed changes.
 2053      */
 2054     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2055          tuple != NULL; tuple = next) {
 2056         if (tuple->op == DNS_DIFFOP_ADD) {
 2057             if (!ttl_good) {
 2058                 /*
 2059                  * Any adds here will contain the final
 2060                  * NSEC3PARAM RRset TTL.
 2061                  */
 2062                 ttl = tuple->ttl;
 2063                 ttl_good = true;
 2064             }
 2065             /*
 2066              * Walk the temp_diff list looking for the
 2067              * corresponding delete.
 2068              */
 2069             next = ISC_LIST_HEAD(temp_diff.tuples);
 2070             while (next != NULL) {
 2071                 unsigned char *next_data = next->rdata.data;
 2072                 unsigned char *tuple_data = tuple->rdata.data;
 2073                 if (next->op == DNS_DIFFOP_DEL &&
 2074                     next->rdata.length == tuple->rdata.length &&
 2075                     !memcmp(next_data, tuple_data,
 2076                         next->rdata.length)) {
 2077                     ISC_LIST_UNLINK(temp_diff.tuples, next,
 2078                             link);
 2079                     ISC_LIST_APPEND(diff->tuples, next,
 2080                             link);
 2081                     break;
 2082                 }
 2083                 next = ISC_LIST_NEXT(next, link);
 2084             }
 2085             /*
 2086              * If we have not found a pair move onto the next
 2087              * tuple.
 2088              */
 2089             if (next == NULL) {
 2090                 next = ISC_LIST_NEXT(tuple, link);
 2091                 continue;
 2092             }
 2093             /*
 2094              * Find the next tuple to be processed before
 2095              * unlinking then complete moving the pair to 'diff'.
 2096              */
 2097             next = ISC_LIST_NEXT(tuple, link);
 2098             ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2099             ISC_LIST_APPEND(diff->tuples, tuple, link);
 2100         } else
 2101             next = ISC_LIST_NEXT(tuple, link);
 2102     }
 2103 
 2104     /*
 2105      * Preserve any ongoing changes from a BIND 9.6.x upgrade.
 2106      *
 2107      * Any NSEC3PARAM records with flags other than OPTOUT named
 2108      * in managing and should not be touched so revert such changes
 2109      * taking into account any TTL change of the NSEC3PARAM RRset.
 2110      */
 2111     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2112          tuple != NULL; tuple = next) {
 2113         next = ISC_LIST_NEXT(tuple, link);
 2114         if ((tuple->rdata.data[1] & ~DNS_NSEC3FLAG_OPTOUT) != 0) {
 2115             /*
 2116              * If we haven't had any adds then the tuple->ttl must
 2117              * be the original ttl and should be used for any
 2118              * future changes.
 2119              */
 2120             if (!ttl_good) {
 2121                 ttl = tuple->ttl;
 2122                 ttl_good = true;
 2123             }
 2124             op = (tuple->op == DNS_DIFFOP_DEL) ?
 2125                  DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
 2126             CHECK(dns_difftuple_create(diff->mctx, op, name,
 2127                            ttl, &tuple->rdata,
 2128                            &newtuple));
 2129             CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2130             ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2131             dns_diff_appendminimal(diff, &tuple);
 2132         }
 2133     }
 2134 
 2135     /*
 2136      * We now have just the actual changes to the NSEC3PARAM RRset.
 2137      * Convert the adds to delayed adds and the deletions into delayed
 2138      * deletions.
 2139      */
 2140     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2141          tuple != NULL; tuple = next) {
 2142         /*
 2143          * If we haven't had any adds then the tuple->ttl must be the
 2144          * original ttl and should be used for any future changes.
 2145          */
 2146         if (!ttl_good) {
 2147             ttl = tuple->ttl;
 2148             ttl_good = true;
 2149         }
 2150         if (tuple->op == DNS_DIFFOP_ADD) {
 2151             bool nseconly = false;
 2152 
 2153             /*
 2154              * Look for any deletes which match this ADD ignoring
 2155              * flags.  We don't need to explicitly remove them as
 2156              * they will be removed a side effect of processing
 2157              * the add.
 2158              */
 2159             next = ISC_LIST_HEAD(temp_diff.tuples);
 2160             while (next != NULL) {
 2161                 unsigned char *next_data = next->rdata.data;
 2162                 unsigned char *tuple_data = tuple->rdata.data;
 2163                 if (next->op != DNS_DIFFOP_DEL ||
 2164                     next->rdata.length != tuple->rdata.length ||
 2165                     next_data[0] != tuple_data[0] ||
 2166                     next_data[2] != tuple_data[2] ||
 2167                     next_data[3] != tuple_data[3] ||
 2168                     memcmp(next_data + 4, tuple_data + 4,
 2169                        tuple->rdata.length - 4)) {
 2170                     next = ISC_LIST_NEXT(next, link);
 2171                     continue;
 2172                 }
 2173                 ISC_LIST_UNLINK(temp_diff.tuples, next, link);
 2174                 ISC_LIST_APPEND(diff->tuples, next, link);
 2175                 next = ISC_LIST_HEAD(temp_diff.tuples);
 2176             }
 2177 
 2178             /*
 2179              * Create a private-type record to signal that
 2180              * we want a delayed NSEC3 chain add/delete
 2181              */
 2182             dns_nsec3param_toprivate(&tuple->rdata, &rdata,
 2183                          privatetype, buf, sizeof(buf));
 2184             buf[2] |= DNS_NSEC3FLAG_CREATE;
 2185 
 2186             /*
 2187              * If the zone is not currently capable of
 2188              * supporting an NSEC3 chain, then we set the
 2189              * INITIAL flag to indicate that these parameters
 2190              * are to be used later.
 2191              */
 2192             result = dns_nsec_nseconly(db, ver, &nseconly);
 2193             if (result == ISC_R_NOTFOUND || nseconly)
 2194                 buf[2] |= DNS_NSEC3FLAG_INITIAL;
 2195 
 2196             /*
 2197              * See if this CREATE request already exists.
 2198              */
 2199             CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2200 
 2201             if (!flag) {
 2202                 CHECK(dns_difftuple_create(diff->mctx,
 2203                                DNS_DIFFOP_ADD,
 2204                                name, 0, &rdata,
 2205                                &newtuple));
 2206                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2207             }
 2208 
 2209             /*
 2210              * Remove any existing CREATE request to add an
 2211              * otherwise identical chain with a reversed
 2212              * OPTOUT state.
 2213              */
 2214             buf[2] ^= DNS_NSEC3FLAG_OPTOUT;
 2215             CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2216 
 2217             if (flag) {
 2218                 CHECK(dns_difftuple_create(diff->mctx,
 2219                                DNS_DIFFOP_DEL,
 2220                                name, 0, &rdata,
 2221                                &newtuple));
 2222                 CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2223             }
 2224 
 2225             /*
 2226              * Find the next tuple to be processed and remove the
 2227              * temporary add record.
 2228              */
 2229             next = ISC_LIST_NEXT(tuple, link);
 2230             CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
 2231                            name, ttl, &tuple->rdata,
 2232                            &newtuple));
 2233             CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2234             ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2235             dns_diff_appendminimal(diff, &tuple);
 2236             dns_rdata_reset(&rdata);
 2237         } else
 2238             next = ISC_LIST_NEXT(tuple, link);
 2239     }
 2240 
 2241     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2242          tuple != NULL; tuple = next) {
 2243 
 2244         INSIST(ttl_good);
 2245 
 2246         next = ISC_LIST_NEXT(tuple, link);
 2247         /*
 2248          * See if we already have a REMOVE request in progress.
 2249          */
 2250         dns_nsec3param_toprivate(&tuple->rdata, &rdata, privatetype,
 2251                      buf, sizeof(buf));
 2252 
 2253         buf[2] |= DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
 2254 
 2255         CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2256         if (!flag) {
 2257             buf[2] &= ~DNS_NSEC3FLAG_NONSEC;
 2258             CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2259         }
 2260 
 2261         if (!flag) {
 2262             CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
 2263                            name, 0, &rdata, &newtuple));
 2264             CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2265         }
 2266         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
 2267                        ttl, &tuple->rdata, &newtuple));
 2268         CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2269         ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2270         dns_diff_appendminimal(diff, &tuple);
 2271         dns_rdata_reset(&rdata);
 2272     }
 2273 
 2274     result = ISC_R_SUCCESS;
 2275  failure:
 2276     dns_diff_clear(&temp_diff);
 2277     return (result);
 2278 }
 2279 
 2280 static isc_result_t
 2281 rollback_private(dns_db_t *db, dns_rdatatype_t privatetype,
 2282          dns_dbversion_t *ver, dns_diff_t *diff)
 2283 {
 2284     dns_diff_t temp_diff;
 2285     dns_diffop_t op;
 2286     dns_difftuple_t *tuple, *newtuple = NULL, *next;
 2287     dns_name_t *name = dns_db_origin(db);
 2288     isc_mem_t *mctx = diff->mctx;
 2289     isc_result_t result;
 2290 
 2291     if (privatetype == 0)
 2292         return (ISC_R_SUCCESS);
 2293 
 2294     dns_diff_init(mctx, &temp_diff);
 2295 
 2296     /*
 2297      * Extract the changes to be rolled back.
 2298      */
 2299     for (tuple = ISC_LIST_HEAD(diff->tuples);
 2300          tuple != NULL; tuple = next) {
 2301 
 2302         next = ISC_LIST_NEXT(tuple, link);
 2303 
 2304         if (tuple->rdata.type != privatetype ||
 2305             !dns_name_equal(name, &tuple->name))
 2306             continue;
 2307 
 2308         /*
 2309          * Allow records which indicate that a zone has been
 2310          * signed with a DNSKEY to be removed.
 2311          */
 2312         if (tuple->op == DNS_DIFFOP_DEL &&
 2313             tuple->rdata.length == 5 &&
 2314             tuple->rdata.data[0] != 0 &&
 2315             tuple->rdata.data[4] != 0)
 2316             continue;
 2317 
 2318         ISC_LIST_UNLINK(diff->tuples, tuple, link);
 2319         ISC_LIST_PREPEND(temp_diff.tuples, tuple, link);
 2320     }
 2321 
 2322     /*
 2323      * Rollback the changes.
 2324      */
 2325     while ((tuple = ISC_LIST_HEAD(temp_diff.tuples)) != NULL) {
 2326         op = (tuple->op == DNS_DIFFOP_DEL) ?
 2327               DNS_DIFFOP_ADD : DNS_DIFFOP_DEL;
 2328         CHECK(dns_difftuple_create(mctx, op, name, tuple->ttl,
 2329                        &tuple->rdata, &newtuple));
 2330         CHECK(do_one_tuple(&newtuple, db, ver, &temp_diff));
 2331     }
 2332     result = ISC_R_SUCCESS;
 2333 
 2334  failure:
 2335     dns_diff_clear(&temp_diff);
 2336     return (result);
 2337 }
 2338 
 2339 /*
 2340  * Add records to cause the delayed signing of the zone by added DNSKEY
 2341  * to remove the RRSIG records generated by a deleted DNSKEY.
 2342  */
 2343 static isc_result_t
 2344 add_signing_records(dns_db_t *db, dns_rdatatype_t privatetype,
 2345             dns_dbversion_t *ver, dns_diff_t *diff)
 2346 {
 2347     dns_difftuple_t *tuple, *newtuple = NULL, *next;
 2348     dns_rdata_dnskey_t dnskey;
 2349     dns_rdata_t rdata = DNS_RDATA_INIT;
 2350     bool flag;
 2351     isc_region_t r;
 2352     isc_result_t result = ISC_R_SUCCESS;
 2353     uint16_t keyid;
 2354     unsigned char buf[5];
 2355     dns_name_t *name = dns_db_origin(db);
 2356     dns_diff_t temp_diff;
 2357 
 2358     dns_diff_init(diff->mctx, &temp_diff);
 2359 
 2360     /*
 2361      * Extract the DNSKEY tuples from the list.
 2362      */
 2363     for (tuple = ISC_LIST_HEAD(diff->tuples);
 2364          tuple != NULL; tuple = next) {
 2365 
 2366         next = ISC_LIST_NEXT(tuple, link);
 2367 
 2368         if (tuple->rdata.type != dns_rdatatype_dnskey)
 2369             continue;
 2370 
 2371         ISC_LIST_UNLINK(diff->tuples, tuple, link);
 2372         ISC_LIST_APPEND(temp_diff.tuples, tuple, link);
 2373     }
 2374 
 2375     /*
 2376      * Extract TTL changes pairs, we don't need signing records for these.
 2377      */
 2378     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2379          tuple != NULL; tuple = next) {
 2380         if (tuple->op == DNS_DIFFOP_ADD) {
 2381             /*
 2382              * Walk the temp_diff list looking for the
 2383              * corresponding delete.
 2384              */
 2385             next = ISC_LIST_HEAD(temp_diff.tuples);
 2386             while (next != NULL) {
 2387                 unsigned char *next_data = next->rdata.data;
 2388                 unsigned char *tuple_data = tuple->rdata.data;
 2389                 if (next->op == DNS_DIFFOP_DEL &&
 2390                     dns_name_equal(&tuple->name, &next->name) &&
 2391                     next->rdata.length == tuple->rdata.length &&
 2392                     !memcmp(next_data, tuple_data,
 2393                         next->rdata.length)) {
 2394                     ISC_LIST_UNLINK(temp_diff.tuples, next,
 2395                             link);
 2396                     ISC_LIST_APPEND(diff->tuples, next,
 2397                             link);
 2398                     break;
 2399                 }
 2400                 next = ISC_LIST_NEXT(next, link);
 2401             }
 2402             /*
 2403              * If we have not found a pair move onto the next
 2404              * tuple.
 2405              */
 2406             if (next == NULL) {
 2407                 next = ISC_LIST_NEXT(tuple, link);
 2408                 continue;
 2409             }
 2410             /*
 2411              * Find the next tuple to be processed before
 2412              * unlinking then complete moving the pair to 'diff'.
 2413              */
 2414             next = ISC_LIST_NEXT(tuple, link);
 2415             ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2416             ISC_LIST_APPEND(diff->tuples, tuple, link);
 2417         } else
 2418             next = ISC_LIST_NEXT(tuple, link);
 2419     }
 2420 
 2421     /*
 2422      * Process the remaining DNSKEY entries.
 2423      */
 2424     for (tuple = ISC_LIST_HEAD(temp_diff.tuples);
 2425          tuple != NULL;
 2426          tuple = ISC_LIST_HEAD(temp_diff.tuples)) {
 2427 
 2428         ISC_LIST_UNLINK(temp_diff.tuples, tuple, link);
 2429         ISC_LIST_APPEND(diff->tuples, tuple, link);
 2430 
 2431         result = dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
 2432         RUNTIME_CHECK(result == ISC_R_SUCCESS);
 2433         if ((dnskey.flags &
 2434              (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
 2435              != DNS_KEYOWNER_ZONE)
 2436             continue;
 2437 
 2438         dns_rdata_toregion(&tuple->rdata, &r);
 2439 
 2440         keyid = dst_region_computeid(&r, dnskey.algorithm);
 2441 
 2442         buf[0] = dnskey.algorithm;
 2443         buf[1] = (keyid & 0xff00) >> 8;
 2444         buf[2] = (keyid & 0xff);
 2445         buf[3] = (tuple->op == DNS_DIFFOP_ADD) ? 0 : 1;
 2446         buf[4] = 0;
 2447         rdata.data = buf;
 2448         rdata.length = sizeof(buf);
 2449         rdata.type = privatetype;
 2450         rdata.rdclass = tuple->rdata.rdclass;
 2451 
 2452         CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2453         if (flag)
 2454             continue;
 2455         CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD,
 2456                        name, 0, &rdata, &newtuple));
 2457         CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2458         INSIST(newtuple == NULL);
 2459         /*
 2460          * Remove any record which says this operation has already
 2461          * completed.
 2462          */
 2463         buf[4] = 1;
 2464         CHECK(rr_exists(db, ver, name, &rdata, &flag));
 2465         if (flag) {
 2466             CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL,
 2467                            name, 0, &rdata, &newtuple));
 2468             CHECK(do_one_tuple(&newtuple, db, ver, diff));
 2469             INSIST(newtuple == NULL);
 2470         }
 2471     }
 2472 
 2473  failure:
 2474     dns_diff_clear(&temp_diff);
 2475     return (result);
 2476 }
 2477 
 2478 static bool
 2479 isdnssec(dns_db_t *db, dns_dbversion_t *ver, dns_rdatatype_t privatetype) {
 2480     isc_result_t result;
 2481     bool build_nsec, build_nsec3;
 2482 
 2483     if (dns_db_issecure(db))
 2484         return (true);
 2485 
 2486     result = dns_private_chains(db, ver, privatetype,
 2487                     &build_nsec, &build_nsec3);
 2488     RUNTIME_CHECK(result == ISC_R_SUCCESS);
 2489     return (build_nsec || build_nsec3);
 2490 }
 2491 
 2492 static void
 2493 update_action(isc_task_t *task, isc_event_t *event) {
 2494     update_event_t *uev = (update_event_t *) event;
 2495     dns_zone_t *zone = uev->zone;
 2496     ns_client_t *client = (ns_client_t *)event->ev_arg;
 2497     isc_result_t result;
 2498     dns_db_t *db = NULL;
 2499     dns_dbversion_t *oldver = NULL;
 2500     dns_dbversion_t *ver = NULL;
 2501     dns_diff_t diff;    /* Pending updates. */
 2502     dns_diff_t temp;    /* Pending RR existence assertions. */
 2503     bool soa_serial_changed = false;
 2504     isc_mem_t *mctx = client->mctx;
 2505     dns_rdatatype_t covers;
 2506     dns_message_t *request = client->message;
 2507     dns_rdataclass_t zoneclass;
 2508     dns_name_t *zonename;
 2509     dns_ssutable_t *ssutable = NULL;
 2510     dns_fixedname_t tmpnamefixed;
 2511     dns_name_t *tmpname = NULL;
 2512     unsigned int options, options2;
 2513     dns_difftuple_t *tuple;
 2514     dns_rdata_dnskey_t dnskey;
 2515     bool had_dnskey;
 2516     dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
 2517     dns_ttl_t maxttl = 0;
 2518     uint32_t maxrecords;
 2519     uint64_t records;
 2520 
 2521     INSIST(event->ev_type == DNS_EVENT_UPDATE);
 2522 
 2523     dns_diff_init(mctx, &diff);
 2524     dns_diff_init(mctx, &temp);
 2525 
 2526     CHECK(dns_zone_getdb(zone, &db));
 2527     zonename = dns_db_origin(db);
 2528     zoneclass = dns_db_class(db);
 2529     dns_zone_getssutable(zone, &ssutable);
 2530 
 2531     /*
 2532      * Update message processing can leak record existence information
 2533      * so check that we are allowed to query this zone.  Additionally
 2534      * if we would refuse all updates for this zone we bail out here.
 2535      */
 2536     CHECK(checkqueryacl(client, dns_zone_getqueryacl(zone), zonename,
 2537                 dns_zone_getupdateacl(zone), ssutable));
 2538 
 2539     /*
 2540      * Get old and new versions now that queryacl has been checked.
 2541      */
 2542     dns_db_currentversion(db, &oldver);
 2543     CHECK(dns_db_newversion(db, &ver));
 2544 
 2545     /*
 2546      * Check prerequisites.
 2547      */
 2548 
 2549     for (result = dns_message_firstname(request, DNS_SECTION_PREREQUISITE);
 2550          result == ISC_R_SUCCESS;
 2551          result = dns_message_nextname(request, DNS_SECTION_PREREQUISITE))
 2552     {
 2553         dns_name_t *name = NULL;
 2554         dns_rdata_t rdata = DNS_RDATA_INIT;
 2555         dns_ttl_t ttl;
 2556         dns_rdataclass_t update_class;
 2557         bool flag;
 2558 
 2559         get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
 2560                    &name, &rdata, &covers, &ttl, &update_class);
 2561 
 2562         if (ttl != 0)
 2563             PREREQFAILC(DNS_R_FORMERR,
 2564                     "prerequisite TTL is not zero");
 2565 
 2566         if (! dns_name_issubdomain(name, zonename))
 2567             PREREQFAILN(DNS_R_NOTZONE, name,
 2568                     "prerequisite name is out of zone");
 2569 
 2570         if (update_class == dns_rdataclass_any) {
 2571             if (rdata.length != 0)
 2572                 PREREQFAILC(DNS_R_FORMERR,
 2573                       "class ANY prerequisite "
 2574                       "RDATA is not empty");
 2575             if (rdata.type == dns_rdatatype_any) {
 2576                 CHECK(name_exists(db, ver, name, &flag));
 2577                 if (! flag) {
 2578                     PREREQFAILN(DNS_R_NXDOMAIN, name,
 2579                             "'name in use' "
 2580                             "prerequisite not "
 2581                             "satisfied");
 2582                 }
 2583             } else {
 2584                 CHECK(rrset_exists(db, ver, name,
 2585                            rdata.type, covers, &flag));
 2586                 if (! flag) {
 2587                     /* RRset does not exist. */
 2588                     PREREQFAILNT(DNS_R_NXRRSET, name, rdata.type,
 2589                     "'rrset exists (value independent)' "
 2590                     "prerequisite not satisfied");
 2591                 }
 2592             }
 2593         } else if (update_class == dns_rdataclass_none) {
 2594             if (rdata.length != 0)
 2595                 PREREQFAILC(DNS_R_FORMERR,
 2596                         "class NONE prerequisite "
 2597                         "RDATA is not empty");
 2598             if (rdata.type == dns_rdatatype_any) {
 2599                 CHECK(name_exists(db, ver, name, &flag));
 2600                 if (flag) {
 2601                     PREREQFAILN(DNS_R_YXDOMAIN, name,
 2602                             "'name not in use' "
 2603                             "prerequisite not "
 2604                             "satisfied");
 2605                 }
 2606             } else {
 2607                 CHECK(rrset_exists(db, ver, name,
 2608                            rdata.type, covers, &flag));
 2609                 if (flag) {
 2610                     /* RRset exists. */
 2611                     PREREQFAILNT(DNS_R_YXRRSET, name,
 2612                              rdata.type,
 2613                              "'rrset does not exist' "
 2614                              "prerequisite not "
 2615                              "satisfied");
 2616                 }
 2617             }
 2618         } else if (update_class == zoneclass) {
 2619             /* "temp<rr.name, rr.type> += rr;" */
 2620             result = temp_append(&temp, name, &rdata);
 2621             if (result != ISC_R_SUCCESS) {
 2622                 UNEXPECTED_ERROR(__FILE__, __LINE__,
 2623                      "temp entry creation failed: %s",
 2624                          dns_result_totext(result));
 2625                 FAIL(ISC_R_UNEXPECTED);
 2626             }
 2627         } else {
 2628             PREREQFAILC(DNS_R_FORMERR, "malformed prerequisite");
 2629         }
 2630     }
 2631     if (result != ISC_R_NOMORE)
 2632         FAIL(result);
 2633 
 2634     /*
 2635      * Perform the final check of the "rrset exists (value dependent)"
 2636      * prerequisites.
 2637      */
 2638     if (ISC_LIST_HEAD(temp.tuples) != NULL) {
 2639         dns_rdatatype_t type;
 2640 
 2641         /*
 2642          * Sort the prerequisite records by owner name,
 2643          * type, and rdata.
 2644          */
 2645         result = dns_diff_sort(&temp, temp_order);
 2646         if (result != ISC_R_SUCCESS)
 2647             FAILC(result, "'RRset exists (value dependent)' "
 2648                   "prerequisite not satisfied");
 2649 
 2650         tmpname = dns_fixedname_initname(&tmpnamefixed);
 2651         result = temp_check(mctx, &temp, db, ver, tmpname, &type);
 2652         if (result != ISC_R_SUCCESS)
 2653             FAILNT(result, tmpname, type,
 2654                    "'RRset exists (value dependent)' "
 2655                    "prerequisite not satisfied");
 2656     }
 2657 
 2658     update_log(client, zone, LOGLEVEL_DEBUG,
 2659            "prerequisites are OK");
 2660 
 2661     /*
 2662      * Check Requestor's Permissions.  It seems a bit silly to do this
 2663      * only after prerequisite testing, but that is what RFC2136 says.
 2664      */
 2665     if (ssutable == NULL)
 2666         CHECK(checkupdateacl(client, dns_zone_getupdateacl(zone),
 2667                      "update", zonename, false, false));
 2668     else if (client->signer == NULL && !TCPCLIENT(client))
 2669         CHECK(checkupdateacl(client, NULL, "update", zonename,
 2670                      false, true));
 2671 
 2672     if (dns_zone_getupdatedisabled(zone))
 2673         FAILC(DNS_R_REFUSED, "dynamic update temporarily disabled "
 2674                      "because the zone is frozen.  Use "
 2675                      "'rndc thaw' to re-enable updates.");
 2676 
 2677     /*
 2678      * Perform the Update Section Prescan.
 2679      */
 2680 
 2681     for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
 2682          result == ISC_R_SUCCESS;
 2683          result = dns_message_nextname(request, DNS_SECTION_UPDATE))
 2684     {
 2685         dns_name_t *name = NULL;
 2686         dns_rdata_t rdata = DNS_RDATA_INIT;
 2687         dns_ttl_t ttl;
 2688         dns_rdataclass_t update_class;
 2689         get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
 2690                    &name, &rdata, &covers, &ttl, &update_class);
 2691 
 2692         if (! dns_name_issubdomain(name, zonename))
 2693             FAILC(DNS_R_NOTZONE,
 2694                   "update RR is outside zone");
 2695         if (update_class == zoneclass) {
 2696             /*
 2697              * Check for meta-RRs.  The RFC2136 pseudocode says
 2698              * check for ANY|AXFR|MAILA|MAILB, but the text adds
 2699              * "or any other QUERY metatype"
 2700              */
 2701             if (dns_rdatatype_ismeta(rdata.type)) {
 2702                 FAILC(DNS_R_FORMERR,
 2703                       "meta-RR in update");
 2704             }
 2705             result = dns_zone_checknames(zone, name, &rdata);
 2706             if (result != ISC_R_SUCCESS)
 2707                 FAIL(DNS_R_REFUSED);
 2708         } else if (update_class == dns_rdataclass_any) {
 2709             if (ttl != 0 || rdata.length != 0 ||
 2710                 (dns_rdatatype_ismeta(rdata.type) &&
 2711                  rdata.type != dns_rdatatype_any))
 2712                 FAILC(DNS_R_FORMERR,
 2713                       "meta-RR in update");
 2714         } else if (update_class == dns_rdataclass_none) {
 2715             if (ttl != 0 ||
 2716                 dns_rdatatype_ismeta(rdata.type))
 2717                 FAILC(DNS_R_FORMERR,
 2718                       "meta-RR in update");
 2719         } else {
 2720             update_log(client, zone, ISC_LOG_WARNING,
 2721                    "update RR has incorrect class %d",
 2722                    update_class);
 2723             FAIL(DNS_R_FORMERR);
 2724         }
 2725 
 2726         /*
 2727          * draft-ietf-dnsind-simple-secure-update-01 says
 2728          * "Unlike traditional dynamic update, the client
 2729          * is forbidden from updating NSEC records."
 2730          */
 2731         if (rdata.type == dns_rdatatype_nsec3) {
 2732             FAILC(DNS_R_REFUSED,
 2733                   "explicit NSEC3 updates are not allowed "
 2734                   "in secure zones");
 2735         } else if (rdata.type == dns_rdatatype_nsec) {
 2736             FAILC(DNS_R_REFUSED,
 2737                   "explicit NSEC updates are not allowed "
 2738                   "in secure zones");
 2739         } else if (rdata.type == dns_rdatatype_rrsig &&
 2740                !dns_name_equal(name, zonename)) {
 2741             FAILC(DNS_R_REFUSED,
 2742                   "explicit RRSIG updates are currently "
 2743                   "not supported in secure zones except "
 2744                   "at the apex");
 2745         }
 2746 
 2747         if (ssutable != NULL) {
 2748             isc_netaddr_t netaddr;
 2749             dst_key_t *tsigkey = NULL;
 2750             isc_netaddr_fromsockaddr(&netaddr, &client->peeraddr);
 2751 
 2752             if (client->message->tsigkey != NULL)
 2753                 tsigkey = client->message->tsigkey->key;
 2754 
 2755             if (rdata.type != dns_rdatatype_any) {
 2756                 if (!dns_ssutable_checkrules2
 2757                     (ssutable, client->signer, name, &netaddr,
 2758                      TCPCLIENT(client),
 2759                      &ns_g_server->aclenv,
 2760                      rdata.type, tsigkey))
 2761                 {
 2762                     FAILC(DNS_R_REFUSED,
 2763                           "rejected by secure update");
 2764                 }
 2765             } else {
 2766                 if (!ssu_checkall(db, ver, name, ssutable,
 2767                           client->signer,
 2768                           &netaddr,
 2769                           TCPCLIENT(client),
 2770                           tsigkey))
 2771                 {
 2772                     FAILC(DNS_R_REFUSED,
 2773                           "rejected by secure update");
 2774                 }
 2775             }
 2776         }
 2777     }
 2778     if (result != ISC_R_NOMORE)
 2779         FAIL(result);
 2780 
 2781     update_log(client, zone, LOGLEVEL_DEBUG,
 2782            "update section prescan OK");
 2783 
 2784     /*
 2785      * Process the Update Section.
 2786      */
 2787 
 2788     options = dns_zone_getoptions(zone);
 2789     options2 = dns_zone_getoptions2(zone);
 2790     for (result = dns_message_firstname(request, DNS_SECTION_UPDATE);
 2791          result == ISC_R_SUCCESS;
 2792          result = dns_message_nextname(request, DNS_SECTION_UPDATE))
 2793     {
 2794         dns_name_t *name = NULL;
 2795         dns_rdata_t rdata = DNS_RDATA_INIT;
 2796         dns_ttl_t ttl;
 2797         dns_rdataclass_t update_class;
 2798         bool flag;
 2799 
 2800         get_current_rr(request, DNS_SECTION_UPDATE, zoneclass,
 2801                    &name, &rdata, &covers, &ttl, &update_class);
 2802 
 2803         if (update_class == zoneclass) {
 2804 
 2805             /*
 2806              * RFC1123 doesn't allow MF and MD in master zones.
 2807              */
 2808             if (rdata.type == dns_rdatatype_md ||
 2809                 rdata.type == dns_rdatatype_mf) {
 2810                 char typebuf[DNS_RDATATYPE_FORMATSIZE];
 2811 
 2812                 dns_rdatatype_format(rdata.type, typebuf,
 2813                              sizeof(typebuf));
 2814                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 2815                        "attempt to add %s ignored",
 2816                        typebuf);
 2817                 continue;
 2818             }
 2819             if ((rdata.type == dns_rdatatype_ns ||
 2820                  rdata.type == dns_rdatatype_dname) &&
 2821                 dns_name_iswildcard(name)) {
 2822                 char typebuf[DNS_RDATATYPE_FORMATSIZE];
 2823 
 2824                 dns_rdatatype_format(rdata.type, typebuf,
 2825                              sizeof(typebuf));
 2826                 update_log(client, zone,
 2827                        LOGLEVEL_PROTOCOL,
 2828                        "attempt to add wildcard %s record "
 2829                        "ignored", typebuf);
 2830                 continue;
 2831             }
 2832             if (rdata.type == dns_rdatatype_cname) {
 2833                 CHECK(cname_incompatible_rrset_exists(db, ver,
 2834                                       name,
 2835                                       &flag));
 2836                 if (flag) {
 2837                     update_log(client, zone,
 2838                            LOGLEVEL_PROTOCOL,
 2839                            "attempt to add CNAME "
 2840                            "alongside non-CNAME "
 2841                            "ignored");
 2842                     continue;
 2843                 }
 2844             } else {
 2845                 CHECK(rrset_exists(db, ver, name,
 2846                            dns_rdatatype_cname, 0,
 2847                            &flag));
 2848                 if (flag &&
 2849                     ! dns_rdatatype_atcname(rdata.type))
 2850                 {
 2851                     update_log(client, zone,
 2852                            LOGLEVEL_PROTOCOL,
 2853                            "attempt to add non-CNAME "
 2854                            "alongside CNAME ignored");
 2855                     continue;
 2856                 }
 2857             }
 2858             if (rdata.type == dns_rdatatype_soa) {
 2859                 bool ok;
 2860                 CHECK(rrset_exists(db, ver, name,
 2861                            dns_rdatatype_soa, 0,
 2862                            &flag));
 2863                 if (! flag) {
 2864                     update_log(client, zone,
 2865                            LOGLEVEL_PROTOCOL,
 2866                            "attempt to create 2nd "
 2867                            "SOA ignored");
 2868                     continue;
 2869                 }
 2870                 CHECK(check_soa_increment(db, ver, &rdata,
 2871                               &ok));
 2872                 if (! ok) {
 2873                     update_log(client, zone,
 2874                            LOGLEVEL_PROTOCOL,
 2875                            "SOA update failed to "
 2876                            "increment serial, "
 2877                            "ignoring it");
 2878                     continue;
 2879                 }
 2880                 soa_serial_changed = true;
 2881             }
 2882 
 2883             if (rdata.type == privatetype) {
 2884                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 2885                        "attempt to add a private type "
 2886                        "(%u) record rejected internal "
 2887                        "use only", privatetype);
 2888                 continue;
 2889             }
 2890 
 2891             if (rdata.type == dns_rdatatype_nsec3param) {
 2892                 /*
 2893                  * Ignore attempts to add NSEC3PARAM records
 2894                  * with any flags other than OPTOUT.
 2895                  */
 2896                 if ((rdata.data[1] &
 2897                      ~DNS_NSEC3FLAG_OPTOUT) != 0)
 2898                 {
 2899                     update_log(client, zone,
 2900                            LOGLEVEL_PROTOCOL,
 2901                            "attempt to add NSEC3PARAM "
 2902                            "record with non OPTOUT "
 2903                            "flag");
 2904                     continue;
 2905                 }
 2906             }
 2907 
 2908             if ((options & DNS_ZONEOPT_CHECKWILDCARD) != 0 &&
 2909                 dns_name_internalwildcard(name)) {
 2910                 char namestr[DNS_NAME_FORMATSIZE];
 2911                 dns_name_format(name, namestr,
 2912                         sizeof(namestr));
 2913                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 2914                        "warning: ownername '%s' contains "
 2915                        "a non-terminal wildcard", namestr);
 2916             }
 2917 
 2918             if ((options2 & DNS_ZONEOPT2_CHECKTTL) != 0) {
 2919                 maxttl = dns_zone_getmaxttl(zone);
 2920                 if (ttl > maxttl) {
 2921                     ttl = maxttl;
 2922                     update_log(client, zone,
 2923                            LOGLEVEL_PROTOCOL,
 2924                            "reducing TTL to the "
 2925                            "configured max-zone-ttl %d",
 2926                            maxttl);
 2927                 }
 2928             }
 2929 
 2930             if (isc_log_wouldlog(ns_g_lctx, LOGLEVEL_PROTOCOL)) {
 2931                 char namestr[DNS_NAME_FORMATSIZE];
 2932                 char typestr[DNS_RDATATYPE_FORMATSIZE];
 2933                 char rdstr[2048];
 2934                 isc_buffer_t buf;
 2935                 int len = 0;
 2936                 const char *truncated = "";
 2937 
 2938                 dns_name_format(name, namestr, sizeof(namestr));
 2939                 dns_rdatatype_format(rdata.type, typestr,
 2940                              sizeof(typestr));
 2941                 isc_buffer_init(&buf, rdstr, sizeof(rdstr));
 2942                 result = dns_rdata_totext(&rdata, NULL, &buf);
 2943                 if (result == ISC_R_NOSPACE) {
 2944                     len = (int)isc_buffer_usedlength(&buf);
 2945                     truncated = " [TRUNCATED]";
 2946                 } else if (result != ISC_R_SUCCESS) {
 2947                     snprintf(rdstr, sizeof(rdstr), "[dns_"
 2948                          "rdata_totext failed: %s]",
 2949                          dns_result_totext(result));
 2950                     len = strlen(rdstr);
 2951                 } else
 2952                     len = (int)isc_buffer_usedlength(&buf);
 2953                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 2954                        "adding an RR at '%s' %s %.*s%s",
 2955                        namestr, typestr, len, rdstr,
 2956                        truncated);
 2957             }
 2958 
 2959             /* Prepare the affected RRset for the addition. */
 2960             {
 2961                 add_rr_prepare_ctx_t ctx;
 2962                 ctx.db = db;
 2963                 ctx.ver = ver;
 2964                 ctx.diff = &diff;
 2965                 ctx.name = name;
 2966                 ctx.oldname = name;
 2967                 ctx.update_rr = &rdata;
 2968                 ctx.update_rr_ttl = ttl;
 2969                 ctx.ignore_add = false;
 2970                 dns_diff_init(mctx, &ctx.del_diff);
 2971                 dns_diff_init(mctx, &ctx.add_diff);
 2972                 CHECK(foreach_rr(db, ver, name, rdata.type,
 2973                          covers, add_rr_prepare_action,
 2974                          &ctx));
 2975 
 2976                 if (ctx.ignore_add) {
 2977                     dns_diff_clear(&ctx.del_diff);
 2978                     dns_diff_clear(&ctx.add_diff);
 2979                 } else {
 2980                     result = do_diff(&ctx.del_diff, db, ver,
 2981                              &diff);
 2982                     if (result == ISC_R_SUCCESS) {
 2983                         result = do_diff(&ctx.add_diff,
 2984                                  db, ver,
 2985                                  &diff);
 2986                     }
 2987                     if (result != ISC_R_SUCCESS) {
 2988                         dns_diff_clear(&ctx.del_diff);
 2989                         dns_diff_clear(&ctx.add_diff);
 2990                         goto failure;
 2991                     }
 2992                     CHECK(update_one_rr(db, ver, &diff,
 2993                                 DNS_DIFFOP_ADD,
 2994                                 name, ttl, &rdata));
 2995                 }
 2996             }
 2997         } else if (update_class == dns_rdataclass_any) {
 2998             if (rdata.type == dns_rdatatype_any) {
 2999                 if (isc_log_wouldlog(ns_g_lctx,
 3000                              LOGLEVEL_PROTOCOL))
 3001                 {
 3002                     char namestr[DNS_NAME_FORMATSIZE];
 3003                     dns_name_format(name, namestr,
 3004                             sizeof(namestr));
 3005                     update_log(client, zone,
 3006                            LOGLEVEL_PROTOCOL,
 3007                            "delete all rrsets from "
 3008                            "name '%s'", namestr);
 3009                 }
 3010                 if (dns_name_equal(name, zonename)) {
 3011                     CHECK(delete_if(type_not_soa_nor_ns_p,
 3012                             db, ver, name,
 3013                             dns_rdatatype_any, 0,
 3014                             &rdata, &diff));
 3015                 } else {
 3016                     CHECK(delete_if(type_not_dnssec,
 3017                             db, ver, name,
 3018                             dns_rdatatype_any, 0,
 3019                             &rdata, &diff));
 3020                 }
 3021             } else if (dns_name_equal(name, zonename) &&
 3022                    (rdata.type == dns_rdatatype_soa ||
 3023                     rdata.type == dns_rdatatype_ns)) {
 3024                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 3025                        "attempt to delete all SOA "
 3026                        "or NS records ignored");
 3027                 continue;
 3028             } else {
 3029                 if (isc_log_wouldlog(ns_g_lctx,
 3030                              LOGLEVEL_PROTOCOL))
 3031                 {
 3032                     char namestr[DNS_NAME_FORMATSIZE];
 3033                     char typestr[DNS_RDATATYPE_FORMATSIZE];
 3034                     dns_name_format(name, namestr,
 3035                             sizeof(namestr));
 3036                     dns_rdatatype_format(rdata.type,
 3037                                  typestr,
 3038                                  sizeof(typestr));
 3039                     update_log(client, zone,
 3040                            LOGLEVEL_PROTOCOL,
 3041                            "deleting rrset at '%s' %s",
 3042                            namestr, typestr);
 3043                 }
 3044                 CHECK(delete_if(true_p, db, ver, name,
 3045                         rdata.type, covers, &rdata,
 3046                         &diff));
 3047             }
 3048         } else if (update_class == dns_rdataclass_none) {
 3049             char namestr[DNS_NAME_FORMATSIZE];
 3050             char typestr[DNS_RDATATYPE_FORMATSIZE];
 3051 
 3052             /*
 3053              * The (name == zonename) condition appears in
 3054              * RFC2136 3.4.2.4 but is missing from the pseudocode.
 3055              */
 3056             if (dns_name_equal(name, zonename)) {
 3057                 if (rdata.type == dns_rdatatype_soa) {
 3058                     update_log(client, zone,
 3059                            LOGLEVEL_PROTOCOL,
 3060                            "attempt to delete SOA "
 3061                            "ignored");
 3062                     continue;
 3063                 }
 3064                 if (rdata.type == dns_rdatatype_ns) {
 3065                     int count;
 3066                     CHECK(rr_count(db, ver, name,
 3067                                dns_rdatatype_ns,
 3068                                0, &count));
 3069                     if (count == 1) {
 3070                         update_log(client, zone,
 3071                                LOGLEVEL_PROTOCOL,
 3072                                "attempt to "
 3073                                "delete last "
 3074                                "NS ignored");
 3075                         continue;
 3076                     }
 3077                 }
 3078             }
 3079             dns_name_format(name, namestr, sizeof(namestr));
 3080             dns_rdatatype_format(rdata.type, typestr,
 3081                          sizeof(typestr));
 3082             update_log(client, zone, LOGLEVEL_PROTOCOL,
 3083                    "deleting an RR at %s %s", namestr, typestr);
 3084             CHECK(delete_if(rr_equal_p, db, ver, name, rdata.type,
 3085                     covers, &rdata, &diff));
 3086         }
 3087     }
 3088     if (result != ISC_R_NOMORE)
 3089         FAIL(result);
 3090 
 3091     /*
 3092      * Check that any changes to DNSKEY/NSEC3PARAM records make sense.
 3093      * If they don't then back out all changes to DNSKEY/NSEC3PARAM
 3094      * records.
 3095      */
 3096     if (! ISC_LIST_EMPTY(diff.tuples))
 3097         CHECK(check_dnssec(client, zone, db, ver, &diff));
 3098 
 3099     if (! ISC_LIST_EMPTY(diff.tuples)) {
 3100         unsigned int errors = 0;
 3101         CHECK(dns_zone_nscheck(zone, db, ver, &errors));
 3102         if (errors != 0) {
 3103             update_log(client, zone, LOGLEVEL_PROTOCOL,
 3104                    "update rejected: post update name server "
 3105                    "sanity check failed");
 3106             result = DNS_R_REFUSED;
 3107             goto failure;
 3108         }
 3109     }
 3110     if (! ISC_LIST_EMPTY(diff.tuples)) {
 3111         result = dns_zone_cdscheck(zone, db, ver);
 3112         if (result == DNS_R_BADCDS || result == DNS_R_BADCDNSKEY) {
 3113             update_log(client, zone, LOGLEVEL_PROTOCOL,
 3114                    "update rejected: bad %s RRset",
 3115                    result == DNS_R_BADCDS ? "CDS" : "CDNSKEY");
 3116             result = DNS_R_REFUSED;
 3117             goto failure;
 3118         }
 3119         if (result != ISC_R_SUCCESS)
 3120             goto failure;
 3121 
 3122     }
 3123 
 3124     /*
 3125      * If any changes were made, increment the SOA serial number,
 3126      * update RRSIGs and NSECs (if zone is secure), and write the update
 3127      * to the journal.
 3128      */
 3129     if (! ISC_LIST_EMPTY(diff.tuples)) {
 3130         char *journalfile;
 3131         dns_journal_t *journal;
 3132         bool has_dnskey;
 3133 
 3134         /*
 3135          * Increment the SOA serial, but only if it was not
 3136          * changed as a result of an update operation.
 3137          */
 3138         if (! soa_serial_changed) {
 3139             CHECK(update_soa_serial(db, ver, &diff, mctx,
 3140                        dns_zone_getserialupdatemethod(zone)));
 3141         }
 3142 
 3143         CHECK(check_mx(client, zone, db, ver, &diff));
 3144 
 3145         CHECK(remove_orphaned_ds(db, ver, &diff));
 3146 
 3147         CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
 3148                    0, &has_dnskey));
 3149 
 3150 #define ALLOW_SECURE_TO_INSECURE(zone) \
 3151     ((dns_zone_getoptions(zone) & DNS_ZONEOPT_SECURETOINSECURE) != 0)
 3152 
 3153         CHECK(rrset_exists(db, oldver, zonename, dns_rdatatype_dnskey,
 3154                    0, &had_dnskey));
 3155         if (!ALLOW_SECURE_TO_INSECURE(zone)) {
 3156             if (had_dnskey && !has_dnskey) {
 3157                 update_log(client, zone, LOGLEVEL_PROTOCOL,
 3158                        "update rejected: all DNSKEY "
 3159                        "records removed and "
 3160                        "'dnssec-secure-to-insecure' "
 3161                        "not set");
 3162                 result = DNS_R_REFUSED;
 3163                 goto failure;
 3164             }
 3165         }
 3166 
 3167         CHECK(rollback_private(db, privatetype, ver, &diff));
 3168 
 3169         CHECK(add_signing_records(db, privatetype, ver, &diff));
 3170 
 3171         CHECK(add_nsec3param_records(client, zone, db, ver, &diff));
 3172 
 3173         if (had_dnskey && !has_dnskey) {
 3174             /*
 3175              * We are transitioning from secure to insecure.
 3176              * Cause all NSEC3 chains to be deleted.  When the
 3177              * the last signature for the DNSKEY records are
 3178              * remove any NSEC chain present will also be removed.
 3179              */
 3180              CHECK(dns_nsec3param_deletechains(db, ver, zone,
 3181                                true, &diff));
 3182         } else if (has_dnskey && isdnssec(db, ver, privatetype)) {
 3183             uint32_t interval;
 3184             dns_update_log_t log;
 3185 
 3186             interval = dns_zone_getsigvalidityinterval(zone);
 3187             log.func = update_log_cb;
 3188             log.arg = client;
 3189             result = dns_update_signatures(&log, zone, db, oldver,
 3190                                ver, &diff, interval);
 3191 
 3192             if (result != ISC_R_SUCCESS) {
 3193                 update_log(client, zone,
 3194                        ISC_LOG_ERROR,
 3195                        "RRSIG/NSEC/NSEC3 update failed: %s",
 3196                        isc_result_totext(result));
 3197                 goto failure;
 3198             }
 3199         }
 3200 
 3201         maxrecords = dns_zone_getmaxrecords(zone);
 3202         if (maxrecords != 0U) {
 3203             result = dns_db_getsize(db, ver, &records, NULL);
 3204             if (result == ISC_R_SUCCESS && records > maxrecords) {
 3205                 update_log(client, zone, ISC_LOG_ERROR,
 3206                        "records in zone (%"
 3207                        PRIu64
 3208                        ") exceeds max-records (%u)",
 3209                        records, maxrecords);
 3210                 result = DNS_R_TOOMANYRECORDS;
 3211                 goto failure;
 3212             }
 3213         }
 3214 
 3215         journalfile = dns_zone_getjournal(zone);
 3216         if (journalfile != NULL) {
 3217             update_log(client, zone, LOGLEVEL_DEBUG,
 3218                    "writing journal %s", journalfile);
 3219 
 3220             journal = NULL;
 3221             result = dns_journal_open(mctx, journalfile,
 3222                           DNS_JOURNAL_CREATE, &journal);
 3223             if (result != ISC_R_SUCCESS)
 3224                 FAILS(result, "journal open failed");
 3225 
 3226             result = dns_journal_write_transaction(journal, &diff);
 3227             if (result != ISC_R_SUCCESS) {
 3228                 dns_journal_destroy(&journal);
 3229                 FAILS(result, "journal write failed");
 3230             }
 3231 
 3232             dns_journal_destroy(&journal);
 3233         }
 3234 
 3235         /*
 3236          * XXXRTH  Just a note that this committing code will have
 3237          *     to change to handle databases that need two-phase
 3238          *     commit, but this isn't a priority.
 3239          */
 3240         update_log(client, zone, LOGLEVEL_DEBUG,
 3241                "committing update transaction");
 3242 
 3243         dns_db_closeversion(db, &ver, true);
 3244 
 3245         /*
 3246          * Mark the zone as dirty so that it will be written to disk.
 3247          */
 3248         dns_zone_markdirty(zone);
 3249 
 3250         /*
 3251          * Notify slaves of the change we just made.
 3252          */
 3253         dns_zone_notify(zone);
 3254 
 3255         /*
 3256          * Cause the zone to be signed with the key that we
 3257          * have just added or have the corresponding signatures
 3258          * deleted.
 3259          *
 3260          * Note: we are already committed to this course of action.
 3261          */
 3262         for (tuple = ISC_LIST_HEAD(diff.tuples);
 3263              tuple != NULL;
 3264              tuple = ISC_LIST_NEXT(tuple, link)) {
 3265             isc_region_t r;
 3266             dns_secalg_t algorithm;
 3267             uint16_t keyid;
 3268 
 3269             if (tuple->rdata.type != dns_rdatatype_dnskey)
 3270                 continue;
 3271 
 3272             dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
 3273             if ((dnskey.flags &
 3274                  (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
 3275                  != DNS_KEYOWNER_ZONE)
 3276                 continue;
 3277 
 3278             dns_rdata_toregion(&tuple->rdata, &r);
 3279             algorithm = dnskey.algorithm;
 3280             keyid = dst_region_computeid(&r, algorithm);
 3281 
 3282             result = dns_zone_signwithkey(zone, algorithm, keyid,
 3283                               (tuple->op == DNS_DIFFOP_DEL));
 3284             if (result != ISC_R_SUCCESS) {
 3285                 update_log(client, zone, ISC_LOG_ERROR,
 3286                        "dns_zone_signwithkey failed: %s",
 3287                        dns_result_totext(result));
 3288             }
 3289         }
 3290 
 3291         /*
 3292          * Cause the zone to add/delete NSEC3 chains for the
 3293          * deferred NSEC3PARAM changes.
 3294          *
 3295          * Note: we are already committed to this course of action.
 3296          */
 3297         for (tuple = ISC_LIST_HEAD(diff.tuples);
 3298              tuple != NULL;
 3299              tuple = ISC_LIST_NEXT(tuple, link)) {
 3300             unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
 3301             dns_rdata_t rdata = DNS_RDATA_INIT;
 3302             dns_rdata_nsec3param_t nsec3param;
 3303 
 3304             if (tuple->rdata.type != privatetype ||
 3305                 tuple->op != DNS_DIFFOP_ADD)
 3306                 continue;
 3307 
 3308             if (!dns_nsec3param_fromprivate(&tuple->rdata, &rdata,
 3309                            buf, sizeof(buf)))
 3310                 continue;
 3311             dns_rdata_tostruct(&rdata, &nsec3param, NULL);
 3312             if (nsec3param.flags == 0)
 3313                 continue;
 3314 
 3315             result = dns_zone_addnsec3chain(zone, &nsec3param);
 3316             if (result != ISC_R_SUCCESS) {
 3317                 update_log(client, zone, ISC_LOG_ERROR,
 3318                        "dns_zone_addnsec3chain failed: %s",
 3319                        dns_result_totext(result));
 3320             }
 3321         }
 3322     } else {
 3323         update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
 3324         dns_db_closeversion(db, &ver, true);
 3325     }
 3326     result = ISC_R_SUCCESS;
 3327     goto common;
 3328 
 3329  failure:
 3330     /*
 3331      * The reason for failure should have been logged at this point.
 3332      */
 3333     if (ver != NULL) {
 3334         update_log(client, zone, LOGLEVEL_DEBUG,
 3335                "rolling back");
 3336         dns_db_closeversion(db, &ver, false);
 3337     }
 3338 
 3339  common:
 3340     dns_diff_clear(&temp);
 3341     dns_diff_clear(&diff);
 3342 
 3343     if (oldver != NULL)
 3344         dns_db_closeversion(db, &oldver, false);
 3345 
 3346     if (db != NULL)
 3347         dns_db_detach(&db);
 3348 
 3349     if (ssutable != NULL)
 3350         dns_ssutable_detach(&ssutable);
 3351 
 3352     isc_task_detach(&task);
 3353     uev->result = result;
 3354     if (zone != NULL)
 3355         INSIST(uev->zone == zone); /* we use this later */
 3356     uev->ev_type = DNS_EVENT_UPDATEDONE;
 3357     uev->ev_action = updatedone_action;
 3358     isc_task_send(client->task, &event);
 3359 
 3360     INSIST(ver == NULL);
 3361     INSIST(event == NULL);
 3362 }
 3363 
 3364 static void
 3365 updatedone_action(isc_task_t *task, isc_event_t *event) {
 3366     update_event_t *uev = (update_event_t *) event;
 3367     ns_client_t *client = (ns_client_t *) event->ev_arg;
 3368 
 3369     UNUSED(task);
 3370 
 3371     INSIST(event->ev_type == DNS_EVENT_UPDATEDONE);
 3372     INSIST(task == client->task);
 3373 
 3374     INSIST(client->nupdates > 0);
 3375     switch (uev->result) {
 3376     case ISC_R_SUCCESS:
 3377         inc_stats(uev->zone, dns_nsstatscounter_updatedone);
 3378         break;
 3379     case DNS_R_REFUSED:
 3380         inc_stats(uev->zone, dns_nsstatscounter_updaterej);
 3381         break;
 3382     default:
 3383         inc_stats(uev->zone, dns_nsstatscounter_updatefail);
 3384         break;
 3385     }
 3386     if (uev->zone != NULL)
 3387         dns_zone_detach(&uev->zone);
 3388     client->nupdates--;
 3389     respond(client, uev->result);
 3390     isc_event_free(&event);
 3391     ns_client_detach(&client);
 3392 }
 3393 
 3394 /*%
 3395  * Update forwarding support.
 3396  */
 3397 
 3398 static void
 3399 forward_fail(isc_task_t *task, isc_event_t *event) {
 3400     ns_client_t *client = (ns_client_t *)event->ev_arg;
 3401 
 3402     UNUSED(task);
 3403 
 3404     INSIST(client->nupdates > 0);
 3405     client->nupdates--;
 3406     respond(client, DNS_R_SERVFAIL);
 3407     isc_event_free(&event);
 3408     ns_client_detach(&client);
 3409 }
 3410 
 3411 
 3412 static void
 3413 forward_callback(void *arg, isc_result_t result, dns_message_t *answer) {
 3414     update_event_t *uev = arg;
 3415     ns_client_t *client = uev->ev_arg;
 3416     dns_zone_t *zone = uev->zone;
 3417 
 3418     if (result != ISC_R_SUCCESS) {
 3419         INSIST(answer == NULL);
 3420         uev->ev_type = DNS_EVENT_UPDATEDONE;
 3421         uev->ev_action = forward_fail;
 3422         inc_stats(zone, dns_nsstatscounter_updatefwdfail);
 3423     } else {
 3424         uev->ev_type = DNS_EVENT_UPDATEDONE;
 3425         uev->ev_action = forward_done;
 3426         uev->answer = answer;
 3427         inc_stats(zone, dns_nsstatscounter_updaterespfwd);
 3428     }
 3429     isc_task_send(client->task, ISC_EVENT_PTR(&uev));
 3430     dns_zone_detach(&zone);
 3431 }
 3432 
 3433 static void
 3434 forward_done(isc_task_t *task, isc_event_t *event) {
 3435     update_event_t *uev = (update_event_t *) event;
 3436     ns_client_t *client = (ns_client_t *)event->ev_arg;
 3437 
 3438     UNUSED(task);
 3439 
 3440     INSIST(client->nupdates > 0);
 3441     client->nupdates--;
 3442     ns_client_sendraw(client, uev->answer);
 3443     dns_message_destroy(&uev->answer);
 3444     isc_event_free(&event);
 3445     ns_client_detach(&client);
 3446 }
 3447 
 3448 static void
 3449 forward_action(isc_task_t *task, isc_event_t *event) {
 3450     update_event_t *uev = (update_event_t *) event;
 3451     dns_zone_t *zone = uev->zone;
 3452     ns_client_t *client = (ns_client_t *)event->ev_arg;
 3453     isc_result_t result;
 3454 
 3455     result = dns_zone_forwardupdate(zone, client->message,
 3456                     forward_callback, event);
 3457     if (result != ISC_R_SUCCESS) {
 3458         uev->ev_type = DNS_EVENT_UPDATEDONE;
 3459         uev->ev_action = forward_fail;
 3460         isc_task_send(client->task, &event);
 3461         inc_stats(zone, dns_nsstatscounter_updatefwdfail);
 3462         dns_zone_detach(&zone);
 3463     } else
 3464         inc_stats(zone, dns_nsstatscounter_updatereqfwd);
 3465     isc_task_detach(&task);
 3466 }
 3467 
 3468 static isc_result_t
 3469 send_forward_event(ns_client_t *client, dns_zone_t *zone) {
 3470     char namebuf[DNS_NAME_FORMATSIZE];
 3471     char classbuf[DNS_RDATACLASS_FORMATSIZE];
 3472     isc_result_t result = ISC_R_SUCCESS;
 3473     update_event_t *event = NULL;
 3474     isc_task_t *zonetask = NULL;
 3475     ns_client_t *evclient;
 3476 
 3477     /*
 3478      * This may take some time so replace this client.
 3479      */
 3480     if (!client->mortal && (client->attributes & NS_CLIENTATTR_TCP) == 0)
 3481         CHECK(ns_client_replace(client));
 3482 
 3483     event = (update_event_t *)
 3484         isc_event_allocate(client->mctx, client, DNS_EVENT_UPDATE,
 3485                    forward_action, NULL, sizeof(*event));
 3486     if (event == NULL)
 3487         FAIL(ISC_R_NOMEMORY);
 3488     event->zone = zone;
 3489     event->result = ISC_R_SUCCESS;
 3490 
 3491     evclient = NULL;
 3492     ns_client_attach(client, &evclient);
 3493     INSIST(client->nupdates == 0);
 3494     client->nupdates++;
 3495     event->ev_arg = evclient;
 3496 
 3497     dns_name_format(dns_zone_getorigin(zone), namebuf,
 3498             sizeof(namebuf));
 3499     dns_rdataclass_format(dns_zone_getclass(zone), classbuf,
 3500                   sizeof(classbuf));
 3501 
 3502     ns_client_log(client, NS_LOGCATEGORY_UPDATE, NS_LOGMODULE_UPDATE,
 3503               LOGLEVEL_PROTOCOL, "forwarding update for zone '%s/%s'",
 3504               namebuf, classbuf);
 3505 
 3506     dns_zone_gettask(zone, &zonetask);
 3507     isc_task_send(zonetask, ISC_EVENT_PTR(&event));
 3508 
 3509  failure:
 3510     if (event != NULL)
 3511         isc_event_free(ISC_EVENT_PTR(&event));
 3512     return (result);
 3513 }