OpenDNSSEC-signer  1.3.8
/build/buildd/opendnssec-1.3.8/signer/src/signer/tools.c
Go to the documentation of this file.
00001 /*
00002  * $Id: tools.c 6318 2012-05-09 08:56:43Z 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 "config.h"
00035 #include "adapter/adapter.h"
00036 #include "shared/file.h"
00037 #include "shared/log.h"
00038 #include "signer/tools.h"
00039 #include "signer/zone.h"
00040 
00041 static const char* tools_str = "tools";
00042 
00043 
00048 ods_status
00049 tools_input(zone_type* zone)
00050 {
00051     ods_status status = ODS_STATUS_OK;
00052     char* tmpname = NULL;
00053     char* lockname = NULL;
00054     time_t start = 0;
00055     time_t end = 0;
00056     FILE* fd = NULL;
00057 
00058     if (!zone) {
00059         ods_log_error("[%s] unable to read zone: no zone", tools_str);
00060         return ODS_STATUS_ASSERT_ERR;
00061     }
00062     ods_log_assert(zone);
00063 
00064     if (!zone->zonedata) {
00065         ods_log_error("[%s] unable to read zone: no zone data", tools_str);
00066         return ODS_STATUS_ASSERT_ERR;
00067     }
00068     ods_log_assert(zone->zonedata);
00069 
00070     ods_log_assert(zone->adinbound);
00071     ods_log_assert(zone->signconf);
00072 
00073     if (zone->stats) {
00074         lock_basic_lock(&zone->stats->stats_lock);
00075         zone->stats->sort_done = 0;
00076         zone->stats->sort_count = 0;
00077         zone->stats->sort_time = 0;
00078         lock_basic_unlock(&zone->stats->stats_lock);
00079     }
00080 
00081     if (zone->adinbound->type == ADAPTER_FILE) {
00082         if (zone->fetch) {
00083             ods_log_verbose("[%s] fetch zone %s", tools_str,
00084                 zone->name?zone->name:"(null)");
00085             tmpname = ods_build_path(
00086                 zone->adinbound->configstr, ".axfr", 0, 0);
00087             lockname = ods_build_path(
00088                 zone->adinbound->configstr, ".lock", 0, 0);
00089 
00090 lock_fetch:
00091             if (access(lockname, F_OK) == 0) {
00092                 ods_log_deeebug("[%s] axfr file %s is locked, "
00093                     "waiting...", tools_str, tmpname);
00094                 sleep(1);
00095                 goto lock_fetch;
00096             } else {
00097                 fd = fopen(lockname, "w");
00098                 if (!fd) {
00099                     ods_log_error("[%s] cannot lock AXFR file %s",
00100                         tools_str, lockname);
00101                     free((void*)tmpname);
00102                     free((void*)lockname);
00103                     return ODS_STATUS_ERR;
00104                 }
00105             }
00106             ods_log_assert(fd); /* locked */
00107 
00108             status = ods_file_copy(tmpname, zone->adinbound->configstr);
00109 
00110             fclose(fd);
00111             (void) unlink(lockname); /* unlocked */
00112 
00113             if (status != ODS_STATUS_OK) {
00114                 ods_log_error("[%s] unable to copy axfr file %s to %s: %s",
00115                     tools_str, tmpname, zone->adinbound->configstr,
00116                     ods_status2str(status));
00117                 free((void*)tmpname);
00118                 free((void*)lockname);
00119                 return status;
00120             }
00121             free((void*)tmpname);
00122             free((void*)lockname);
00123         }
00124     }
00125 
00126     start = time(NULL);
00127     status = adapter_read(zone);
00128     if (status != ODS_STATUS_OK) {
00129         ods_log_error("[%s] unable to read from input adapter for zone %s: "
00130             "%s", tools_str, zone->name?zone->name:"(null)",
00131             ods_status2str(status));
00132     } else {
00133         tmpname = ods_build_path(zone->name, ".inbound", 0, 1);
00134         status = ods_file_copy(zone->adinbound->configstr, tmpname);
00135         if (status != ODS_STATUS_OK) {
00136             ods_log_error("[%s] unable to copy zone input file %s: %s",
00137                 tools_str, tmpname, ods_status2str(status));
00138         }
00139         free((void*)tmpname);
00140         tmpname = NULL;
00141     }
00142 
00143     if (status == ODS_STATUS_OK) {
00144         ods_log_verbose("[%s] commit updates for zone %s", tools_str,
00145             zone->name?zone->name:"(null)");
00146         status = zonedata_commit(zone->zonedata);
00147     } else {
00148         ods_log_warning("[%s] rollback updates for zone %s", tools_str,
00149             zone->name?zone->name:"(null)");
00150         zonedata_rollback(zone->zonedata);
00151     }
00152     end = time(NULL);
00153 
00154     if (status == ODS_STATUS_OK && zone->stats) {
00155         lock_basic_lock(&zone->stats->stats_lock);
00156         zone->stats->start_time = start;
00157         zone->stats->sort_time = (end-start);
00158         zone->stats->sort_done = 1;
00159         lock_basic_unlock(&zone->stats->stats_lock);
00160     }
00161     return status;
00162 }
00163 
00164 
00169 ods_status
00170 tools_nsecify(zone_type* zone)
00171 {
00172     ods_status status = ODS_STATUS_OK;
00173     time_t start = 0;
00174     time_t end = 0;
00175     uint32_t ttl = 0;
00176     uint32_t num_added = 0;
00177 
00178     if (!zone) {
00179         ods_log_error("[%s] unable to nsecify zone: no zone", tools_str);
00180         return ODS_STATUS_ASSERT_ERR;
00181     }
00182     ods_log_assert(zone);
00183 
00184     if (!zone->zonedata) {
00185         ods_log_error("[%s] unable to nsecify zone %s: no zonedata",
00186             tools_str, zone->name);
00187         return ODS_STATUS_ASSERT_ERR;
00188     }
00189     ods_log_assert(zone->zonedata);
00190 
00191     if (!zone->signconf) {
00192         ods_log_error("[%s] unable to nsecify zone %s: no signconf",
00193             tools_str, zone->name);
00194         return ODS_STATUS_ASSERT_ERR;
00195     }
00196     ods_log_assert(zone->signconf);
00197 
00198     if (zone->stats) {
00199         lock_basic_lock(&zone->stats->stats_lock);
00200         zone->stats->nsec_time = 0;
00201         zone->stats->nsec_count = 0;
00202         lock_basic_unlock(&zone->stats->stats_lock);
00203     }
00204 
00205     start = time(NULL);
00206     /* determine denial ttl */
00207     ttl = zone->zonedata->default_ttl;
00208     if (zone->signconf->soa_min) {
00209         ttl = (uint32_t) duration2time(zone->signconf->soa_min);
00210     }
00211     /* add missing empty non-terminals */
00212     status = zonedata_entize(zone->zonedata, zone->dname);
00213     if (status != ODS_STATUS_OK) {
00214         ods_log_error("[%s] unable to nsecify zone %s: failed to add empty ",
00215             "non-terminals", tools_str, zone->name);
00216         return status;
00217     }
00218     /* nsecify(3) */
00219     if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC) {
00220         status = zonedata_nsecify(zone->zonedata, zone->klass, ttl,
00221             &num_added);
00222     } else if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
00223         if (zone->signconf->nsec3_optout) {
00224             ods_log_debug("[%s] OptOut is being used for zone %s",
00225                 tools_str, zone->name);
00226         }
00227         ods_log_assert(zone->nsec3params);
00228         status = zonedata_nsecify3(zone->zonedata, zone->klass, ttl,
00229             zone->nsec3params, &num_added);
00230     } else {
00231         ods_log_error("[%s] unable to nsecify zone %s: unknown RRtype %u for ",
00232             "denial of existence", tools_str, zone->name,
00233             (unsigned) zone->signconf->nsec_type);
00234         return ODS_STATUS_ERR;
00235     }
00236     end = time(NULL);
00237     if (status == ODS_STATUS_OK && zone->stats) {
00238         lock_basic_lock(&zone->stats->stats_lock);
00239         if (!zone->stats->start_time) {
00240             zone->stats->start_time = start;
00241         }
00242         zone->stats->nsec_time = (end-start);
00243         zone->stats->nsec_count = num_added;
00244         lock_basic_unlock(&zone->stats->stats_lock);
00245     }
00246     return status;
00247 }
00248 
00249 
00254 ods_status
00255 tools_audit(zone_type* zone, char* working_dir, char* cfg_filename)
00256 {
00257     ods_status status = ODS_STATUS_OK;
00258 #ifdef HAVE_AUDITOR
00259     char* inbound = NULL;
00260     char* finalized = NULL;
00261     char str[SYSTEM_MAXLEN];
00262     int error = 0;
00263     time_t start = 0;
00264     time_t end = 0;
00265 
00266     if (!zone) {
00267         ods_log_error("[%s] unable to audit zone: no zone", tools_str);
00268         return ODS_STATUS_ASSERT_ERR;
00269     }
00270     ods_log_assert(zone);
00271 
00272     if (!zone->signconf) {
00273         ods_log_error("[%s] unable to audit zone %s: no signconf",
00274             tools_str, zone->name?zone->name:"(null)");
00275         return ODS_STATUS_ASSERT_ERR;
00276     }
00277     ods_log_assert(zone->signconf);
00278 
00279     if (zone->stats) {
00280         lock_basic_lock(&zone->stats->stats_lock);
00281         if (zone->stats->sort_done == 0 &&
00282             (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
00283             lock_basic_unlock(&zone->stats->stats_lock);
00284             return ODS_STATUS_OK;
00285         }
00286         lock_basic_unlock(&zone->stats->stats_lock);
00287     }
00288 
00289     if (zone->signconf->audit) {
00290         inbound = ods_build_path(zone->name, ".inbound", 0, 1);
00291         finalized = ods_build_path(zone->name, ".finalized", 0, 1);
00292         status = adfile_write(zone, finalized);
00293         if (status != ODS_STATUS_OK) {
00294             ods_log_error("[%s] audit zone %s failed: unable to write zone",
00295                 tools_str, finalized);
00296             free((void*)inbound);
00297             free((void*)finalized);
00298             return status;
00299         }
00300 
00301         snprintf(str, SYSTEM_MAXLEN, "%s -c %s -u %s/%s -s %s/%s -z %s > /dev/null",
00302             ODS_SE_AUDITOR,
00303             cfg_filename?cfg_filename:ODS_SE_CFGFILE,
00304             working_dir?working_dir:"",
00305             inbound?inbound:"(null)",
00306             working_dir?working_dir:"",
00307             finalized?finalized:"(null)",
00308             zone->name?zone->name:"(null)");
00309 
00310         start = time(NULL);
00311         ods_log_debug("system call: %s", str);
00312         error = system(str);
00313         if (finalized) {
00314             if (!error) {
00315                 unlink(finalized);
00316             }
00317             free((void*)finalized);
00318         }
00319         free((void*)inbound);
00320 
00321         if (error) {
00322             ods_log_error("[%s] audit failed for zone %s", tools_str,
00323                 zone->name);
00324             status = ODS_STATUS_ERR;
00325         } else {
00326             ods_log_info("[%s] audit passed for zone %s", tools_str,
00327                 zone->name);
00328         }
00329         end = time(NULL);
00330         if (status == ODS_STATUS_OK && zone->stats) {
00331             lock_basic_lock(&zone->stats->stats_lock);
00332             zone->stats->audit_time = (end-start);
00333             lock_basic_unlock(&zone->stats->stats_lock);
00334         }
00335     }
00336 #else
00337     ods_log_error("[%s] unable to audit zone %s: ods-auditor not installed",
00338         tools_str, zone->name?zone->name:"(null)");
00339     status = ODS_STATUS_ERR;
00340 #endif
00341     return status;
00342 }
00343 
00344 
00349 ods_status
00350 tools_output(zone_type* zone)
00351 {
00352     ods_status status = ODS_STATUS_OK;
00353     char str[SYSTEM_MAXLEN];
00354     int error = 0;
00355     uint32_t outbound_serial = 0;
00356 
00357     if (!zone) {
00358         ods_log_error("[%s] unable to write zone: no zone", tools_str);
00359         return ODS_STATUS_ASSERT_ERR;
00360     }
00361     ods_log_assert(zone);
00362 
00363     if (!zone->adoutbound) {
00364         ods_log_error("[%s] unable to write zone %s: no outbound adapter",
00365             tools_str, zone->name?zone->name:"(null)");
00366         return ODS_STATUS_ASSERT_ERR;
00367     }
00368     ods_log_assert(zone->adoutbound);
00369 
00370     if (zone->stats) {
00371         lock_basic_lock(&zone->stats->stats_lock);
00372         if (zone->stats->sort_done == 0 &&
00373             (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
00374             ods_log_verbose("[%s] skip write zone %s serial %u (zone not "
00375                 "changed)", tools_str, zone->name?zone->name:"(null)",
00376                 zone->zonedata->internal_serial);
00377             stats_clear(zone->stats);
00378             lock_basic_unlock(&zone->stats->stats_lock);
00379             zone->zonedata->internal_serial =
00380                 zone->zonedata->outbound_serial;
00381             return ODS_STATUS_OK;
00382         }
00383         lock_basic_unlock(&zone->stats->stats_lock);
00384     }
00385 
00386     outbound_serial = zone->zonedata->outbound_serial;
00387     zone->zonedata->outbound_serial = zone->zonedata->internal_serial;
00388     status = adapter_write(zone);
00389     if (status != ODS_STATUS_OK) {
00390         ods_log_error("[%s] unable to write zone %s: adapter failed (%s)",
00391             tools_str, zone->name, ods_status2str(status));
00392         zone->zonedata->outbound_serial = outbound_serial;
00393         return status;
00394     }
00395 
00396     /* initialize zonedata */
00397     zone->zonedata->initialized = 1;
00398 
00399     /* kick the nameserver */
00400     if (zone->notify_ns) {
00401         ods_log_verbose("[%s] notify nameserver: %s", tools_str,
00402             zone->notify_ns);
00403         snprintf(str, SYSTEM_MAXLEN, "%s > /dev/null",
00404             zone->notify_ns);
00405         error = system(str);
00406         if (error) {
00407            ods_log_error("[%s] failed to notify nameserver", tools_str);
00408            status = ODS_STATUS_ERR;
00409         }
00410     }
00411     /* log stats */
00412     if (zone->stats) {
00413         lock_basic_lock(&zone->stats->stats_lock);
00414         zone->stats->end_time = time(NULL);
00415         ods_log_debug("[%s] log stats for zone %s", tools_str,
00416             zone->name?zone->name:"(null)");
00417         stats_log(zone->stats, zone->name, zone->signconf->nsec_type);
00418         stats_clear(zone->stats);
00419         lock_basic_unlock(&zone->stats->stats_lock);
00420     }
00421     return status;
00422 }