"Fossies" - the Fresh Open Source Software Archive

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


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