OpenDNSSEC-signer  1.3.4
/build/buildd/opendnssec-1.3.4/signer/src/signer/tools.c
Go to the documentation of this file.
00001 /*
00002  * $Id: tools.c 5849 2011-11-14 08:43:44Z 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);
00087             lockname = ods_build_path(
00088                 zone->adinbound->configstr, ".lock", 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);
00134         status = ods_file_copy(zone->adinbound->configstr, tmpname);
00135         free((void*)tmpname);
00136         tmpname = NULL;
00137         if (status != ODS_STATUS_OK) {
00138             ods_log_error("[%s] unable to copy zone input file %s: %s",
00139                 tools_str, zone->name?zone->name:"(null)",
00140                 ods_status2str(status));
00141         }
00142     }
00143 
00144     if (status == ODS_STATUS_OK) {
00145         ods_log_verbose("[%s] commit updates for zone %s", tools_str,
00146             zone->name?zone->name:"(null)");
00147         status = zonedata_commit(zone->zonedata);
00148     } else {
00149         ods_log_warning("[%s] rollback updates for zone %s", tools_str,
00150             zone->name?zone->name:"(null)");
00151         zonedata_rollback(zone->zonedata);
00152     }
00153     end = time(NULL);
00154 
00155     if (status == ODS_STATUS_OK && zone->stats) {
00156         lock_basic_lock(&zone->stats->stats_lock);
00157         zone->stats->start_time = start;
00158         zone->stats->sort_time = (end-start);
00159         zone->stats->sort_done = 1;
00160         lock_basic_unlock(&zone->stats->stats_lock);
00161     }
00162     return status;
00163 }
00164 
00165 
00170 ods_status
00171 tools_nsecify(zone_type* zone)
00172 {
00173     ods_status status = ODS_STATUS_OK;
00174     time_t start = 0;
00175     time_t end = 0;
00176     uint32_t ttl = 0;
00177     uint32_t num_added = 0;
00178 
00179     if (!zone) {
00180         ods_log_error("[%s] unable to nsecify zone: no zone", tools_str);
00181         return ODS_STATUS_ASSERT_ERR;
00182     }
00183     ods_log_assert(zone);
00184 
00185     if (!zone->zonedata) {
00186         ods_log_error("[%s] unable to nsecify zone %s: no zonedata",
00187             tools_str, zone->name);
00188         return ODS_STATUS_ASSERT_ERR;
00189     }
00190     ods_log_assert(zone->zonedata);
00191 
00192     if (!zone->signconf) {
00193         ods_log_error("[%s] unable to nsecify zone %s: no signconf",
00194             tools_str, zone->name);
00195         return ODS_STATUS_ASSERT_ERR;
00196     }
00197     ods_log_assert(zone->signconf);
00198 
00199     if (zone->stats) {
00200         lock_basic_lock(&zone->stats->stats_lock);
00201         zone->stats->nsec_time = 0;
00202         zone->stats->nsec_count = 0;
00203         lock_basic_unlock(&zone->stats->stats_lock);
00204     }
00205 
00206     start = time(NULL);
00207     /* determine denial ttl */
00208     ttl = zone->zonedata->default_ttl;
00209     if (zone->signconf->soa_min) {
00210         ttl = (uint32_t) duration2time(zone->signconf->soa_min);
00211     }
00212     /* add missing empty non-terminals */
00213     status = zonedata_entize(zone->zonedata, zone->dname);
00214     if (status != ODS_STATUS_OK) {
00215         ods_log_error("[%s] unable to nsecify zone %s: failed to add empty ",
00216             "non-terminals", tools_str, zone->name);
00217         return status;
00218     }
00219     /* nsecify(3) */
00220     if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC) {
00221         status = zonedata_nsecify(zone->zonedata, zone->klass, ttl,
00222             &num_added);
00223     } else if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
00224         if (zone->signconf->nsec3_optout) {
00225             ods_log_debug("[%s] OptOut is being used for zone %s",
00226                 tools_str, zone->name);
00227         }
00228         ods_log_assert(zone->nsec3params);
00229         status = zonedata_nsecify3(zone->zonedata, zone->klass, ttl,
00230             zone->nsec3params, &num_added);
00231     } else {
00232         ods_log_error("[%s] unable to nsecify zone %s: unknown RRtype %u for ",
00233             "denial of existence", tools_str, zone->name,
00234             (unsigned) zone->signconf->nsec_type);
00235         return ODS_STATUS_ERR;
00236     }
00237     end = time(NULL);
00238     if (status == ODS_STATUS_OK && zone->stats) {
00239         lock_basic_lock(&zone->stats->stats_lock);
00240         if (!zone->stats->start_time) {
00241             zone->stats->start_time = start;
00242         }
00243         zone->stats->nsec_time = (end-start);
00244         zone->stats->nsec_count = num_added;
00245         lock_basic_unlock(&zone->stats->stats_lock);
00246     }
00247     return status;
00248 }
00249 
00250 
00255 ods_status
00256 tools_audit(zone_type* zone, char* working_dir, char* cfg_filename)
00257 {
00258     char* inbound = NULL;
00259     char* finalized = NULL;
00260     char str[SYSTEM_MAXLEN];
00261     ods_status status = ODS_STATUS_OK;
00262     int error = 0;
00263     time_t start = 0;
00264     time_t end = 0;
00265     if (!zone) {
00266         ods_log_error("[%s] unable to audit zone: no zone", tools_str);
00267         return ODS_STATUS_ASSERT_ERR;
00268     }
00269     ods_log_assert(zone);
00270 
00271     if (!zone->signconf) {
00272         ods_log_error("[%s] unable to audit zone %s: no signconf",
00273             tools_str, zone->name?zone->name:"(null)");
00274         return ODS_STATUS_ASSERT_ERR;
00275     }
00276     ods_log_assert(zone->signconf);
00277 
00278     if (zone->stats) {
00279         lock_basic_lock(&zone->stats->stats_lock);
00280         if (zone->stats->sort_done == 0 &&
00281             (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
00282             lock_basic_unlock(&zone->stats->stats_lock);
00283             return ODS_STATUS_OK;
00284         }
00285         lock_basic_unlock(&zone->stats->stats_lock);
00286     }
00287 
00288     if (zone->signconf->audit) {
00289         inbound = ods_build_path(zone->name, ".inbound", 0);
00290         finalized = ods_build_path(zone->name, ".finalized", 0);
00291         status = adfile_write(zone, finalized);
00292         if (status != ODS_STATUS_OK) {
00293             ods_log_error("[%s] audit zone %s failed: unable to write zone",
00294                 tools_str, zone->name?zone->name:"(null)");
00295             free((void*)inbound);
00296             free((void*)finalized);
00297             return status;
00298         }
00299 
00300         snprintf(str, SYSTEM_MAXLEN, "%s -c %s -u %s/%s -s %s/%s -z %s > /dev/null",
00301             ODS_SE_AUDITOR,
00302             cfg_filename?cfg_filename:ODS_SE_CFGFILE,
00303             working_dir?working_dir:"",
00304             inbound?inbound:"(null)",
00305             working_dir?working_dir:"",
00306             finalized?finalized:"(null)",
00307             zone->name?zone->name:"(null)");
00308 
00309         start = time(NULL);
00310         ods_log_debug("system call: %s", str);
00311         error = system(str);
00312         if (finalized) {
00313             if (!error) {
00314                 unlink(finalized);
00315             }
00316             free((void*)finalized);
00317         }
00318         free((void*)inbound);
00319 
00320         if (error) {
00321             ods_log_error("[%s] audit failed for zone %s", tools_str,
00322                 zone->name);
00323             status = ODS_STATUS_ERR;
00324         } else {
00325             ods_log_info("[%s] audit passed for zone %s", tools_str,
00326                 zone->name);
00327         }
00328         end = time(NULL);
00329         if (status == ODS_STATUS_OK && zone->stats) {
00330             lock_basic_lock(&zone->stats->stats_lock);
00331             zone->stats->audit_time = (end-start);
00332             lock_basic_unlock(&zone->stats->stats_lock);
00333         }
00334     }
00335     return status;
00336 }
00337 
00338 
00343 ods_status
00344 tools_output(zone_type* zone)
00345 {
00346     ods_status status = ODS_STATUS_OK;
00347     char str[SYSTEM_MAXLEN];
00348     int error = 0;
00349     uint32_t outbound_serial = 0;
00350 
00351     if (!zone) {
00352         ods_log_error("[%s] unable to write zone: no zone", tools_str);
00353         return ODS_STATUS_ASSERT_ERR;
00354     }
00355     ods_log_assert(zone);
00356 
00357     if (!zone->adoutbound) {
00358         ods_log_error("[%s] unable to write zone %s: no outbound adapter",
00359             tools_str, zone->name?zone->name:"(null)");
00360         return ODS_STATUS_ASSERT_ERR;
00361     }
00362     ods_log_assert(zone->adoutbound);
00363 
00364     if (zone->stats) {
00365         lock_basic_lock(&zone->stats->stats_lock);
00366         if (zone->stats->sort_done == 0 &&
00367             (zone->stats->sig_count <= zone->stats->sig_soa_count)) {
00368             ods_log_verbose("[%s] skip write zone %s serial %u (zone not "
00369                 "changed)", tools_str, zone->name?zone->name:"(null)",
00370                 zone->zonedata->internal_serial);
00371             stats_clear(zone->stats);
00372             lock_basic_unlock(&zone->stats->stats_lock);
00373             zone->zonedata->internal_serial =
00374                 zone->zonedata->outbound_serial;
00375             return ODS_STATUS_OK;
00376         }
00377         lock_basic_unlock(&zone->stats->stats_lock);
00378     }
00379 
00380     outbound_serial = zone->zonedata->outbound_serial;
00381     zone->zonedata->outbound_serial = zone->zonedata->internal_serial;
00382     status = adapter_write(zone);
00383     if (status != ODS_STATUS_OK) {
00384         ods_log_error("[%s] unable to write zone %s: adapter failed",
00385             tools_str, zone->name);
00386         zone->zonedata->outbound_serial = outbound_serial;
00387         return status;
00388     }
00389 
00390     /* initialize zonedata */
00391     zone->zonedata->initialized = 1;
00392 
00393     /* kick the nameserver */
00394     if (zone->notify_ns) {
00395         ods_log_verbose("[%s] notify nameserver: %s", tools_str,
00396             zone->notify_ns);
00397         snprintf(str, SYSTEM_MAXLEN, "%s > /dev/null",
00398             zone->notify_ns);
00399         error = system(str);
00400         if (error) {
00401            ods_log_error("[%s] failed to notify nameserver", tools_str);
00402            status = ODS_STATUS_ERR;
00403         }
00404     }
00405     /* log stats */
00406     if (zone->stats) {
00407         lock_basic_lock(&zone->stats->stats_lock);
00408         zone->stats->end_time = time(NULL);
00409         ods_log_debug("[%s] log stats for zone %s", tools_str,
00410             zone->name?zone->name:"(null)");
00411         stats_log(zone->stats, zone->name, zone->signconf->nsec_type);
00412         stats_clear(zone->stats);
00413         lock_basic_unlock(&zone->stats->stats_lock);
00414     }
00415     return status;
00416 }