"Fossies" - the Fresh Open Source Software Archive

Member "opendnssec-2.1.4/signer/src/signer/zone.c" (16 May 2019, 37358 Bytes) of package /linux/misc/dns/opendnssec-2.1.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zone.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.1.2_vs_2.1.3.

    1 /*
    2  * Copyright (c) 2009 NLNet Labs. All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
   19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
   23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  *
   25  */
   26 
   27 /**
   28  * Zone.
   29  *
   30  */
   31 
   32 #include "adapter/adapter.h"
   33 #include "file.h"
   34 #include "hsm.h"
   35 #include "locks.h"
   36 #include "log.h"
   37 #include "status.h"
   38 #include "util.h"
   39 #include "signer/backup.h"
   40 #include "signer/zone.h"
   41 #include "wire/netio.h"
   42 #include "compat.h"
   43 #include "daemon/signertasks.h"
   44 
   45 #include <ldns/ldns.h>
   46 
   47 static const char* zone_str = "zone";
   48 
   49 
   50 /**
   51  * Create a new zone.
   52  *
   53  */
   54 zone_type*
   55 zone_create(char* name, ldns_rr_class klass)
   56 {
   57     zone_type* zone = NULL;
   58     int err;
   59 
   60     if (!name || !klass) {
   61         return NULL;
   62     }
   63     CHECKALLOC(zone = (zone_type*) calloc(1, sizeof(zone_type)));
   64     /* [start] PS 9218653: Drop trailing dot in domain name */
   65     if (strlen(name) > 1 && name[strlen(name)-1] == '.') {
   66         name[strlen(name)-1] = '\0';
   67     }
   68     /* [end] PS 9218653 */
   69 
   70     if (pthread_mutex_init(&zone->zone_lock, NULL)) {
   71         free(zone);
   72         return NULL;
   73     }
   74     if (pthread_mutex_init(&zone->xfr_lock, NULL)) {
   75         (void)pthread_mutex_destroy(&zone->zone_lock);
   76         free(zone);
   77         return NULL;
   78     }
   79 
   80     zone->name = strdup(name);
   81     if (!zone->name) {
   82         ods_log_error("[%s] unable to create zone %s: allocator_strdup() "
   83             "failed", zone_str, name);
   84         zone_cleanup(zone);
   85         return NULL;
   86     }
   87     zone->klass = klass;
   88     zone->default_ttl = 3600; /* TODO: configure --default-ttl option? */
   89     zone->apex = ldns_dname_new_frm_str(name);
   90     /* check zone->apex? */
   91     zone->notify_command = NULL;
   92     zone->notify_ns = NULL;
   93     zone->notify_args = NULL;
   94     zone->policy_name = NULL;
   95     zone->signconf_filename = NULL;
   96     zone->adinbound = NULL;
   97     zone->adoutbound = NULL;
   98     zone->zl_status = ZONE_ZL_OK;
   99     zone->xfrd = NULL;
  100     zone->notify = NULL;
  101     zone->db = namedb_create((void*)zone);
  102     if (!zone->db) {
  103         ods_log_error("[%s] unable to create zone %s: namedb_create() "
  104             "failed", zone_str, name);
  105         zone_cleanup(zone);
  106         return NULL;
  107     }
  108     zone->ixfr = ixfr_create();
  109     if (!zone->ixfr) {
  110         ods_log_error("[%s] unable to create zone %s: ixfr_create() "
  111             "failed", zone_str, name);
  112         zone_cleanup(zone);
  113         return NULL;
  114     }
  115     zone->zoneconfigvalid = 0;
  116     zone->signconf = signconf_create();
  117     if (!zone->signconf) {
  118         ods_log_error("[%s] unable to create zone %s: signconf_create() "
  119             "failed", zone_str, name);
  120         zone_cleanup(zone);
  121         return NULL;
  122     }
  123     zone->stats = stats_create();
  124     zone->rrstore = rrset_store_initialize();
  125     return zone;
  126 }
  127 
  128 /**
  129  * Load signer configuration for zone.
  130  *
  131  */
  132 ods_status
  133 zone_load_signconf(zone_type* zone, signconf_type** new_signconf)
  134 {
  135     ods_status status = ODS_STATUS_OK;
  136     signconf_type* signconf = NULL;
  137     char* datestamp = NULL;
  138 
  139     if (!zone || !zone->name || !zone->signconf) {
  140         return ODS_STATUS_ASSERT_ERR;
  141     }
  142     if (!zone->signconf_filename) {
  143         ods_log_warning("[%s] zone %s has no signconf filename, treat as "
  144             "insecure?", zone_str, zone->name);
  145         return ODS_STATUS_INSECURE;
  146     }
  147     status = signconf_update(&signconf, zone->signconf_filename,
  148         zone->signconf->last_modified);
  149     if (status == ODS_STATUS_OK) {
  150         if (!signconf) {
  151             /* this is unexpected */
  152             ods_log_alert("[%s] unable to load signconf for zone %s: signconf "
  153                 "status ok but no signconf stored", zone_str, zone->name);
  154             return ODS_STATUS_ASSERT_ERR;
  155         }
  156         (void)time_datestamp(signconf->last_modified, "%Y-%m-%d %T",
  157             &datestamp);
  158         ods_log_debug("[%s] zone %s signconf file %s is modified since %s",
  159             zone_str, zone->name, zone->signconf_filename,
  160             datestamp?datestamp:"Unknown");
  161         free((void*)datestamp);
  162         *new_signconf = signconf;
  163     } else if (status == ODS_STATUS_UNCHANGED) {
  164         /* OPENDNSSEC-686: changes happening within one second will not be
  165          * seen
  166          */
  167         (void)time_datestamp(zone->signconf->last_modified,
  168             "%Y-%m-%d %T", &datestamp);
  169         ods_log_verbose("[%s] zone %s signconf file %s is unchanged since "
  170             "%s", zone_str, zone->name, zone->signconf_filename,
  171             datestamp?datestamp:"Unknown");
  172         free((void*)datestamp);
  173     } else {
  174         ods_log_error("[%s] unable to load signconf for zone %s: signconf %s "
  175             "%s", zone_str, zone->name, zone->signconf_filename,
  176             ods_status2str(status));
  177     }
  178     return status;
  179 }
  180 
  181 /**
  182  * Publish the keys as indicated by the signer configuration.
  183  *
  184  */
  185 ods_status
  186 zone_publish_dnskeys(zone_type* zone, int skip_hsm_access)
  187 {
  188     hsm_ctx_t* ctx = NULL;
  189     uint32_t ttl = 0;
  190     unsigned int i;
  191     ods_status status = ODS_STATUS_OK;
  192     rrset_type* rrset = NULL;
  193     rr_type* dnskey = NULL;
  194 
  195     if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
  196         return ODS_STATUS_ASSERT_ERR;
  197     }
  198     ods_log_assert(zone->name);
  199 
  200     /* hsm access */
  201     if (!skip_hsm_access) {
  202         ctx = hsm_create_context();
  203         if (ctx == NULL) {
  204             ods_log_error("[%s] unable to publish keys for zone %s: "
  205                 "error creating libhsm context", zone_str, zone->name);
  206             return ODS_STATUS_HSM_ERR;
  207         }
  208     }
  209     ttl = zone->default_ttl;
  210     /* dnskey ttl */
  211     if (zone->signconf->dnskey_ttl) {
  212         ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
  213     }
  214     /* publish keys */
  215     for (i=0; i < zone->signconf->keys->count; i++) {
  216         if (!zone->signconf->keys->keys[i].publish) {
  217             continue;
  218         }
  219         if (!zone->signconf->keys->keys[i].dnskey) {
  220             /* get dnskey */
  221             if  (zone->signconf->keys->keys[i].resourcerecord) {
  222                 if ((status = rrset_getliteralrr(&zone->signconf->keys->keys[i].dnskey, zone->signconf->keys->keys[i].resourcerecord, ttl, zone->apex)) != ODS_STATUS_OK) {
  223                     ods_log_error("[%s] unable to publish dnskeys for zone %s: "
  224                             "error decoding literal dnskey", zone_str, zone->name);
  225                     if (!skip_hsm_access) {
  226                         hsm_destroy_context(ctx);
  227                     }
  228                     return status;
  229                 }
  230             } else {
  231                 status = lhsm_get_key(ctx, zone->apex,
  232                         &zone->signconf->keys->keys[i], skip_hsm_access);
  233                 if (status != ODS_STATUS_OK) {
  234                     ods_log_error("[%s] unable to publish dnskeys for zone %s: "
  235                             "error creating dnskey", zone_str, zone->name);
  236                     break;
  237                 }
  238             }
  239         }
  240         ods_log_debug("[%s] publish %s DNSKEY locator %s", zone_str,
  241             zone->name, zone->signconf->keys->keys[i].locator);
  242         if (!skip_hsm_access) {
  243             ods_log_assert(zone->signconf->keys->keys[i].dnskey);
  244             ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl);
  245             ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass);
  246             status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0);
  247             if (status == ODS_STATUS_UNCHANGED) {
  248                 /* rr already exists, adjust pointer */
  249                 rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
  250                 ods_log_assert(rrset);
  251                 dnskey = rrset_lookup_rr(rrset,
  252                     zone->signconf->keys->keys[i].dnskey);
  253                 ods_log_assert(dnskey);
  254                 if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) {
  255                     ldns_rr_free(zone->signconf->keys->keys[i].dnskey);
  256                 }
  257                 zone->signconf->keys->keys[i].dnskey = dnskey->rr;
  258                 status = ODS_STATUS_OK;
  259             } else if (status != ODS_STATUS_OK) {
  260                 ods_log_error("[%s] unable to publish dnskeys for zone %s: "
  261                     "error adding dnskey", zone_str, zone->name);
  262                 break;
  263             }
  264         }
  265     }
  266     /* done */
  267     if (!skip_hsm_access) {
  268         hsm_destroy_context(ctx);
  269     }
  270     return status;
  271 }
  272 
  273 
  274 /**
  275  * Unlink DNSKEY RRs.
  276  *
  277  */
  278 void
  279 zone_rollback_dnskeys(zone_type* zone)
  280 {
  281     uint16_t i = 0;
  282     rrset_type* rrset = NULL;
  283     rr_type* dnskey = NULL;
  284     if (!zone || !zone->signconf || !zone->signconf->keys) {
  285         return;
  286     }
  287     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY);
  288     /* unlink dnskey rrs */
  289     for (i=0; i < zone->signconf->keys->count; i++) {
  290         if (rrset && zone->signconf->keys->keys[i].dnskey) {
  291             dnskey = rrset_lookup_rr(rrset,
  292                 zone->signconf->keys->keys[i].dnskey);
  293             if (dnskey && !dnskey->exists &&
  294                 dnskey->rr == zone->signconf->keys->keys[i].dnskey) {
  295                 zone->signconf->keys->keys[i].dnskey = NULL;
  296             }
  297         }
  298     }
  299 }
  300 
  301 
  302 /**
  303  * Publish the NSEC3 parameters as indicated by the signer configuration.
  304  *
  305  */
  306 ods_status
  307 zone_publish_nsec3param(zone_type* zone)
  308 {
  309     rrset_type* rrset = NULL;
  310     rr_type* n3prr = NULL;
  311     ldns_rr* rr = NULL;
  312     ods_status status = ODS_STATUS_OK;
  313 
  314     if (!zone || !zone->name || !zone->db || !zone->signconf) {
  315         return ODS_STATUS_ASSERT_ERR;
  316     }
  317     if (!zone->signconf->nsec3params) {
  318         /* NSEC */
  319         ods_log_assert(zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC);
  320         return ODS_STATUS_OK;
  321     }
  322 
  323     if (!zone->signconf->nsec3params->rr) {
  324         uint32_t paramttl =
  325             (uint32_t) duration2time(zone->signconf->nsec3param_ttl);
  326         rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
  327         if (!rr) {
  328             ods_log_error("[%s] unable to publish nsec3params for zone %s: "
  329                 "error creating rr (%s)", zone_str, zone->name,
  330                 ods_status2str(status));
  331             return ODS_STATUS_MALLOC_ERR;
  332         }
  333         ldns_rr_set_class(rr, zone->klass);
  334         ldns_rr_set_ttl(rr, paramttl);
  335         ldns_rr_set_owner(rr, ldns_rdf_clone(zone->apex));
  336         ldns_nsec3_add_param_rdfs(rr,
  337             zone->signconf->nsec3params->algorithm, 0,
  338             zone->signconf->nsec3params->iterations,
  339             zone->signconf->nsec3params->salt_len,
  340             zone->signconf->nsec3params->salt_data);
  341         /**
  342          * Always set bit 7 of the flags to zero,
  343          * according to rfc5155 section 11
  344          */
  345         ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(rr, 1)), 7, 0);
  346         zone->signconf->nsec3params->rr = rr;
  347     }
  348 
  349     /* Delete all nsec3param rrs. */
  350     (void) zone_del_nsec3params(zone);
  351 
  352     ods_log_assert(zone->signconf->nsec3params->rr);
  353     status = zone_add_rr(zone, ldns_rr_clone(zone->signconf->nsec3params->rr), 0);
  354     if (status == ODS_STATUS_UNCHANGED) {
  355         status = ODS_STATUS_OK;
  356     } else if (status != ODS_STATUS_OK) {
  357         ods_log_error("[%s] unable to publish nsec3params for zone %s: "
  358             "error adding nsec3params (%s)", zone_str,
  359             zone->name, ods_status2str(status));
  360     }
  361     return status;
  362 }
  363 
  364 
  365 /**
  366  * Unlink NSEC3PARAM RR.
  367  *
  368  */
  369 void
  370 zone_rollback_nsec3param(zone_type* zone)
  371 {
  372     rrset_type* rrset = NULL;
  373     rr_type* n3prr = NULL;
  374 
  375     if (!zone || !zone->signconf || !zone->signconf->nsec3params) {
  376         return;
  377     }
  378     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_NSEC3PARAMS);
  379     if (rrset && zone->signconf->nsec3params->rr) {
  380         n3prr = rrset_lookup_rr(rrset, zone->signconf->nsec3params->rr);
  381         if (n3prr && !n3prr->exists &&
  382             n3prr->rr == zone->signconf->nsec3params->rr) {
  383             zone->signconf->nsec3params->rr = NULL;
  384         }
  385     }
  386 }
  387 
  388 
  389 /**
  390  * Prepare keys for signing.
  391  *
  392  */
  393 ods_status
  394 zone_prepare_keys(zone_type* zone)
  395 {
  396     hsm_ctx_t* ctx = NULL;
  397     uint16_t i = 0;
  398     ods_status status = ODS_STATUS_OK;
  399 
  400     if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) {
  401         return ODS_STATUS_ASSERT_ERR;
  402     }
  403     ods_log_assert(zone->name);
  404     /* hsm access */
  405     ctx = hsm_create_context();
  406     if (ctx == NULL) {
  407         ods_log_error("[%s] unable to prepare signing keys for zone %s: "
  408             "error creating libhsm context", zone_str, zone->name);
  409         return ODS_STATUS_HSM_ERR;
  410     }
  411     /* prepare keys */
  412     for (i=0; i < zone->signconf->keys->count; i++) {
  413         if(zone->signconf->dnskey_signature != NULL && zone->signconf->keys->keys[i].ksk)
  414             continue;
  415         /* get dnskey */
  416         status = lhsm_get_key(ctx, zone->apex, &zone->signconf->keys->keys[i], 0);
  417         if (status != ODS_STATUS_OK) {
  418             ods_log_error("[%s] unable to prepare signing keys for zone %s: "
  419                 "error getting dnskey", zone_str, zone->name);
  420             break;
  421         }
  422         ods_log_assert(zone->signconf->keys->keys[i].dnskey);
  423         ods_log_assert(zone->signconf->keys->keys[i].params);
  424     }
  425     /* done */
  426     hsm_destroy_context(ctx);
  427     return status;
  428 }
  429 
  430 
  431 /**
  432  * Update serial.
  433  *
  434  */
  435 ods_status
  436 zone_update_serial(zone_type* zone)
  437 {
  438     ods_status status = ODS_STATUS_OK;
  439     rrset_type* rrset = NULL;
  440     rr_type* soa = NULL;
  441     ldns_rr* rr = NULL;
  442     ldns_rdf* soa_rdata = NULL;
  443 
  444     ods_log_assert(zone);
  445     ods_log_assert(zone->apex);
  446     ods_log_assert(zone->name);
  447     ods_log_assert(zone->db);
  448     ods_log_assert(zone->signconf);
  449 
  450     if (zone->db->serial_updated) {
  451         /* already done, unmark and return ok */
  452         ods_log_debug("[%s] zone %s soa serial already up to date",
  453             zone_str, zone->name);
  454         zone->db->serial_updated = 0;
  455         return ODS_STATUS_OK;
  456     }
  457     rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_SOA);
  458     if (!rrset || !rrset->rrs || !rrset->rrs[0].rr) {
  459         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
  460             "find soa rrset", zone_str, zone->name);
  461         return ODS_STATUS_ERR;
  462     }
  463     ods_log_assert(rrset);
  464     ods_log_assert(rrset->rrs);
  465     ods_log_assert(rrset->rrs[0].rr);
  466     rr = ldns_rr_clone(rrset->rrs[0].rr);
  467     if (!rr) {
  468         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
  469             "clone soa rr", zone_str, zone->name);
  470         return ODS_STATUS_ERR;
  471     }
  472     status = namedb_update_serial(zone->db, zone->name,
  473         zone->signconf->soa_serial, zone->db->inbserial);
  474     if (status != ODS_STATUS_OK) {
  475         ods_log_error("[%s] unable to update zone %s soa serial: %s",
  476             zone_str, zone->name, ods_status2str(status));
  477         if (status == ODS_STATUS_CONFLICT_ERR) {
  478             ods_log_error("[%s] If this is the result of a key rollover, "
  479                 "please increment the serial in the unsigned zone %s",
  480                 zone_str, zone->name);
  481         }
  482         ldns_rr_free(rr);
  483         return status;
  484     }
  485     ods_log_verbose("[%s] zone %s set soa serial to %u", zone_str,
  486         zone->name, zone->db->intserial);
  487     soa_rdata = ldns_rr_set_rdf(rr,
  488         ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
  489         zone->db->intserial), SE_SOA_RDATA_SERIAL);
  490     if (soa_rdata) {
  491         ldns_rdf_deep_free(soa_rdata);
  492         soa_rdata = NULL;
  493     } else {
  494         ods_log_error("[%s] unable to update zone %s soa serial: failed to "
  495             "replace soa serial rdata", zone_str, zone->name);
  496         ldns_rr_free(rr);
  497         return ODS_STATUS_ERR;
  498     }
  499     soa = rrset_add_rr(rrset, rr);
  500     ods_log_assert(soa);
  501     rrset_diff(rrset, 0, 0);
  502     zone->db->serial_updated = 0;
  503     return ODS_STATUS_OK;
  504 }
  505 
  506 
  507 /**
  508  * Lookup RRset.
  509  *
  510  */
  511 rrset_type*
  512 zone_lookup_rrset(zone_type* zone, ldns_rdf* owner, ldns_rr_type type)
  513 {
  514     domain_type* domain = NULL;
  515     if (!zone || !owner || !type) {
  516         return NULL;
  517     }
  518     domain = namedb_lookup_domain(zone->db, owner);
  519     if (!domain) {
  520         return NULL;
  521     }
  522     return domain_lookup_rrset(domain, type);
  523 }
  524 
  525 
  526 /**
  527  * Add RR.
  528  *
  529  */
  530 ods_status
  531 zone_add_rr(zone_type* zone, ldns_rr* rr, int do_stats)
  532 {
  533     domain_type* domain = NULL;
  534     rrset_type* rrset = NULL;
  535     rr_type* record = NULL;
  536     ods_status status = ODS_STATUS_OK;
  537 
  538     ods_log_assert(rr);
  539     ods_log_assert(zone);
  540     ods_log_assert(zone->name);
  541     ods_log_assert(zone->db);
  542     ods_log_assert(zone->signconf);
  543     /* If we already have this RR, return ODS_STATUS_UNCHANGED */
  544     domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
  545     if (!domain) {
  546         domain = namedb_add_domain(zone->db, ldns_rr_owner(rr));
  547         if (!domain) {
  548             ods_log_error("[%s] unable to add RR to zone %s: "
  549                 "failed to add domain", zone_str, zone->name);
  550             return ODS_STATUS_ERR;
  551         }
  552         if (ldns_dname_compare(domain->dname, zone->apex) == 0) {
  553             domain->is_apex = 1;
  554         } else {
  555             status = namedb_domain_entize(zone->db, domain, zone->apex);
  556             if (status != ODS_STATUS_OK) {
  557                 ods_log_error("[%s] unable to add RR to zone %s: "
  558                     "failed to entize domain", zone_str, zone->name);
  559                 return ODS_STATUS_ERR;
  560             }
  561         }
  562     }
  563     rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
  564     if (!rrset) {
  565         rrset = rrset_create(domain->zone, ldns_rr_get_type(rr));
  566         if (!rrset) {
  567             ods_log_error("[%s] unable to add RR to zone %s: "
  568                 "failed to add RRset", zone_str, zone->name);
  569             return ODS_STATUS_ERR;
  570         }
  571         domain_add_rrset(domain, rrset);
  572     }
  573     record = rrset_lookup_rr(rrset, rr);
  574 
  575     uint32_t ttl_rr = ldns_rr_ttl(rr);
  576     uint32_t ttl_rrset = rrset_lookup_ttl(rrset, ttl_rr);
  577 
  578     if (record && ttl_rr == ttl_rrset && ttl_rr == ldns_rr_ttl(record->rr)) {
  579         record->is_added = 1; /* already exists, just mark added */
  580         record->is_removed = 0; /* unset is_removed */
  581         return ODS_STATUS_UNCHANGED;
  582     } else {
  583         record = rrset_add_rr(rrset, rr);
  584         ods_log_assert(record);
  585         ods_log_assert(record->rr);
  586         ods_log_assert(record->is_added);
  587         if (ttl_rr != ttl_rrset) {
  588             char *str = ldns_rr2str(rr);
  589             str[(strlen(str)) - 1] = '\0';
  590             for (int i = 0; i < strlen(str); i++) {
  591                 if (str[i] == '\t') {
  592                     str[i] = ' ';
  593                 }
  594             }
  595             ods_log_error("In zone file %s: TTL for the record '%s' (%d) not"
  596                 " equal to recordset TTL (%d)", zone->name, str, ttl_rr, ttl_rrset);
  597             LDNS_FREE(str);
  598         }
  599     }
  600     /* update stats */
  601     if (do_stats && zone->stats) {
  602         zone->stats->sort_count += 1;
  603     }
  604     return ODS_STATUS_OK;
  605 }
  606 
  607 
  608 /**
  609  * Delete RR.
  610  *
  611  */
  612 ods_status
  613 zone_del_rr(zone_type* zone, ldns_rr* rr, int do_stats)
  614 {
  615     domain_type* domain = NULL;
  616     rrset_type* rrset = NULL;
  617     rr_type* record = NULL;
  618     ods_log_assert(rr);
  619     ods_log_assert(zone);
  620     ods_log_assert(zone->name);
  621     ods_log_assert(zone->db);
  622     ods_log_assert(zone->signconf);
  623     domain = namedb_lookup_domain(zone->db, ldns_rr_owner(rr));
  624     if (!domain) {
  625         ods_log_warning("[%s] unable to delete RR from zone %s: "
  626             "domain not found", zone_str, zone->name);
  627         return ODS_STATUS_UNCHANGED;
  628     }
  629     rrset = domain_lookup_rrset(domain, ldns_rr_get_type(rr));
  630     if (!rrset) {
  631         ods_log_warning("[%s] unable to delete RR from zone %s: "
  632             "RRset not found", zone_str, zone->name);
  633         return ODS_STATUS_UNCHANGED;
  634     }
  635     record = rrset_lookup_rr(rrset, rr);
  636     if (!record) {
  637         ods_log_error("[%s] unable to delete RR from zone %s: "
  638             "RR not found", zone_str, zone->name);
  639         return ODS_STATUS_UNCHANGED;
  640     }
  641 
  642     record->is_removed = 1;
  643     record->is_added = 0; /* unset is_added */
  644     /* update stats */
  645     if (do_stats && zone->stats) {
  646         zone->stats->sort_count -= 1;
  647     }
  648     return ODS_STATUS_OK;
  649 }
  650 
  651 /**
  652  * Delete NSEC3PARAM RRs.
  653  *
  654  * Marks all NSEC3PARAM records as removed.
  655  */
  656 ods_status
  657 zone_del_nsec3params(zone_type* zone)
  658 {
  659     domain_type* domain = NULL;
  660     rrset_type* rrset = NULL;
  661     int i;
  662 
  663     ods_log_assert(zone);
  664     ods_log_assert(zone->name);
  665     ods_log_assert(zone->db);
  666 
  667     domain = namedb_lookup_domain(zone->db, zone->apex);
  668     if (!domain) {
  669         ods_log_verbose("[%s] unable to delete RR from zone %s: "
  670             "domain not found", zone_str, zone->name);
  671         return ODS_STATUS_UNCHANGED;
  672     }
  673 
  674     rrset = domain_lookup_rrset(domain, LDNS_RR_TYPE_NSEC3PARAMS);
  675     if (!rrset) {
  676         ods_log_verbose("[%s] NSEC3PARAM in zone %s not found: "
  677             "skipping delete", zone_str, zone->name);
  678         return ODS_STATUS_UNCHANGED;
  679     }
  680 
  681     /* We don't actually delete the record as we still need the
  682      * information in the IXFR. Just set it as removed. The code
  683      * inserting the new record may flip this flag when the record
  684      * hasn't changed. */
  685     for (i=0; i < rrset->rr_count; i++) {
  686         rrset->rrs[i].is_removed = 1;
  687     }
  688     return ODS_STATUS_OK;
  689 }
  690 
  691 /**
  692  * Merge zones.
  693  *
  694  */
  695 void
  696 zone_merge(zone_type* z1, zone_type* z2)
  697 {
  698     const char* str;
  699     adapter_type* adtmp = NULL;
  700 
  701     if (!z1 || !z2) {
  702         return;
  703     }
  704     /* policy name */
  705     if (ods_strcmp(z2->policy_name, z1->policy_name) != 0) {
  706         if (z2->policy_name) {
  707             str = strdup(z2->policy_name);
  708             if (!str) {
  709                 ods_log_error("[%s] failed to merge policy %s name to zone "
  710                     "%s", zone_str, z2->policy_name, z1->name);
  711             } else {
  712                 free((void*)z1->policy_name);
  713                 z1->policy_name = str;
  714                 z1->zl_status = ZONE_ZL_UPDATED;
  715             }
  716         } else {
  717             free((void*)z1->policy_name);
  718             z1->policy_name = NULL;
  719             z1->zl_status = ZONE_ZL_UPDATED;
  720         }
  721     }
  722     /* signconf filename */
  723     if (ods_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
  724         if (z2->signconf_filename) {
  725             str = strdup(z2->signconf_filename);
  726             if (!str) {
  727                 ods_log_error("[%s] failed to merge signconf filename %s to "
  728                     "zone %s", zone_str, z2->policy_name, z1->name);
  729             } else {
  730                 free((void*)z1->signconf_filename);
  731                 z1->signconf_filename = str;
  732                 z1->zl_status = ZONE_ZL_UPDATED;
  733             }
  734         } else {
  735             free((void*)z1->signconf_filename);
  736             z1->signconf_filename = NULL;
  737             z1->zl_status = ZONE_ZL_UPDATED;
  738         }
  739     }
  740     /* adapters */
  741     if (adapter_compare(z2->adinbound, z1->adinbound) != 0) {
  742         adtmp = z2->adinbound;
  743         z2->adinbound = z1->adinbound;
  744         z1->adinbound = adtmp;
  745         adtmp = NULL;
  746     }
  747     if (adapter_compare(z2->adoutbound, z1->adoutbound) != 0) {
  748         adtmp = z2->adoutbound;
  749         z2->adoutbound = z1->adoutbound;
  750         z1->adoutbound = adtmp;
  751         adtmp = NULL;
  752     }
  753 }
  754 
  755 
  756 /**
  757  * Clean up zone.
  758  *
  759  */
  760 void
  761 zone_cleanup(zone_type* zone)
  762 {
  763     if (!zone) {
  764         return;
  765     }
  766 pthread_mutex_lock(&zone->zone_lock);
  767     ldns_rdf_deep_free(zone->apex);
  768     adapter_cleanup(zone->adinbound);
  769     adapter_cleanup(zone->adoutbound);
  770     namedb_cleanup(zone->db);
  771     ixfr_cleanup(zone->ixfr);
  772     xfrd_cleanup(zone->xfrd, 1);
  773     notify_cleanup(zone->notify);
  774     signconf_cleanup(zone->signconf);
  775 pthread_mutex_unlock(&zone->zone_lock);
  776     stats_cleanup(zone->stats);
  777     free(zone->notify_command);
  778     free(zone->notify_args);
  779     free((void*)zone->policy_name);
  780     free((void*)zone->signconf_filename);
  781     free((void*)zone->name);
  782     collection_class_destroy(&zone->rrstore);
  783     pthread_mutex_destroy(&zone->xfr_lock);
  784     pthread_mutex_destroy(&zone->zone_lock);
  785     free(zone);
  786 }
  787 
  788 
  789 /**
  790  * Recover zone from backup.
  791  *
  792  */
  793 ods_status
  794 zone_recover2(engine_type* engine, zone_type* zone)
  795 {
  796     char* filename = NULL;
  797     FILE* fd = NULL;
  798     const char* token = NULL;
  799     time_t when = 0;
  800     ods_status status = ODS_STATUS_OK;
  801     /* zone part */
  802     int klass = 0;
  803     uint32_t inbound = 0, internal = 0, outbound = 0;
  804     /* signconf part */
  805     time_t lastmod = 0;
  806     /* nsec3params part */
  807     const char* salt = NULL;
  808 
  809     ods_log_assert(zone);
  810     ods_log_assert(zone->name);
  811     ods_log_assert(zone->signconf);
  812     ods_log_assert(zone->db);
  813 
  814     filename = ods_build_path(zone->name, ".backup2", 0, 1);
  815     if (!filename) {
  816         return ODS_STATUS_MALLOC_ERR;
  817     }
  818     fd = ods_fopen(filename, NULL, "r");
  819     if (fd) {
  820         /* start recovery */
  821         if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) {
  822             ods_log_error("[%s] corrupted backup file zone %s: read magic "
  823                 "error", zone_str, zone->name);
  824             goto recover_error2;
  825         }
  826         if (!backup_read_check_str(fd, ";;Time:") |
  827             !backup_read_time_t(fd, &when)) {
  828             ods_log_error("[%s] corrupted backup file zone %s: read time "
  829                 "error", zone_str, zone->name);
  830             goto recover_error2;
  831         }
  832         /* zone stuff */
  833         if (!backup_read_check_str(fd, ";;Zone:") |
  834             !backup_read_check_str(fd, "name") |
  835             !backup_read_check_str(fd, zone->name)) {
  836             ods_log_error("[%s] corrupted backup file zone %s: read name "
  837                 "error", zone_str, zone->name);
  838             goto recover_error2;
  839         }
  840         if (!backup_read_check_str(fd, "class") |
  841             !backup_read_int(fd, &klass)) {
  842             ods_log_error("[%s] corrupted backup file zone %s: read class "
  843                 "error", zone_str, zone->name);
  844             goto recover_error2;
  845         }
  846         if (!backup_read_check_str(fd, "inbound") |
  847             !backup_read_uint32_t(fd, &inbound) |
  848             !backup_read_check_str(fd, "internal") |
  849             !backup_read_uint32_t(fd, &internal) |
  850             !backup_read_check_str(fd, "outbound") |
  851             !backup_read_uint32_t(fd, &outbound)) {
  852             ods_log_error("[%s] corrupted backup file zone %s: read serial "
  853                 "error", zone_str, zone->name);
  854             goto recover_error2;
  855         }
  856         zone->klass = (ldns_rr_class) klass;
  857         zone->db->inbserial = inbound;
  858         zone->db->intserial = internal;
  859         zone->db->outserial = outbound;
  860         /* signconf part */
  861         if (!backup_read_check_str(fd, ";;Signconf:") |
  862             !backup_read_check_str(fd, "lastmod") |
  863             !backup_read_time_t(fd, &lastmod) |
  864             !backup_read_check_str(fd, "maxzonettl") |
  865             !backup_read_check_str(fd, "0") |
  866             !backup_read_check_str(fd, "resign") |
  867             !backup_read_duration(fd, &zone->signconf->sig_resign_interval) |
  868             !backup_read_check_str(fd, "refresh") |
  869             !backup_read_duration(fd, &zone->signconf->sig_refresh_interval) |
  870             !backup_read_check_str(fd, "valid") |
  871             !backup_read_duration(fd, &zone->signconf->sig_validity_default) |
  872             !backup_read_check_str(fd, "denial") |
  873             !backup_read_duration(fd,&zone->signconf->sig_validity_denial) |
  874             !backup_read_check_str(fd, "keyset") |
  875             !backup_read_duration(fd,&zone->signconf->sig_validity_keyset) |
  876             !backup_read_check_str(fd, "jitter") |
  877             !backup_read_duration(fd, &zone->signconf->sig_jitter) |
  878             !backup_read_check_str(fd, "offset") |
  879             !backup_read_duration(fd, &zone->signconf->sig_inception_offset) |
  880             !backup_read_check_str(fd, "nsec") |
  881             !backup_read_rr_type(fd, &zone->signconf->nsec_type) |
  882             !backup_read_check_str(fd, "dnskeyttl") |
  883             !backup_read_duration(fd, &zone->signconf->dnskey_ttl) |
  884             !backup_read_check_str(fd, "soattl") |
  885             !backup_read_duration(fd, &zone->signconf->soa_ttl) |
  886             !backup_read_check_str(fd, "soamin") |
  887             !backup_read_duration(fd, &zone->signconf->soa_min) |
  888             !backup_read_check_str(fd, "serial") |
  889             !backup_read_str(fd, &zone->signconf->soa_serial)) {
  890             ods_log_error("[%s] corrupted backup file zone %s: read signconf "
  891                 "error", zone_str, zone->name);
  892             goto recover_error2;
  893         }
  894         /* nsec3params part */
  895         if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
  896             if (!backup_read_check_str(fd, ";;Nsec3parameters:") |
  897                 !backup_read_check_str(fd, "salt") |
  898                 !backup_read_str(fd, &salt) |
  899                 !backup_read_check_str(fd, "algorithm") |
  900                 !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) |
  901                 !backup_read_check_str(fd, "optout") |
  902                 !backup_read_int(fd, &zone->signconf->nsec3_optout) |
  903                 !backup_read_check_str(fd, "iterations") |
  904                 !backup_read_uint32_t(fd, &zone->signconf->nsec3_iterations)) {
  905                 ods_log_error("[%s] corrupted backup file zone %s: read "
  906                     "nsec3parameters error", zone_str, zone->name);
  907                 goto recover_error2;
  908             }
  909             zone->signconf->nsec3_salt = strdup(salt);
  910             free((void*) salt);
  911             salt = NULL;
  912             zone->signconf->nsec3params = nsec3params_create(
  913                 zone->signconf,
  914                 (uint8_t) zone->signconf->nsec3_algo,
  915                 (uint8_t) zone->signconf->nsec3_optout,
  916                 (uint16_t) zone->signconf->nsec3_iterations,
  917                 zone->signconf->nsec3_salt);
  918             if (!zone->signconf->nsec3params) {
  919                 ods_log_error("[%s] corrupted backup file zone %s: unable to "
  920                     "create nsec3param", zone_str, zone->name);
  921                 goto recover_error2;
  922             }
  923         }
  924         zone->signconf->last_modified = lastmod;
  925         zone->zoneconfigvalid = 1;
  926         zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min);
  927         /* keys part */
  928         zone->signconf->keys = keylist_create((void*) zone->signconf);
  929         while (backup_read_str(fd, &token)) {
  930             if (ods_strcmp(token, ";;Key:") == 0) {
  931                 if (!key_recover2(fd, zone->signconf->keys)) {
  932                     ods_log_error("[%s] corrupted backup file zone %s: read "
  933                         "key error", zone_str, zone->name);
  934                     goto recover_error2;
  935                 }
  936             } else if (ods_strcmp(token, ";;") == 0) {
  937                 /* keylist done */
  938                 free((void*) token);
  939                 token = NULL;
  940                 break;
  941             } else {
  942                 /* keylist corrupted */
  943                 goto recover_error2;
  944             }
  945             free((void*) token);
  946             token = NULL;
  947         }
  948         /* publish dnskeys */
  949         status = zone_publish_dnskeys(zone, 1);
  950         if (status != ODS_STATUS_OK) {
  951             ods_log_error("[%s] corrupted backup file zone %s: unable to "
  952                 "publish dnskeys (%s)", zone_str, zone->name,
  953                 ods_status2str(status));
  954             goto recover_error2;
  955         }
  956         /* publish nsec3param */
  957         if (!zone->signconf->passthrough)
  958             status = zone_publish_nsec3param(zone);
  959         if (status != ODS_STATUS_OK) {
  960             ods_log_error("[%s] corrupted backup file zone %s: unable to "
  961                 "publish nsec3param (%s)", zone_str, zone->name,
  962                 ods_status2str(status));
  963             goto recover_error2;
  964         }
  965         /* publish other records */
  966         status = backup_read_namedb(fd, zone);
  967         if (status != ODS_STATUS_OK) {
  968             ods_log_error("[%s] corrupted backup file zone %s: unable to "
  969                 "read resource records (%s)", zone_str, zone->name,
  970                 ods_status2str(status));
  971             goto recover_error2;
  972         }
  973         /* task */
  974         schedule_scheduletask(engine->taskq, TASK_SIGN, zone->name, zone, &zone->zone_lock, schedule_PROMPTLY);
  975         free((void*)filename);
  976         ods_fclose(fd);
  977         zone->db->is_initialized = 1;
  978         zone->db->have_serial = 1;
  979         /* journal */
  980         filename = ods_build_path(zone->name, ".ixfr", 0, 1);
  981         if (filename) {
  982             fd = ods_fopen(filename, NULL, "r");
  983         }
  984         if (fd) {
  985             status = backup_read_ixfr(fd, zone);
  986             if (status != ODS_STATUS_OK) {
  987                 ods_log_warning("[%s] corrupted journal file zone %s, "
  988                     "skipping (%s)", zone_str, zone->name,
  989                     ods_status2str(status));
  990                 (void)unlink(filename);
  991                 ixfr_cleanup(zone->ixfr);
  992                 zone->ixfr = ixfr_create();
  993             }
  994         }
  995         pthread_mutex_lock(&zone->ixfr->ixfr_lock);
  996         ixfr_purge(zone->ixfr, zone->name);
  997         pthread_mutex_unlock(&zone->ixfr->ixfr_lock);
  998 
  999         /* all ok */
 1000         free((void*)filename);
 1001         if (fd) {
 1002             ods_fclose(fd);
 1003         }
 1004         if (zone->stats) {
 1005             pthread_mutex_lock(&zone->stats->stats_lock);
 1006             stats_clear(zone->stats);
 1007             pthread_mutex_unlock(&zone->stats->stats_lock);
 1008         }
 1009         return ODS_STATUS_OK;
 1010     }
 1011     free(filename);
 1012     return ODS_STATUS_UNCHANGED;
 1013 
 1014 recover_error2:
 1015     free((void*)filename);
 1016     ods_fclose(fd);
 1017     /* signconf cleanup */
 1018     free((void*)salt);
 1019     salt = NULL;
 1020     signconf_cleanup(zone->signconf);
 1021     zone->signconf = signconf_create();
 1022     ods_log_assert(zone->signconf);
 1023     /* namedb cleanup */
 1024     namedb_cleanup(zone->db);
 1025     zone->db = namedb_create((void*)zone);
 1026     ods_log_assert(zone->db);
 1027     /* stats reset */
 1028     if (zone->stats) {
 1029        pthread_mutex_lock(&zone->stats->stats_lock);
 1030        stats_clear(zone->stats);
 1031        pthread_mutex_unlock(&zone->stats->stats_lock);
 1032     }
 1033     return ODS_STATUS_ERR;
 1034 }
 1035 
 1036 
 1037 /**
 1038  * Backup zone.
 1039  *
 1040  */
 1041 ods_status
 1042 zone_backup2(zone_type* zone, time_t nextResign)
 1043 {
 1044     char* filename = NULL;
 1045     char* tmpfile = NULL;
 1046     FILE* fd = NULL;
 1047     int ret = 0;
 1048     ods_status status = ODS_STATUS_OK;
 1049 
 1050     ods_log_assert(zone);
 1051     ods_log_assert(zone->name);
 1052     ods_log_assert(zone->db);
 1053     ods_log_assert(zone->signconf);
 1054 
 1055     tmpfile = ods_build_path(zone->name, ".backup2.tmp", 0, 1);
 1056     filename = ods_build_path(zone->name, ".backup2", 0, 1);
 1057     if (!tmpfile || !filename) {
 1058         free(tmpfile);
 1059         free(filename);
 1060         return ODS_STATUS_MALLOC_ERR;
 1061     }
 1062     fd = ods_fopen(tmpfile, NULL, "w");
 1063     if (fd) {
 1064         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
 1065         fprintf(fd, ";;Time: %u\n", (unsigned) nextResign);
 1066         /** Backup zone */
 1067         fprintf(fd, ";;Zone: name %s class %i inbound %u internal %u "
 1068             "outbound %u\n", zone->name, (int) zone->klass,
 1069             (unsigned) zone->db->inbserial,
 1070             (unsigned) zone->db->intserial,
 1071             (unsigned) zone->db->outserial);
 1072         /** Backup signconf */
 1073         signconf_backup(fd, zone->signconf, ODS_SE_FILE_MAGIC_V3);
 1074         /** Backup NSEC3 parameters */
 1075         if (zone->signconf->nsec3params) {
 1076             nsec3params_backup(fd,
 1077                 zone->signconf->nsec3_algo,
 1078                 zone->signconf->nsec3_optout,
 1079                 zone->signconf->nsec3_iterations,
 1080                 zone->signconf->nsec3_salt,
 1081                 zone->signconf->nsec3params->rr,
 1082                 ODS_SE_FILE_MAGIC_V3);
 1083         }
 1084         /** Backup keylist */
 1085         keylist_backup(fd, zone->signconf->keys, ODS_SE_FILE_MAGIC_V3);
 1086         fprintf(fd, ";;\n");
 1087         /** Backup domains and stuff */
 1088         namedb_backup2(fd, zone->db);
 1089         /** Done */
 1090         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC_V3);
 1091         ods_fclose(fd);
 1092         ret = rename(tmpfile, filename);
 1093         if (ret != 0) {
 1094             ods_log_error("[%s] unable to rename zone %s backup %s to %s: %s",
 1095                 zone_str, zone->name, tmpfile, filename, strerror(errno));
 1096             status = ODS_STATUS_RENAME_ERR;
 1097         }
 1098     } else {
 1099         status = ODS_STATUS_FOPEN_ERR;
 1100     }
 1101 
 1102     free((void*) tmpfile);
 1103     free((void*) filename);
 1104     return status;
 1105 }