OpenDNSSEC-signer 1.2.1

/build/buildd-opendnssec_1.2.1.dfsg-1-ia64-j6OroR/opendnssec-1.2.1.dfsg/signer/src/signer/zone.c

Go to the documentation of this file.
00001 /*
00002  * $Id: zone.c 4521 2011-03-01 14:56:15Z matthijs $
00003  *
00004  * Copyright (c) 2009 NLNet Labs. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  */
00028 
00034 #include "adapter/adapter.h"
00035 #include "scheduler/locks.h"
00036 #include "scheduler/task.h"
00037 #include "signer/backup.h"
00038 #include "signer/hsm.h"
00039 #include "signer/nsec3params.h"
00040 #include "signer/signconf.h"
00041 #include "signer/zone.h"
00042 #include "signer/zonedata.h"
00043 #include "util/duration.h"
00044 #include "util/file.h"
00045 #include "util/log.h"
00046 #include "util/se_malloc.h"
00047 #include "util/util.h"
00048 
00049 #include <ldns/ldns.h> /* ldns_*() */
00050 #include <libhsm.h> /* hsm_create_context(), hsm_get_key(), hsm_destroy_context() */
00051 #include <libhsmdns.h> /* hsm_create_context(), hsm_get_key(), hsm_destroy_context() */
00052 
00053 
00058 zone_type*
00059 zone_create(const char* name, ldns_rr_class klass)
00060 {
00061     zone_type* zone = (zone_type*) se_calloc(1, sizeof(zone_type));
00062     se_log_assert(name);
00063     se_log_debug("create zone %s", name?name:"(null)");
00064     zone->name = se_strdup(name);
00065     zone->dname = ldns_dname_new_frm_str(name);
00066     ldns_dname2canonical(zone->dname);
00067     zone->klass = klass;
00068     zone->notify_ns = NULL;
00069     zone->policy_name = NULL;
00070     zone->signconf_filename = NULL;
00071     zone->signconf = NULL;
00072     zone->nsec3params = NULL;
00073     zone->inbound_adapter = NULL;
00074     zone->outbound_adapter = NULL;
00075     zone->task = NULL;
00076     zone->backoff = 0;
00077     zone->just_added = 0;
00078     zone->just_updated = 0;
00079     zone->tobe_removed = 0;
00080     zone->in_progress = 0;
00081     zone->processed = 0;
00082     zone->fetch = 0;
00083     zone->zonedata = zonedata_create();
00084     zone->stats = stats_create();
00085     lock_basic_init(&zone->zone_lock);
00086     return zone;
00087 }
00088 
00089 
00094 void
00095 zone_update_zonelist(zone_type* z1, zone_type* z2)
00096 {
00097     se_log_assert(z1);
00098     se_log_assert(z2);
00099 
00100     if (se_strcmp(z2->policy_name, z1->policy_name) != 0) {
00101         se_free((void*)z1->policy_name);
00102         if (z2->policy_name) {
00103             z1->policy_name = se_strdup(z2->policy_name);
00104         } else {
00105             z1->policy_name = NULL;
00106         }
00107         z1->just_updated = 1;
00108     }
00109 
00110     if (se_strcmp(z2->signconf_filename, z1->signconf_filename) != 0) {
00111         se_free((void*)z1->signconf_filename);
00112         if (z2->signconf_filename) {
00113             z1->signconf_filename = se_strdup(z2->signconf_filename);
00114         } else {
00115             z1->signconf_filename = NULL;
00116         }
00117         z1->just_updated = 1;
00118     }
00119 
00120     if (adapter_compare(z1->inbound_adapter, z2->inbound_adapter) != 0) {
00121         adapter_cleanup(z1->inbound_adapter);
00122         if (z2->inbound_adapter) {
00123             z1->inbound_adapter = adapter_create(
00124                 z2->inbound_adapter->filename,
00125                 z2->inbound_adapter->type,
00126                 z2->inbound_adapter->inbound);
00127         } else {
00128             z1->inbound_adapter = NULL;
00129         }
00130         z1->just_updated = 1;
00131     }
00132 
00133     if (adapter_compare(z1->outbound_adapter, z2->outbound_adapter) != 0) {
00134         adapter_cleanup(z1->outbound_adapter);
00135         if (z2->outbound_adapter) {
00136             z1->outbound_adapter = adapter_create(
00137                 z2->outbound_adapter->filename,
00138                 z2->outbound_adapter->type,
00139                 z2->outbound_adapter->inbound);
00140         } else {
00141             z1->outbound_adapter = NULL;
00142         }
00143         z1->just_updated = 1;
00144     }
00145 
00146     zone_cleanup(z2);
00147     return;
00148 }
00149 
00150 
00155 int
00156 zone_update_signconf(zone_type* zone, struct tasklist_struct* tl, char* buf)
00157 {
00158     task_type* task = NULL;
00159     signconf_type* signconf = NULL;
00160     ldns_rbnode_t* node = LDNS_RBTREE_NULL;
00161     domain_type* domain = NULL;
00162     time_t last_modified = 0;
00163     time_t now = 0;
00164     int update = 0;
00165 
00166     se_log_assert(zone);
00167     se_log_debug("load zone %s signconf %s",
00168         zone->name?zone->name:"(null)",
00169         zone->signconf_filename?zone->signconf_filename:"(null)");
00170 
00171     if (zone->signconf) {
00172         last_modified = zone->signconf->last_modified;
00173     }
00174 
00175     signconf = signconf_read(zone->signconf_filename, last_modified);
00176     if (!signconf) {
00177         if (!zone->policy_name) {
00178             se_log_warning("zone %s has no policy",
00179                 zone->name?zone->name:"(null)");
00180         } else {
00181             signconf = signconf_read(zone->signconf_filename, 0);
00182             if (!signconf) {
00183                 se_log_warning("zone %s has policy %s configured, "
00184                     "but has no (valid) signconf file",
00185                     zone->name?zone->name:"(null)", zone->policy_name);
00186                 if (buf) {
00187                     (void)snprintf(buf, ODS_SE_MAXLINE,
00188                         "Zone %s config has errors.\n",
00189                              zone->name?zone->name:"(null)");
00190                 }
00191                 return -1;
00192             } else {
00193                 se_log_debug("zone %s has not changed",
00194                     zone->name?zone->name:"(null)");
00195                 signconf_cleanup(signconf);
00196             }
00197         }
00198         if (buf) {
00199             (void)snprintf(buf, ODS_SE_MAXLINE,
00200                 "Zone %s config has not changed.\n",
00201                 zone->name?zone->name:"(null)");
00202         }
00203         return 0;
00204     } else if (signconf_check(signconf) != 0) {
00205         se_log_warning("zone %s signconf has errors",
00206             zone->name?zone->name:"(null)");
00207         if (buf) {
00208             (void)snprintf(buf, ODS_SE_MAXLINE,
00209                 "Zone %s config has errors.\n", zone->name?zone->name:"(null)");
00210         }
00211         return -1;
00212     } else if (!zone->signconf) {
00213         zone->signconf = signconf;
00214         /* we don't check if foo in <Zone name="foo"> matches zone->name */
00215         zone->signconf->name = zone->name;
00216         se_log_debug("zone %s now has signconf",
00217             zone->name?zone->name:"(null)");
00218         signconf_backup(zone->signconf);
00219 
00220         /* zone state? */
00221         /* create task for new zone */
00222         now = time_now();
00223         zone->task = task_create(TASK_READ, now, zone->name, zone);
00224         task = tasklist_schedule_task(tl, zone->task, 0);
00225         if (!task) {
00226             if (buf) {
00227                 (void)snprintf(buf, ODS_SE_MAXLINE, "Zone %s now has config, "
00228                     "but could not be scheduled.\n",
00229                     zone->name?zone->name:"(null)");
00230             }
00231         } else {
00232             if (buf) {
00233                 (void)snprintf(buf, ODS_SE_MAXLINE,
00234                     "Zone %s now has config.\n",
00235                     zone->name?zone->name:"(null)");
00236             }
00237         }
00238         return 1;
00239     } else {
00240         /* update task for new zone */
00241         task = tasklist_delete_task(tl, zone->task);
00242         if (!task) {
00243             se_log_error("cannot update zone %s: delete old task failed",
00244                 zone->name);
00245             if (buf) {
00246                 (void)snprintf(buf, ODS_SE_MAXLINE, "Update zone %s failed.\n",
00247                     zone->name?zone->name:"(null)");
00248             }
00249             return -1;
00250         }
00251 
00252         zone->task->what = signconf_compare(zone->signconf, signconf, &update);
00253         zone->task->when = time_now();
00254         if (update) {
00255             /* destroy NSEC(3) storage */
00256             se_log_debug("destroy old NSEC(3) records for zone %s", zone->name);
00257             if (zone->zonedata && zone->zonedata->denial_chain) {
00258                 zonedata_cleanup_denials(zone->zonedata->denial_chain);
00259                 zone->zonedata->denial_chain = NULL;
00260                 node = ldns_rbtree_first(zone->zonedata->domains);
00261                 while (node && node != LDNS_RBTREE_NULL) {
00262                     domain = (domain_type*) node->data;
00263                     domain->denial = NULL;
00264                     node = ldns_rbtree_next(node);
00265                 }
00266             }
00267             if (zone->nsec3params) {
00268                 nsec3params_cleanup(zone->nsec3params);
00269                 zone->nsec3params = NULL;
00270             }
00271         }
00272 
00273         task = tasklist_schedule_task(tl, zone->task, 0);
00274         if (!task) {
00275             if (buf) {
00276                 (void)snprintf(buf, ODS_SE_MAXLINE,
00277                     "Zone %s config updated, but could not be schedulted.\n",
00278                     zone->name?zone->name:"(null)");
00279             }
00280         } else {
00281             if (buf) {
00282                 (void)snprintf(buf, ODS_SE_MAXLINE,
00283                     "Zone %s config updated.\n", zone->name?zone->name:
00284                     "(null)");
00285             }
00286         }
00287 
00288         signconf_cleanup(zone->signconf);
00289         zone->signconf = signconf;
00290         zone->signconf->name = zone->name;
00291         se_log_debug("zone %s signconf updated",
00292                 zone->name?zone->name:"(null)");
00293             signconf_backup(zone->signconf);
00294         return 1;
00295     }
00296     /* not reached */
00297     return 0;
00298 }
00299 
00300 
00305 static int
00306 zone_publish_dnskeys(zone_type* zone, FILE* fd)
00307 {
00308     key_type* key = NULL;
00309     uint32_t ttl = 0;
00310     size_t count = 0;
00311     int error = 0;
00312     hsm_ctx_t* ctx = NULL;
00313     ldns_rr* dnskey = NULL;
00314 
00315     se_log_assert(zone);
00316     se_log_assert(zone->signconf);
00317     se_log_assert(zone->signconf->keys);
00318     se_log_assert(zone->zonedata);
00319 
00320     ctx = hsm_create_context();
00321     if (ctx == NULL) {
00322         se_log_error("error creating libhsm context");
00323         return 2;
00324     }
00325 
00326     ttl = zone->zonedata->default_ttl;
00327     if (zone->signconf->dnskey_ttl) {
00328         ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
00329     }
00330 
00331     key = zone->signconf->keys->first_key;
00332     for (count=0; count < zone->signconf->keys->count; count++) {
00333         if (key->publish) {
00334             if (!key->dnskey) {
00335                 error = hsm_get_key(ctx, zone->dname, key);
00336                 if (error) {
00337                     se_log_error("error creating DNSKEY for key %s",
00338                         key->locator?key->locator:"(null)");
00339                     error = 1;
00340                     break;
00341                 }
00342             }
00343             ldns_rr_set_ttl(key->dnskey, ttl);
00344             ldns_rr_set_class(key->dnskey, zone->klass);
00345             ldns_rr2canonical(key->dnskey);
00346             dnskey = ldns_rr_clone(key->dnskey);
00347             error = zone_add_rr(zone, dnskey, 0);
00348             if (error) {
00349                 se_log_error("error adding DNSKEY[%u] for key %s",
00350                     ldns_calc_keytag(dnskey),
00351                     key->locator?key->locator:"(null)");
00352                 break;
00353             } else if (fd) {
00354                 fprintf(fd, ";DNSKEY %s %u %u %i %i %i\n",
00355                     key->locator?key->locator:"(null)", key->algorithm,
00356                     key->flags, key->publish, key->ksk, key->zsk);
00357                 ldns_rr_print(fd, dnskey);
00358                 fprintf(fd, ";END\n");
00359             }
00360         }
00361         key = key->next;
00362     }
00363     hsm_destroy_context(ctx);
00364     return error;
00365 }
00366 
00367 
00372 static int
00373 zone_publish_nsec3params(zone_type* zone, FILE* fd)
00374 {
00375     ldns_rr* nsec3params_rr = NULL;
00376     int error = 0;
00377 
00378     if (!zone->nsec3params) {
00379         zone->nsec3params = nsec3params_create(
00380             (uint8_t) zone->signconf->nsec3_algo,
00381             (uint8_t) zone->signconf->nsec3_optout,
00382             (uint16_t) zone->signconf->nsec3_iterations,
00383             zone->signconf->nsec3_salt);
00384         if (!zone->nsec3params) {
00385             se_log_error("error creating NSEC3 parameters for zone %s",
00386                 zone->name?zone->name:"(null)");
00387             return 1;
00388         }
00389     }
00390 
00391     nsec3params_rr = ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAMS);
00392     ldns_rr_set_class(nsec3params_rr, zone->klass);
00393     ldns_rr_set_ttl(nsec3params_rr, zone->zonedata->default_ttl);
00394     ldns_rr_set_owner(nsec3params_rr, ldns_rdf_clone(zone->dname));
00395     ldns_nsec3_add_param_rdfs(nsec3params_rr,
00396         zone->nsec3params->algorithm, 0,
00397         zone->nsec3params->iterations,
00398         zone->nsec3params->salt_len,
00399         zone->nsec3params->salt_data);
00404     ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3params_rr, 1)), 7, 0);
00405 
00406     ldns_rr2canonical(nsec3params_rr);
00407     error = zone_add_rr(zone, nsec3params_rr, 0);
00408     if (error) {
00409         se_log_error("error adding NSEC3PARAMS record to zone %s",
00410             zone->name?zone->name:"(null)");
00411     } else if (fd) {
00412         fprintf(fd, ";NSEC3PARAMS %s %u %u %u\n",
00413             zone->signconf->nsec3_salt, zone->nsec3params->algorithm,
00414             zone->nsec3params->flags, zone->nsec3params->iterations);
00415         ldns_rr_print(fd, nsec3params_rr);
00416         fprintf(fd, ";END\n");
00417     }
00418     return error;
00419 }
00420 
00421 
00426 int
00427 zone_update_zonedata(zone_type* zone)
00428 {
00429     int error = 0;
00430 
00431     se_log_assert(zone);
00432     se_log_assert(zone->signconf);
00433     se_log_assert(zone->inbound_adapter);
00434     se_log_assert(zone->zonedata);
00435 
00436     /* examine zone data */
00437     se_log_debug("examine zone %s update", zone->name);
00438     error = zonedata_examine(zone->zonedata, zone->dname,
00439         zone->inbound_adapter->type==ADAPTER_FILE);
00440     if (error) {
00441         se_log_error("update zone %s failed: zone data contains errors",
00442             zone->name);
00443         zonedata_cancel_update(zone->zonedata);
00444         return error;
00445     }
00446     return zonedata_update(zone->zonedata, zone->signconf);
00447 }
00448 
00449 
00454 int
00455 zone_add_dnskeys(zone_type* zone)
00456 {
00457     int error = 0;
00458     char* filename = NULL;
00459     FILE* fd = NULL;
00460 
00461     se_log_assert(zone);
00462     se_log_assert(zone->signconf);
00463     se_log_assert(zone->zonedata);
00464 
00465     filename = se_build_path(zone->name, ".dnskeys", 0);
00466     fd = se_fopen(filename, NULL, "w");
00467     if (fd) {
00468         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00469     }
00470 
00471     error = zone_publish_dnskeys(zone, fd);
00472     if (error) {
00473         se_log_error("error adding DNSKEYs to zone %s",
00474             zone->name?zone->name:"(null)");
00475         return error;
00476     }
00477     if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
00478         error = zone_publish_nsec3params(zone, fd);
00479         if (error) {
00480             se_log_error("error adding NSEC3PARAMS RR to zone %s",
00481                 zone->name?zone->name:"(null)");
00482             return error;
00483         }
00484     }
00485 
00486     if (fd) {
00487         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00488         se_fclose(fd);
00489     } else {
00490         se_log_warning("cannot backup DNSKEY / NSEC3PARAMS records: "
00491             "cannot open file %s for writing", filename?filename:"(null)");
00492     }
00493     se_free((void*)filename);
00494 
00495     return error;
00496 }
00497 
00498 
00503 int
00504 zone_add_rr(zone_type* zone, ldns_rr* rr, int recover)
00505 {
00506     ldns_rr_type type = 0;
00507     int error = 0;
00508     int at_apex = 0;
00509     uint32_t tmp = 0;
00510     ldns_rdf* soa_min = NULL;
00511 
00512     se_log_assert(zone);
00513     se_log_assert(zone->zonedata);
00514     se_log_assert(zone->signconf);
00515     se_log_assert(rr);
00516 
00517     /* in-zone? */
00518     if (ldns_dname_compare(zone->dname, ldns_rr_owner(rr)) != 0 &&
00519         !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->dname)) {
00520         se_log_warning("zone %s contains out-of-zone data, skipping",
00521             zone->name?zone->name:"(null)");
00522         return 0;
00523     } else if (ldns_dname_compare(zone->dname, ldns_rr_owner(rr)) == 0) {
00524         at_apex = 1;
00525     }
00526 
00527     /* type specific configuration */
00528     type = ldns_rr_get_type(rr);
00529     if (type == LDNS_RR_TYPE_DNSKEY && zone->signconf->dnskey_ttl) {
00530         tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl);
00531         se_log_verbose("zone %s set DNSKEY TTL to %u",
00532             zone->name?zone->name:"(null)", tmp);
00533         ldns_rr_set_ttl(rr, tmp);
00534     }
00535     if (type == LDNS_RR_TYPE_SOA) {
00536         if (zone->signconf->soa_ttl) {
00537             tmp = (uint32_t) duration2time(zone->signconf->soa_ttl);
00538             se_log_verbose("zone %s set SOA TTL to %u",
00539                 zone->name?zone->name:"(null)", tmp);
00540             ldns_rr_set_ttl(rr, tmp);
00541         }
00542         if (zone->signconf->soa_min) {
00543             tmp = (uint32_t) duration2time(zone->signconf->soa_min);
00544             se_log_verbose("zone %s set SOA MINIMUM to %u",
00545                 zone->name?zone->name:"(null)", tmp);
00546             soa_min = ldns_rr_set_rdf(rr,
00547                 ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp),
00548                 SE_SOA_RDATA_MINIMUM);
00549             if (soa_min) {
00550                 ldns_rdf_deep_free(soa_min);
00551             } else {
00552                 se_log_error("zone %s failed to replace SOA MINIMUM "
00553                     "rdata", zone->name?zone->name:"(null)");
00554             }
00555         }
00556     }
00557     if (recover) {
00558        error = zonedata_recover_rr_from_backup(zone->zonedata, rr);
00559     } else {
00560        error = zonedata_add_rr(zone->zonedata, rr, at_apex);
00561     }
00562     return error;
00563 }
00564 
00565 
00570 int
00571 zone_del_rr(zone_type* zone, ldns_rr* rr)
00572 {
00573     se_log_assert(zone);
00574     se_log_assert(zone->zonedata);
00575     se_log_assert(rr);
00576     return zonedata_del_rr(zone->zonedata, rr);
00577 }
00578 
00579 
00584 int
00585 zone_nsecify(zone_type* zone)
00586 {
00587     int error = 0;
00588     FILE* fd = NULL;
00589     char* filename = NULL;
00590     time_t start = 0;
00591     time_t end = 0;
00592 
00593     se_log_assert(zone);
00594     se_log_assert(zone->signconf);
00595     se_log_assert(zone->zonedata);
00596     se_log_assert(zone->stats);
00597 
00598     zone->stats->nsec_count = 0;
00599     zone->stats->nsec_time = 0;
00600     start = time(NULL);
00601 
00602     /* add empty non-terminals */
00603     error = zonedata_entize(zone->zonedata, zone->dname);
00604     if (error) {
00605         se_log_error("failed to add empty non-terminals to zone %s",
00606             zone->name?zone->name:"(null)");
00607         return error;
00608     }
00609 
00610     if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC) {
00611         error = zonedata_nsecify(zone->zonedata, zone->klass, zone->stats);
00612     } else if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
00613         if (zone->signconf->nsec3_optout) {
00614             se_log_debug("OptOut is being used for zone %s",
00615                 zone->name?zone->name:"(null)");
00616         }
00617         error = zonedata_nsecify3(zone->zonedata, zone->klass,
00618             zone->nsec3params, zone->stats);
00619     } else {
00620         se_log_error("unknown RR type for denial of existence, %i",
00621             zone->signconf->nsec_type);
00622         error = 1;
00623     }
00624     if (!error) {
00625         end = time(NULL);
00626         zone->stats->nsec_time = (end-start);
00627 
00628         filename = se_build_path(zone->name, ".denial", 0);
00629         fd = se_fopen(filename, NULL, "w");
00630         if (fd) {
00631             fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00632             zonedata_print_nsec(fd, zone->zonedata);
00633             fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00634             se_fclose(fd);
00635         } else {
00636             se_log_warning("cannot backup NSEC(3) records: cannot open file "
00637             "%s for writing", filename?filename:"(null)");
00638         }
00639         se_free((void*)filename);
00640     }
00641     return error;
00642 }
00643 
00644 
00649 int
00650 zone_sign(zone_type* zone)
00651 {
00652     int error = 0;
00653     FILE* fd = NULL;
00654     char* filename = NULL;
00655     time_t start = 0;
00656     time_t end = 0;
00657 
00658     se_log_assert(zone);
00659     se_log_assert(zone->signconf);
00660     se_log_assert(zone->zonedata);
00661     se_log_assert(zone->stats);
00662 
00663     zone->stats->sig_count = 0;
00664     zone->stats->sig_reuse = 0;
00665     zone->stats->sig_time = 0;
00666     start = time(NULL);
00667 
00668     error = zonedata_sign(zone->zonedata, zone->dname, zone->signconf,
00669         zone->stats);
00670     if (!error) {
00671         end = time(NULL);
00672         zone->stats->sig_time = (end-start);
00673 
00674         filename = se_build_path(zone->name, ".rrsigs", 0);
00675         fd = se_fopen(filename, NULL, "w");
00676         if (fd) {
00677             fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00678             zonedata_print_rrsig(fd, zone->zonedata);
00679             fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00680             se_fclose(fd);
00681         } else {
00682             se_log_warning("cannot backup RRSIG records: cannot open file "
00683                 "%s for writing", filename?filename:"(null)");
00684         }
00685         se_free((void*)filename);
00686     }
00687     return error;
00688 }
00689 
00690 
00697 int zone_backup_state(zone_type* zone)
00698 {
00699     int error = 0;
00700     char* filename = NULL;
00701     FILE* fd = NULL;
00702 
00703     se_log_assert(zone);
00704     se_log_assert(zone->zonedata);
00705     se_log_assert(zone->signconf);
00706 
00707     filename = se_build_path(zone->name, ".state", 0);
00708     fd = se_fopen(filename, NULL, "w");
00709     if (fd) {
00710         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00711         fprintf(fd, ";name: %s\n", zone->name?zone->name:"(null)");
00712         fprintf(fd, ";class: %i\n", (int) zone->klass);
00713         fprintf(fd, ";fetch: %i\n", (int) zone->fetch);
00714         fprintf(fd, ";default_ttl: %u\n", zone->zonedata->default_ttl);
00715         fprintf(fd, ";inbound_serial: %u\n", zone->zonedata->inbound_serial);
00716         fprintf(fd, ";internal_serial: %u\n", zone->zonedata->internal_serial);
00717         fprintf(fd, ";outbound_serial: %u\n", zone->zonedata->outbound_serial);
00718         fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC);
00719         se_fclose(fd);
00720     } else {
00721         se_log_error("cannot backup zone: cannot open file "
00722         "%s for writing", filename?filename:"(null)");
00723         return 1;
00724     }
00725     se_free((void*)filename);
00726 
00727     return error;
00728 }
00729 
00730 
00735 static int
00736 zone_recover_dnskeys_from_backup(zone_type* zone, FILE* fd)
00737 {
00738     int corrupted = 0;
00739     const char* token = NULL;
00740     key_type* key = NULL;
00741     ldns_rr* rr = NULL;
00742 
00743     if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) {
00744         corrupted = 1;
00745     }
00746 
00747     while (!corrupted) {
00748         if (backup_read_str(fd, &token)) {
00749             if (se_strcmp(token, ";DNSKEY") == 0) {
00750                 key = key_recover_from_backup(fd);
00751                 if (!key || keylist_add(zone->signconf->keys, key)) {
00752                     se_log_error("error adding key from backup file "
00753                         "%s.dnskeys to key list", zone->name);
00754                     corrupted = 1;
00755                 } else {
00756                    rr = ldns_rr_clone(key->dnskey);
00757                    corrupted = zone_add_rr(zone, rr, 1);
00758                    if (corrupted) {
00759                        se_log_error("error recovering DNSKEY[%u] rr",
00760                           ldns_calc_keytag(rr));
00761                    }
00762                    rr = NULL;
00763                 }
00764                 key = NULL;
00765             } else if (se_strcmp(token, ";NSEC3PARAMS") == 0) {
00766                 zone->nsec3params = nsec3params_recover_from_backup(fd,
00767                     &rr);
00768                 if (!zone->nsec3params) {
00769                     se_log_error("error recovering nsec3 parameters from file "
00770                         "%s.dnskeys", zone->name);
00771                     corrupted = 1;
00772                 } else {
00773                     corrupted = zone_add_rr(zone, rr, 1);
00774                     if (corrupted) {
00775                        se_log_error("error recovering NSEC3PARAMS rr");
00776                     } else {
00777                         zone->signconf->nsec3_optout =
00778                             (int) zone->nsec3params->flags;
00779                         zone->signconf->nsec3_algo =
00780                             (uint32_t) zone->nsec3params->algorithm;
00781                         zone->signconf->nsec3_iterations =
00782                             (uint32_t) zone->nsec3params->iterations;
00783                         zone->signconf->nsec3_salt =
00784                             nsec3params_salt2str(zone->nsec3params);
00785                    }
00786                 }
00787                 rr = NULL;
00788             } else if (se_strcmp(token, ODS_SE_FILE_MAGIC) == 0) {
00789                 se_free((void*) token);
00790                 token = NULL;
00791                 break;
00792             } else {
00793                 corrupted = 1;
00794             }
00795             se_free((void*) token);
00796             token = NULL;
00797         } else {
00798             corrupted = 1;
00799         }
00800     }
00801     return corrupted;
00802 }
00803 
00804 
00809 static int
00810 zone_recover_rrsigs_from_backup(zone_type* zone, FILE* fd)
00811 {
00812     int corrupted = 0;
00813     const char* token = NULL;
00814     const char* locator = NULL;
00815     uint32_t flags = 0;
00816     ldns_rr* rr = NULL;
00817     ldns_status status = LDNS_STATUS_OK;
00818 
00819     if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC)) {
00820         corrupted = 1;
00821     }
00822 
00823     while (!corrupted) {
00824         if (backup_read_str(fd, &token)) {
00825             if (se_strcmp(token, ";RRSIG") == 0) {
00826                 if (!backup_read_str(fd, &locator) ||
00827                     !backup_read_uint32_t(fd, &flags)) {
00828 
00829                     se_log_error("error reading key credentials from backup");
00830                     corrupted = 1;
00831                 } else {
00832                     status = ldns_rr_new_frm_fp(&rr, fd, NULL, NULL, NULL);
00833                    if (status != LDNS_STATUS_OK) {
00834                        se_log_error("error reading RRSIG from backup");
00835                        corrupted = 1;
00836                     } else if (ldns_rr_get_type(rr) != LDNS_RR_TYPE_RRSIG) {
00837                        se_log_error("expecting RRtype RRSIG from backup");
00838                        corrupted = 1;
00839                        ldns_rr_free(rr);
00840                        rr = NULL;
00841                     } else {
00842                        corrupted = zonedata_recover_rrsig_from_backup(
00843                            zone->zonedata, rr, locator, flags);
00844                     }
00845                 }
00846             } else if (se_strcmp(token, ODS_SE_FILE_MAGIC) == 0) {
00847                 se_free((void*) token);
00848                 token = NULL;
00849                 break;
00850             } else {
00851                 corrupted = 1;
00852             }
00853             se_free((void*) token);
00854             token = NULL;
00855         } else {
00856             corrupted = 1;
00857         }
00858 
00859         /* reset */
00860         if (locator) {
00861             se_free((void*) locator);
00862             locator = NULL;
00863         }
00864         rr = NULL;
00865         flags = 0;
00866         status = LDNS_STATUS_OK;
00867     }
00868     return corrupted;
00869 }
00870 
00871 
00876 void
00877 zone_recover_from_backup(zone_type* zone, struct tasklist_struct* tl)
00878 {
00879     int klass = 0;
00880     int fetch = 0;
00881     int error = 0;
00882     char* filename = NULL;
00883     task_type* task = NULL;
00884     time_t now = 0;
00885     FILE* fd = NULL;
00886 
00887     se_log_assert(zone);
00888     se_log_assert(zone->zonedata);
00889 
00890     filename = se_build_path(zone->name, ".state", 0);
00891     fd = se_fopen(filename, NULL, "r");
00892     se_free((void*)filename);
00893     if (fd) {
00894         if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC) ||
00895             !backup_read_check_str(fd, ";name:") ||
00896             !backup_read_check_str(fd, zone->name) ||
00897             !backup_read_check_str(fd, ";class:") ||
00898             !backup_read_int(fd, &klass) ||
00899             !backup_read_check_str(fd, ";fetch:") ||
00900             !backup_read_int(fd, &fetch) ||
00901             !backup_read_check_str(fd, ";default_ttl:") ||
00902             !backup_read_uint32_t(fd, &zone->zonedata->default_ttl) ||
00903             !backup_read_check_str(fd, ";inbound_serial:") ||
00904             !backup_read_uint32_t(fd, &zone->zonedata->inbound_serial) ||
00905             !backup_read_check_str(fd, ";internal_serial:") ||
00906             !backup_read_uint32_t(fd, &zone->zonedata->internal_serial) ||
00907             !backup_read_check_str(fd, ";outbound_serial:") ||
00908             !backup_read_uint32_t(fd, &zone->zonedata->outbound_serial) ||
00909             !backup_read_check_str(fd, ODS_SE_FILE_MAGIC))
00910         {
00911             se_log_error("unable to recover zone state from file %s.state: "
00912                 "file corrupted", zone->name);
00913             se_fclose(fd);
00914             return;
00915         }
00916         zone->klass = (ldns_rr_class) klass;
00917         zone->fetch = fetch;
00918 
00919         se_fclose(fd);
00920     } else {
00921         se_log_deeebug("unable to recover zone state from file %s.state: ",
00922             "no such file or directory", zone->name);
00923         return;
00924     }
00925 
00926     /* let's see if we can recover the signconf now */
00927     filename = se_build_path(zone->name, ".sc", 0);
00928     zone->signconf = signconf_recover_from_backup((const char*) filename);
00929     se_free((void*)filename);
00930     if (!zone->signconf) {
00931         /* no, stop recovering process */
00932         return;
00933     }
00934     zone->signconf->name = zone->name;
00935     zone->signconf->keys = keylist_create();
00936 
00937     /* recover denial of existence */
00938     filename = se_build_path(zone->name, ".denial", 0);
00939     fd = se_fopen(filename, NULL, "r");
00940     se_free((void*)filename);
00941     if (fd) {
00942         error = zonedata_recover_from_backup(zone->zonedata, fd);
00943         se_fclose(fd);
00944         if (error) {
00945             se_log_error("unable to recover denial of existence from file "
00946             "%s.denial: file corrupted", zone->name);
00947             if (zone->zonedata) {
00948                 zonedata_cleanup(zone->zonedata);
00949                 zone->zonedata = NULL;
00950             }
00951             zone->zonedata = zonedata_create();
00952         }
00953     } else {
00954         se_log_deeebug("unable to recover denial of existence from file "
00955             "%s.denial: no such file or directory", zone->name);
00956         error = 1;
00957     }
00958     if (error) {
00959         goto abort_recover;
00960     }
00961 
00962     /* zone data */
00963     filename = se_build_path(zone->name, ".unsorted", 0);
00964     error = adfile_read(zone, filename, 1);
00965     se_free((void*)filename);
00966     if (error) {
00967         se_log_error("unable to recover unsorted zone from file "
00968         "%s.unsorted: parse error", zone->name);
00969         if (zone->zonedata) {
00970             zonedata_cleanup(zone->zonedata);
00971             zone->zonedata = NULL;
00972         }
00973         zone->zonedata = zonedata_create();
00974         goto abort_recover;
00975     }
00976 
00977     /* time for the keys and nsec3params file */
00978     filename = se_build_path(zone->name, ".dnskeys", 0);
00979     fd = se_fopen(filename, NULL, "r");
00980     se_free((void*)filename);
00981     if (fd) {
00982         error = zone_recover_dnskeys_from_backup(zone, fd);
00983         se_fclose(fd);
00984         if (error) {
00985             se_log_error("unable to recover dnskeys from file %s.dnskeys: "
00986                 "file corrupted", zone->name);
00987         }
00988     } else {
00989         se_log_deeebug("unable to recover dnskeys from file %s.dnskeys: ",
00990             "no such file or directory", zone->name);
00991         error = 1;
00992     }
00993     if (error) {
00994         goto abort_recover;
00995     }
00996 
00997     /* retrieve signatures */
00998     filename = se_build_path(zone->name, ".rrsigs", 0);
00999     fd = se_fopen(filename, NULL, "r");
01000     se_free((void*)filename);
01001     if (fd) {
01002         error = zone_recover_rrsigs_from_backup(zone, fd);
01003         se_fclose(fd);
01004         if (error) {
01005             se_log_error("unable to recover rrsigs from file %s.rrsigs: "
01006                 "file corrupted", zone->name);
01007         }
01008     } else {
01009         se_log_deeebug("unable to recover rrsigs from file %s.rrsigs: ",
01010             "no such file or directory", zone->name);
01011     }
01012 
01013 abort_recover:
01014 
01015     /* task */
01016     filename = se_build_path(zone->name, ".task", 0);
01017     zone->task = task_recover_from_backup((const char*) filename, zone);
01018     se_free((void*)filename);
01019 
01020     if (!zone->task) {
01021         now = time_now();
01022         zone->task = task_create(TASK_READ, now, zone->name, zone);
01023     }
01024     if (!zone->task) {
01025         se_log_error("failed to create task for zone %s", zone->name);
01026     } else {
01027         if (error) {
01028             zone->task->what = TASK_READ;
01029         }
01030 
01031         task = tasklist_schedule_task(tl, zone->task, 1);
01032         if (!task) {
01033             se_log_error("failed to schedule task for zone %s", zone->name);
01034         }
01035     }
01036 
01037     if (error) {
01038         zone->signconf->last_modified = 0;
01039     }
01040     return;
01041 }
01042 
01043 
01048 void
01049 zone_cleanup(zone_type* zone)
01050 {
01051     if (zone) {
01052         if (zone->dname) {
01053             ldns_rdf_deep_free(zone->dname);
01054             zone->dname = NULL;
01055         }
01056         if (zone->notify_ns) {
01057             se_free((void*)zone->notify_ns);
01058             zone->notify_ns = NULL;
01059         }
01060         if (zone->inbound_adapter) {
01061             adapter_cleanup(zone->inbound_adapter);
01062             zone->inbound_adapter = NULL;
01063         }
01064         if (zone->outbound_adapter) {
01065             adapter_cleanup(zone->outbound_adapter);
01066             zone->outbound_adapter = NULL;
01067         }
01068         if (zone->signconf) {
01069             signconf_cleanup(zone->signconf);
01070             zone->signconf = NULL;
01071         }
01072         if (zone->stats) {
01073             stats_cleanup(zone->stats);
01074             zone->stats = NULL;
01075         }
01076         if (zone->zonedata) {
01077             zonedata_cleanup(zone->zonedata);
01078             zone->zonedata = NULL;
01079         }
01080         if (zone->nsec3params) {
01081             nsec3params_cleanup(zone->nsec3params);
01082             zone->nsec3params = NULL;
01083         }
01084         if (zone->policy_name) {
01085             se_free((void*) zone->policy_name);
01086             zone->policy_name = NULL;
01087         }
01088         if (zone->signconf_filename) {
01089             se_free((void*) zone->signconf_filename);
01090             zone->signconf_filename = NULL;
01091         }
01092         if (zone->name) {
01093             se_free((void*) zone->name);
01094             zone->name = NULL;
01095         }
01096 
01097         lock_basic_destroy(&zone->zone_lock);
01098         se_free((void*) zone);
01099     } else {
01100         se_log_warning("cleanup emtpy zone");
01101     }
01102     return;
01103 }
01104 
01105 
01110 void
01111 zone_print(FILE* out, zone_type* zone)
01112 {
01113     se_log_assert(out);
01114     se_log_assert(zone);
01115     se_log_assert(zone->zonedata);
01116 
01117     zonedata_print(out, zone->zonedata);
01118     return;
01119 }