/** * Load zone signconf. * */ ods_status tools_signconf(zone_type* zone) { ods_status status = ODS_STATUS_OK; signconf_type* new_signconf = NULL; ods_log_assert(zone); ods_log_assert(zone->name); status = zone_load_signconf(zone, &new_signconf); if (status == ODS_STATUS_OK) { ods_log_assert(new_signconf); /* Denial of Existence Rollover? */ if (signconf_compare_denial(zone->signconf, new_signconf) == TASK_NSECIFY) { /** * Or NSEC -> NSEC3, or NSEC3 -> NSEC, or NSEC3 params changed. * All NSEC(3)s become invalid. */ namedb_wipe_denial(zone->db); namedb_cleanup_denials(zone->db); namedb_init_denials(zone->db); } /* all ok, switch signer configuration */ signconf_cleanup(zone->signconf); ods_log_debug("[%s] zone %s switch to new signconf", tools_str, zone->name); zone->signconf = new_signconf; signconf_log(zone->signconf, zone->name); zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min); } else if (status != ODS_STATUS_UNCHANGED) { ods_log_error("[%s] unable to load signconf for zone %s: %s", tools_str, zone->name, ods_status2str(status)); } return status; }
static bool assign_xml_duration_value_to_protobuf_field(const std::string &value, ::google::protobuf::Message* msg, const ::google::protobuf::FieldDescriptor* field) { // convert a duration text to a time_t value that can then be assigned to a numeric field. time_t durationtime; duration_type* duration = duration_create_from_string(value.c_str()); if (duration) { durationtime = duration2time(duration); duration_cleanup(duration); if (durationtime == 0) { printf("ERROR: '%s' not a valid duration !\n",value.c_str()); return false; } } else { printf("ERROR: '%s' not a valid duration !\n",value.c_str()); return false; } const ::google::protobuf::Reflection* reflection = msg->GetReflection(); switch (field->cpp_type()) { case ::google::protobuf::FieldDescriptor::CPPTYPE_INT32: reflection->SetInt32(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_INT64: reflection->SetInt64(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_UINT32: reflection->SetUInt32(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_UINT64: reflection->SetUInt64(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: reflection->SetDouble(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: reflection->SetFloat(msg, field, durationtime); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_BOOL: printf("ERROR: unable to assign a duration to a bool !\n"); return false; case ::google::protobuf::FieldDescriptor::CPPTYPE_ENUM: printf("ERROR: unable to assign a duration to an enum !\n"); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_STRING: printf("ERROR: unable to assign a duration to a string !\n"); break; case ::google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: printf("ERROR: unable to assign a duration to a message !\n"); return false; default: printf("ERROR: Unsupported field type '%d' !\n", field->cpp_type()); return false; } return true; }
/** * Process DNSKEY. * */ static void adapi_process_dnskey(zone_type* zone, ldns_rr* rr) { uint32_t tmp = 0; ods_log_assert(rr); ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->signconf); tmp = (uint32_t) duration2time(zone->signconf->dnskey_ttl); ods_log_verbose("[%s] zone %s set dnskey ttl to %u", adapi_str, zone->name, tmp); ldns_rr_set_ttl(rr, tmp); }
time_t parse_conf_automatic_keygen_period(const char* cfgfile) { time_t period = 365 * 24 * 3600; /* default 1 normal year in seconds */ const char* str = parse_conf_string(cfgfile, "//Configuration/Enforcer/AutomaticKeyGenerationPeriod", 0); if (str) { if (strlen(str) > 0) { duration_type* duration = duration_create_from_string(str); if (duration) { time_t duration_period = duration2time(duration); if (duration_period) period = duration_period; duration_cleanup(duration); } } free((void*)str); } return period; }
/** * Perform task. * */ static void worker_perform_task(worker_type* worker) { engine_type* engine = NULL; zone_type* zone = NULL; task_type* task = NULL; task_id what = TASK_NONE; time_t when = 0; time_t never = (3600*24*365); ods_status status = ODS_STATUS_OK; int backup = 0; time_t start = 0; time_t end = 0; if (!worker || !worker->task || !worker->task->zone || !worker->engine) { return; } engine = (engine_type*) worker->engine; task = (task_type*) worker->task; zone = (zone_type*) worker->task->zone; ods_log_debug("[%s[%i]] perform task %s for zone %s at %u", worker2str(worker->type), worker->thread_num, task_what2str(task->what), task_who2str(task), (uint32_t) worker->clock_in); /* do what you have been told to do */ switch (task->what) { case TASK_SIGNCONF: /* perform 'load signconf' task */ worker_working_with(worker, TASK_SIGNCONF, TASK_READ, "configure", task_who2str(task), &what, &when); status = tools_signconf(zone); if (status == ODS_STATUS_UNCHANGED) { if (!zone->signconf->last_modified) { ods_log_debug("[%s[%i]] no signconf.xml for zone %s yet", worker2str(worker->type), worker->thread_num, task_who2str(task)); status = ODS_STATUS_ERR; } } if (status == ODS_STATUS_UNCHANGED) { if (task->halted != TASK_NONE && task->halted != TASK_SIGNCONF) { goto task_perform_continue; } status = ODS_STATUS_OK; } else if (status == ODS_STATUS_OK) { task->interrupt = TASK_NONE; task->halted = TASK_NONE; } else { if (task->halted == TASK_NONE) { goto task_perform_fail; } goto task_perform_continue; } /* break; */ case TASK_READ: /* perform 'read input adapter' task */ worker_working_with(worker, TASK_READ, TASK_SIGN, "read", task_who2str(task), &what, &when); task->what = TASK_READ; if (!zone->signconf->last_modified) { ods_log_debug("[%s[%i]] no signconf.xml for zone %s yet", worker2str(worker->type), worker->thread_num, task_who2str(task)); status = ODS_STATUS_ERR; } else { lhsm_check_connection((void*)engine); status = tools_input(zone); } if (status == ODS_STATUS_UNCHANGED) { ods_log_verbose("[%s[%i]] zone %s unsigned data not changed, " "continue", worker2str(worker->type), worker->thread_num, task_who2str(task)); status = ODS_STATUS_OK; } if (status == ODS_STATUS_OK) { if (task->interrupt > TASK_SIGNCONF) { task->interrupt = TASK_NONE; task->halted = TASK_NONE; } } else { if (task->halted == TASK_NONE) { goto task_perform_fail; } goto task_perform_continue; } /* break; */ case TASK_SIGN: /* perform 'sign' task */ worker_working_with(worker, TASK_SIGN, TASK_WRITE, "sign", task_who2str(task), &what, &when); task->what = TASK_SIGN; status = zone_update_serial(zone); if (status == ODS_STATUS_OK) { if (task->interrupt > TASK_SIGNCONF) { task->interrupt = TASK_NONE; task->halted = TASK_NONE; } } else { ods_log_error("[%s[%i]] unable to sign zone %s: " "failed to increment serial", worker2str(worker->type), worker->thread_num, task_who2str(task)); if (task->halted == TASK_NONE) { goto task_perform_fail; } goto task_perform_continue; } /* start timer */ start = time(NULL); if (zone->stats) { lock_basic_lock(&zone->stats->stats_lock); if (!zone->stats->start_time) { zone->stats->start_time = start; } zone->stats->sig_count = 0; zone->stats->sig_soa_count = 0; zone->stats->sig_reuse = 0; zone->stats->sig_time = 0; lock_basic_unlock(&zone->stats->stats_lock); } /* check the HSM connection before queuing sign operations */ lhsm_check_connection((void*)engine); /* queue menial, hard signing work */ worker_queue_zone(worker, engine->signq, zone); ods_log_deeebug("[%s[%i]] wait until drudgers are finished " "signing zone %s", worker2str(worker->type), worker->thread_num, task_who2str(task)); /* sleep until work is done */ worker_sleep_unless(worker, 0); /* stop timer */ end = time(NULL); status = worker_check_jobs(worker, task); worker_clear_jobs(worker); if (status == ODS_STATUS_OK && zone->stats) { lock_basic_lock(&zone->stats->stats_lock); zone->stats->sig_time = (end-start); lock_basic_unlock(&zone->stats->stats_lock); } if (status != ODS_STATUS_OK) { if (task->halted == TASK_NONE) { goto task_perform_fail; } goto task_perform_continue; } else { if (task->interrupt > TASK_SIGNCONF) { task->interrupt = TASK_NONE; task->halted = TASK_NONE; } } /* break; */ case TASK_WRITE: /* perform 'write to output adapter' task */ worker_working_with(worker, TASK_WRITE, TASK_SIGN, "write", task_who2str(task), &what, &when); task->what = TASK_WRITE; status = tools_output(zone, engine); if (status == ODS_STATUS_OK) { if (task->interrupt > TASK_SIGNCONF) { task->interrupt = TASK_NONE; task->halted = TASK_NONE; } } else { /* clear signatures? */ if (task->halted == TASK_NONE) { goto task_perform_fail; } goto task_perform_continue; } zone->db->is_processed = 1; if (zone->signconf && duration2time(zone->signconf->sig_resign_interval)) { what = TASK_SIGN; when = worker->clock_in + duration2time(zone->signconf->sig_resign_interval); } else { ods_log_error("[%s[%i]] unable to retrieve resign interval " "for zone %s: duration2time() failed", worker2str(worker->type), worker->thread_num, task_who2str(task)); ods_log_info("[%s[%i]] defaulting to 1H resign interval for " "zone %s", worker2str(worker->type), worker->thread_num, task_who2str(task)); what = TASK_SIGN; when = worker->clock_in + 3600; } backup = 1; break; case TASK_NONE: worker->working_with = TASK_NONE; /* no task */ ods_log_warning("[%s[%i]] none task for zone %s", worker2str(worker->type), worker->thread_num, task_who2str(task)); when = time_now() + never; break; default: worker->working_with = TASK_NONE; /* unknown task */ ods_log_warning("[%s[%i]] unknown task, trying full sign zone %s", worker2str(worker->type), worker->thread_num, task_who2str(task)); what = TASK_SIGNCONF; when = time_now(); break; } /* no error */ task->backoff = 0; if (task->interrupt != TASK_NONE && task->interrupt != what) { ods_log_debug("[%s[%i]] interrupt task %s for zone %s", worker2str(worker->type), worker->thread_num, task_what2str(what), task_who2str(task)); task->halted = what; task->halted_when = when; task->what = task->interrupt; task->when = time_now(); } else { ods_log_debug("[%s[%i]] next task %s for zone %s", worker2str(worker->type), worker->thread_num, task_what2str(what), task_who2str(task)); task->what = what; task->when = when; task->interrupt = TASK_NONE; task->halted = TASK_NONE; task->halted_when = 0; } /* backup the last successful run */ if (backup) { status = zone_backup2(zone); if (status != ODS_STATUS_OK) { ods_log_warning("[%s[%i]] unable to backup zone %s: %s", worker2str(worker->type), worker->thread_num, task_who2str(task), ods_status2str(status)); /* just a warning */ status = ODS_STATUS_OK; } backup = 0; } return; task_perform_fail: if (status != ODS_STATUS_XFR_NOT_READY) { /* other statuses is critical, and we know it is not ODS_STATUS_OK */ ods_log_crit("[%s[%i]] CRITICAL: failed to sign zone %s: %s", worker2str(worker->type), worker->thread_num, task_who2str(task), ods_status2str(status)); } /* in case of failure, also mark zone processed (for single run usage) */ zone->db->is_processed = 1; if (task->backoff) { task->backoff *= 2; } else { task->backoff = 60; } if (task->backoff > ODS_SE_MAX_BACKOFF) { task->backoff = ODS_SE_MAX_BACKOFF; } ods_log_info("[%s[%i]] backoff task %s for zone %s with %u seconds", worker2str(worker->type), worker->thread_num, task_what2str(task->what), task_who2str(task), task->backoff); task->when = time_now() + task->backoff; return; task_perform_continue: ods_log_info("[%s[%i]] continue task %s for zone %s", worker2str(worker->type), worker->thread_num, task_what2str(task->halted), task_who2str(task)); task->what = task->halted; task->when = task->halted_when; task->interrupt = TASK_NONE; task->halted = TASK_NONE; task->halted_when = 0; return; }
/** * Process RR. * */ static ods_status adapi_process_rr(zone_type* zone, ldns_rr* rr, int add, int backup) { ods_status status = ODS_STATUS_OK; uint32_t tmp = 0; ods_log_assert(rr); ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->db); ods_log_assert(zone->signconf); /* We only support IN class */ if (ldns_rr_get_class(rr) != LDNS_RR_CLASS_IN) { ods_log_warning("[%s] only class in is supported, changing class " "to in", adapi_str); ldns_rr_set_class(rr, LDNS_RR_CLASS_IN); } /* RR processing */ if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex)) { ods_log_error("[%s] unable to %s rr to zone: soa record has " "invalid owner name", adapi_str, add?"add":"delete"); return ODS_STATUS_ERR; } status = adapi_process_soa(zone, rr, add, backup); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to %s rr: failed to process soa " "record", adapi_str, add?"add":"delete"); return status; } } else { if (ldns_dname_compare(ldns_rr_owner(rr), zone->apex) && !ldns_dname_is_subdomain(ldns_rr_owner(rr), zone->apex)) { ods_log_warning("[%s] zone %s contains out-of-zone data, " "skipping", adapi_str, zone->name); return ODS_STATUS_UNCHANGED; } else if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_DNSKEY) { adapi_process_dnskey(zone, rr); } else if (util_is_dnssec_rr(rr) && !backup) { ods_log_warning("[%s] zone %s contains dnssec data (type=%u), " "skipping", adapi_str, zone->name, (unsigned) ldns_rr_get_type(rr)); return ODS_STATUS_UNCHANGED; } else if (zone->signconf->max_zone_ttl) { /* Convert MaxZoneTTL */ tmp = (uint32_t) duration2time(zone->signconf->max_zone_ttl); } } /* //MaxZoneTTL. Only set for RRtype != SOA && RRtype != DNSKEY */ if (tmp && tmp < ldns_rr_ttl(rr)) { char* str = ldns_rdf2str(ldns_rr_owner(rr)); if (str) { size_t i = 0; str[(strlen(str))-1] = '\0'; /* replace tabs with white space */ for (i=0; i < strlen(str); i++) { if (str[i] == '\t') { str[i] = ' '; } } ods_log_debug("[%s] capping ttl %u to MaxZoneTTL %u for rrset " "<%s,%s>", adapi_str, ldns_rr_ttl(rr), tmp, str, rrset_type2str(ldns_rr_get_type(rr))); } ldns_rr_set_ttl(rr, tmp); } /* TODO: DNAME and CNAME checks */ /* TODO: NS and DS checks */ if (add) { return zone_add_rr(zone, rr, 1); } else { return zone_del_rr(zone, rr, 1); } /* not reached */ return ODS_STATUS_ERR; }
/** * Process SOA. * */ static ods_status adapi_process_soa(zone_type* zone, ldns_rr* rr, int add, int backup) { uint32_t tmp = 0; ldns_rdf* soa_rdata = NULL; ods_status status = ODS_STATUS_OK; ods_log_assert(rr); ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->signconf); if (backup) { /* no need to do processing */ return ODS_STATUS_OK; } if (zone->signconf->soa_ttl) { tmp = (uint32_t) duration2time(zone->signconf->soa_ttl); ods_log_verbose("[%s] zone %s set soa ttl to %u", adapi_str, zone->name, tmp); ldns_rr_set_ttl(rr, tmp); } if (zone->signconf->soa_min) { tmp = (uint32_t) duration2time(zone->signconf->soa_min); ods_log_verbose("[%s] zone %s set soa minimum to %u", adapi_str, zone->name, tmp); soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, tmp), SE_SOA_RDATA_MINIMUM); if (soa_rdata) { ldns_rdf_deep_free(soa_rdata); soa_rdata = NULL; } else { ods_log_error("[%s] unable to %s soa to zone %s: failed to replace " "soa minimum rdata", adapi_str, add?"add":"delete", zone->name); return ODS_STATUS_ASSERT_ERR; } } if (!add) { /* we are done */ return ODS_STATUS_OK; } tmp = ldns_rdf2native_int32(ldns_rr_rdf(rr, SE_SOA_RDATA_SERIAL)); status = namedb_update_serial(zone->db, zone->name, zone->signconf->soa_serial, tmp); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to add soa to zone %s: failed to replace " "soa serial rdata (%s)", adapi_str, zone->name, ods_status2str(status)); if (status == ODS_STATUS_CONFLICT_ERR) { ods_log_error("[%s] If this is the result of a key rollover, " "please increment the serial in the unsigned zone %s", adapi_str, zone->name); } return status; } ods_log_verbose("[%s] zone %s set soa serial to %u", adapi_str, zone->name, zone->db->intserial); soa_rdata = ldns_rr_set_rdf(rr, ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32, zone->db->intserial), SE_SOA_RDATA_SERIAL); if (soa_rdata) { ldns_rdf_deep_free(soa_rdata); soa_rdata = NULL; } else { ods_log_error("[%s] unable to add soa to zone %s: failed to replace " "soa serial rdata", adapi_str, zone->name); return ODS_STATUS_ERR; } zone->db->serial_updated = 1; return ODS_STATUS_OK; }
int policy_key_create_from_xml(policy_key_t* policy_key, xmlNodePtr key_node) { xmlNodePtr node; xmlChar* xml_text = NULL; duration_type* duration = NULL; int algorithm_length = 0; int standby = 0; int manual_rollover = 0; int rfc5011 = 0; int rolltype = 0; if (!policy_key) { return DB_ERROR_UNKNOWN; } if (!key_node) { return DB_ERROR_UNKNOWN; } if (!strcmp((char*)key_node->name, "KSK")) { ods_log_deeebug("[policy_key_*_from_xml] KSK"); policy_key_set_role(policy_key, POLICY_KEY_ROLE_KSK); } else if (!strcmp((char*)key_node->name, "ZSK")) { ods_log_deeebug("[policy_key_*_from_xml] ZSK"); policy_key_set_role(policy_key, POLICY_KEY_ROLE_ZSK); } else if (!strcmp((char*)key_node->name, "CSK")) { ods_log_deeebug("[policy_key_*_from_xml] CSK"); policy_key_set_role(policy_key, POLICY_KEY_ROLE_CSK); } else { return DB_ERROR_UNKNOWN; } for (node = key_node->children; node; node = node->next) { if (node->type != XML_ELEMENT_NODE) { continue; } if (!strcmp((char*)node->name, "Algorithm")) { if ((xml_text = xmlGetProp(node, (xmlChar*)"length"))) { algorithm_length = 1; ods_log_deeebug("[policy_key_*_from_xml] algorithm length %s", (char*)xml_text); if (policy_key_set_bits(policy_key, (unsigned int)atoi((char*)xml_text))) { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } } if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] algorithm %s", (char*)xml_text); if (policy_key_set_algorithm(policy_key, (unsigned int)atoi((char*)xml_text))) { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } } else if (!strcmp((char*)node->name, "Lifetime")) { if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] lifetime %s", (char*)xml_text); if (!(duration = duration_create_from_string((char*)xml_text))) { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_lifetime(policy_key, duration2time(duration))) { duration_cleanup(duration); return DB_ERROR_UNKNOWN; } duration_cleanup(duration); duration = NULL; } else if (!strcmp((char*)node->name, "Repository")) { if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] repository %s", (char*)xml_text); if (policy_key_set_repository(policy_key, (char*)xml_text)) { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } } else if (!strcmp((char*)node->name, "Standby")) { standby = 1; if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] standby %s", (char*)xml_text); if (policy_key_set_standby(policy_key, (unsigned int)atoi((char*)xml_text))) { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } } else if (!strcmp((char*)node->name, "ManualRollover")) { manual_rollover = 1; ods_log_deeebug("[policy_key_*_from_xml] manual rollover"); if (policy_key_set_manual_rollover(policy_key, 1)) { return DB_ERROR_UNKNOWN; } } else if (policy_key_role(policy_key) == POLICY_KEY_ROLE_KSK && !strcmp((char*)node->name, "KskRollType")) { rolltype = 1; if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] KSK rolltype %s", (char*)xml_text); if (!strcmp((char*)xml_text, "KskDoubleRRset")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_NONE)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "KskDoubleDS")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DNSKEY)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "KskDoubleSignature")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DS)) { return DB_ERROR_UNKNOWN; } } else { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } } else if (policy_key_role(policy_key) == POLICY_KEY_ROLE_ZSK && !strcmp((char*)node->name, "ZskRollType")) { rolltype = 1; if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] ZSK rolltype %s", (char*)xml_text); if (!strcmp((char*)xml_text, "ZskDoubleSignature")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_NONE)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "ZskPrePublication")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_RRSIG)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "ZskDoubleRRsig")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DNSKEY)) { return DB_ERROR_UNKNOWN; } } else { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } } else if (policy_key_role(policy_key) == POLICY_KEY_ROLE_CSK && !strcmp((char*)node->name, "CskRollType")) { rolltype = 1; if (!(xml_text = xmlNodeGetContent(node))) { return DB_ERROR_UNKNOWN; } ods_log_deeebug("[policy_key_*_from_xml] CSK rolltype %s", (char*)xml_text); if (!strcmp((char*)xml_text, "CskDoubleRRset")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_NONE)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "CskSingleSignature")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_RRSIG)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "CskDoubleDS")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DNSKEY)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "CskDoubleSignature")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DS)) { return DB_ERROR_UNKNOWN; } } else if (!strcmp((char*)xml_text, "CskPrePublication")) { if (xml_text) { xmlFree(xml_text); xml_text = NULL; } if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DS_AND_RRSIG)) { return DB_ERROR_UNKNOWN; } } else { if (xml_text) { xmlFree(xml_text); } return DB_ERROR_UNKNOWN; } } else if ((policy_key_role(policy_key) == POLICY_KEY_ROLE_KSK || policy_key_role(policy_key) == POLICY_KEY_ROLE_CSK) && !strcmp((char*)node->name, "RFC5011")) { rfc5011 = 1; ods_log_deeebug("[policy_key_*_from_xml] rfc5011"); if (policy_key_set_rfc5011(policy_key, 1)) { return DB_ERROR_UNKNOWN; } } else { return DB_ERROR_UNKNOWN; } } if (xml_text) { xmlFree(xml_text); xml_text = NULL; } duration_cleanup(duration); duration = NULL; /* * If we did not find these XML elements we need to disable them */ if (!algorithm_length) { ods_log_deeebug("[policy_key_*_from_xml] - algorithm length"); if (policy_key_set_bits(policy_key, 0)) { return DB_ERROR_UNKNOWN; } } if (!standby) { ods_log_deeebug("[policy_key_*_from_xml] - standby"); if (policy_key_set_standby(policy_key, 0)) { return DB_ERROR_UNKNOWN; } } if (!manual_rollover) { ods_log_deeebug("[policy_key_*_from_xml] - manual rollover"); if (policy_key_set_manual_rollover(policy_key, 0)) { return DB_ERROR_UNKNOWN; } } if (!rolltype) { if (policy_key_role(policy_key) == POLICY_KEY_ROLE_KSK) { ods_log_deeebug("[policy_key_*_from_xml] - minimize default KskDoubleSignature"); if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DS)) { return DB_ERROR_UNKNOWN; } } else if (policy_key_role(policy_key) == POLICY_KEY_ROLE_ZSK) { ods_log_deeebug("[policy_key_*_from_xml] - minimize default ZskPrePublication"); if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_RRSIG)) { return DB_ERROR_UNKNOWN; } } else if (policy_key_role(policy_key) == POLICY_KEY_ROLE_CSK) { ods_log_deeebug("[policy_key_*_from_xml] - minimize default CskPrePublication"); if (policy_key_set_minimize(policy_key, POLICY_KEY_MINIMIZE_DS_AND_RRSIG)) { return DB_ERROR_UNKNOWN; } } else { return DB_ERROR_UNKNOWN; } } if ((policy_key_role(policy_key) == POLICY_KEY_ROLE_KSK || policy_key_role(policy_key) == POLICY_KEY_ROLE_CSK) && !rfc5011) { ods_log_deeebug("[policy_key_*_from_xml] - rfc5011"); if (policy_key_set_rfc5011(policy_key, 0)) { return DB_ERROR_UNKNOWN; } } return DB_OK; }
/** * Recover zone from backup. * */ ods_status zone_recover2(zone_type* zone) { char* filename = NULL; FILE* fd = NULL; const char* token = NULL; time_t when = 0; task_type* task = NULL; ods_status status = ODS_STATUS_OK; /* zone part */ int klass = 0; uint32_t inbound = 0, internal = 0, outbound = 0; /* signconf part */ time_t lastmod = 0; /* nsec3params part */ const char* salt = NULL; ods_log_assert(zone); ods_log_assert(zone->name); ods_log_assert(zone->signconf); ods_log_assert(zone->db); filename = ods_build_path(zone->name, ".backup2", 0, 1); if (!filename) { return ODS_STATUS_MALLOC_ERR; } fd = ods_fopen(filename, NULL, "r"); if (fd) { /* start recovery */ if (!backup_read_check_str(fd, ODS_SE_FILE_MAGIC_V3)) { ods_log_error("[%s] corrupted backup file zone %s: read magic " "error", zone_str, zone->name); goto recover_error2; } if (!backup_read_check_str(fd, ";;Time:") | !backup_read_time_t(fd, &when)) { ods_log_error("[%s] corrupted backup file zone %s: read time " "error", zone_str, zone->name); goto recover_error2; } /* zone stuff */ if (!backup_read_check_str(fd, ";;Zone:") | !backup_read_check_str(fd, "name") | !backup_read_check_str(fd, zone->name)) { ods_log_error("[%s] corrupted backup file zone %s: read name " "error", zone_str, zone->name); goto recover_error2; } if (!backup_read_check_str(fd, "class") | !backup_read_int(fd, &klass)) { ods_log_error("[%s] corrupted backup file zone %s: read class " "error", zone_str, zone->name); goto recover_error2; } if (!backup_read_check_str(fd, "inbound") | !backup_read_uint32_t(fd, &inbound) | !backup_read_check_str(fd, "internal") | !backup_read_uint32_t(fd, &internal) | !backup_read_check_str(fd, "outbound") | !backup_read_uint32_t(fd, &outbound)) { ods_log_error("[%s] corrupted backup file zone %s: read serial " "error", zone_str, zone->name); goto recover_error2; } zone->klass = (ldns_rr_class) klass; zone->db->inbserial = inbound; zone->db->intserial = internal; zone->db->outserial = outbound; /* signconf part */ if (!backup_read_check_str(fd, ";;Signconf:") | !backup_read_check_str(fd, "lastmod") | !backup_read_time_t(fd, &lastmod) | !backup_read_check_str(fd, "maxzonettl") | !backup_read_check_str(fd, "0") | !backup_read_check_str(fd, "resign") | !backup_read_duration(fd, &zone->signconf->sig_resign_interval) | !backup_read_check_str(fd, "refresh") | !backup_read_duration(fd, &zone->signconf->sig_refresh_interval) | !backup_read_check_str(fd, "valid") | !backup_read_duration(fd, &zone->signconf->sig_validity_default) | !backup_read_check_str(fd, "denial") | !backup_read_duration(fd,&zone->signconf->sig_validity_denial) | !backup_read_check_str(fd, "jitter") | !backup_read_duration(fd, &zone->signconf->sig_jitter) | !backup_read_check_str(fd, "offset") | !backup_read_duration(fd, &zone->signconf->sig_inception_offset) | !backup_read_check_str(fd, "nsec") | !backup_read_rr_type(fd, &zone->signconf->nsec_type) | !backup_read_check_str(fd, "dnskeyttl") | !backup_read_duration(fd, &zone->signconf->dnskey_ttl) | !backup_read_check_str(fd, "soattl") | !backup_read_duration(fd, &zone->signconf->soa_ttl) | !backup_read_check_str(fd, "soamin") | !backup_read_duration(fd, &zone->signconf->soa_min) | !backup_read_check_str(fd, "serial") | !backup_read_str(fd, &zone->signconf->soa_serial)) { ods_log_error("[%s] corrupted backup file zone %s: read signconf " "error", zone_str, zone->name); goto recover_error2; } /* nsec3params part */ if (zone->signconf->nsec_type == LDNS_RR_TYPE_NSEC3) { if (!backup_read_check_str(fd, ";;Nsec3parameters:") | !backup_read_check_str(fd, "salt") | !backup_read_str(fd, &salt) | !backup_read_check_str(fd, "algorithm") | !backup_read_uint32_t(fd, &zone->signconf->nsec3_algo) | !backup_read_check_str(fd, "optout") | !backup_read_int(fd, &zone->signconf->nsec3_optout) | !backup_read_check_str(fd, "iterations") | !backup_read_uint32_t(fd, &zone->signconf->nsec3_iterations)) { ods_log_error("[%s] corrupted backup file zone %s: read " "nsec3parameters error", zone_str, zone->name); goto recover_error2; } zone->signconf->nsec3_salt = allocator_strdup( zone->signconf->allocator, salt); free((void*) salt); salt = NULL; zone->signconf->nsec3params = nsec3params_create( (void*) zone->signconf, (uint8_t) zone->signconf->nsec3_algo, (uint8_t) zone->signconf->nsec3_optout, (uint16_t) zone->signconf->nsec3_iterations, zone->signconf->nsec3_salt); if (!zone->signconf->nsec3params) { ods_log_error("[%s] corrupted backup file zone %s: unable to " "create nsec3param", zone_str, zone->name); goto recover_error2; } } zone->signconf->last_modified = lastmod; zone->default_ttl = (uint32_t) duration2time(zone->signconf->soa_min); /* keys part */ zone->signconf->keys = keylist_create((void*) zone->signconf); while (backup_read_str(fd, &token)) { if (ods_strcmp(token, ";;Key:") == 0) { if (!key_recover2(fd, zone->signconf->keys)) { ods_log_error("[%s] corrupted backup file zone %s: read " "key error", zone_str, zone->name); goto recover_error2; } } else if (ods_strcmp(token, ";;") == 0) { /* keylist done */ free((void*) token); token = NULL; break; } else { /* keylist corrupted */ goto recover_error2; } free((void*) token); token = NULL; } /* publish dnskeys */ status = zone_publish_dnskeys(zone); if (status != ODS_STATUS_OK) { ods_log_error("[%s] corrupted backup file zone %s: unable to " "publish dnskeys (%s)", zone_str, zone->name, ods_status2str(status)); goto recover_error2; } /* publish nsec3param */ status = zone_publish_nsec3param(zone); if (status != ODS_STATUS_OK) { ods_log_error("[%s] corrupted backup file zone %s: unable to " "publish nsec3param (%s)", zone_str, zone->name, ods_status2str(status)); goto recover_error2; } /* publish other records */ status = backup_read_namedb(fd, zone); if (status != ODS_STATUS_OK) { ods_log_error("[%s] corrupted backup file zone %s: unable to " "read resource records (%s)", zone_str, zone->name, ods_status2str(status)); goto recover_error2; } /* task */ task = task_create(TASK_SIGN, when, (void*) zone); if (!task) { ods_log_error("[%s] failed to restore zone %s: unable to " "create task", zone_str, zone->name); goto recover_error2; } zone->task = (void*) task; free((void*)filename); ods_fclose(fd); /* journal */ zone->db->is_initialized = 1; filename = ods_build_path(zone->name, ".ixfr", 0, 1); if (filename) { fd = ods_fopen(filename, NULL, "r"); } if (fd) { status = backup_read_ixfr(fd, zone); if (status != ODS_STATUS_OK) { ods_log_warning("[%s] corrupted journal file zone %s, " "skipping (%s)", zone_str, zone->name, ods_status2str(status)); ixfr_cleanup(zone->ixfr); zone->ixfr = ixfr_create((void*)zone); } } lock_basic_lock(&zone->ixfr->ixfr_lock); ixfr_purge(zone->ixfr); lock_basic_unlock(&zone->ixfr->ixfr_lock); /* all ok */ free((void*)filename); ods_fclose(fd); if (zone->stats) { lock_basic_lock(&zone->stats->stats_lock); stats_clear(zone->stats); lock_basic_unlock(&zone->stats->stats_lock); } return ODS_STATUS_OK; } return ODS_STATUS_UNCHANGED; recover_error2: free((void*)filename); ods_fclose(fd); /* signconf cleanup */ free((void*)salt); salt = NULL; signconf_cleanup(zone->signconf); zone->signconf = signconf_create(); ods_log_assert(zone->signconf); /* namedb cleanup */ namedb_cleanup(zone->db); zone->db = namedb_create((void*)zone); ods_log_assert(zone->db); /* stats reset */ if (zone->stats) { lock_basic_lock(&zone->stats->stats_lock); stats_clear(zone->stats); lock_basic_unlock(&zone->stats->stats_lock); } return ODS_STATUS_ERR; }
/** * Publish the keys as indicated by the signer configuration. * */ ods_status zone_publish_dnskeys(zone_type* zone) { hsm_ctx_t* ctx = NULL; uint32_t ttl = 0; uint16_t i = 0; ods_status status = ODS_STATUS_OK; rrset_type* rrset = NULL; rr_type* dnskey = NULL; if (!zone || !zone->db || !zone->signconf || !zone->signconf->keys) { return ODS_STATUS_ASSERT_ERR; } ods_log_assert(zone->name); /* hsm access */ ctx = hsm_create_context(); if (ctx == NULL) { ods_log_error("[%s] unable to publish keys for zone %s: " "error creating libhsm context", zone_str, zone->name); return ODS_STATUS_HSM_ERR; } /* dnskey ttl */ ttl = zone->default_ttl; if (zone->signconf->dnskey_ttl) { ttl = (uint32_t) duration2time(zone->signconf->dnskey_ttl); } /* publish keys */ for (i=0; i < zone->signconf->keys->count; i++) { if (!zone->signconf->keys->keys[i].publish) { continue; } if (!zone->signconf->keys->keys[i].dnskey) { /* get dnskey */ status = lhsm_get_key(ctx, zone->apex, &zone->signconf->keys->keys[i]); if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish dnskeys for zone %s: " "error creating dnskey", zone_str, zone->name); break; } } ods_log_assert(zone->signconf->keys->keys[i].dnskey); ldns_rr_set_ttl(zone->signconf->keys->keys[i].dnskey, ttl); ldns_rr_set_class(zone->signconf->keys->keys[i].dnskey, zone->klass); status = zone_add_rr(zone, zone->signconf->keys->keys[i].dnskey, 0); if (status == ODS_STATUS_UNCHANGED) { /* rr already exists, adjust pointer */ rrset = zone_lookup_rrset(zone, zone->apex, LDNS_RR_TYPE_DNSKEY); ods_log_assert(rrset); dnskey = rrset_lookup_rr(rrset, zone->signconf->keys->keys[i].dnskey); ods_log_assert(dnskey); if (dnskey->rr != zone->signconf->keys->keys[i].dnskey) { ldns_rr_free(zone->signconf->keys->keys[i].dnskey); } zone->signconf->keys->keys[i].dnskey = dnskey->rr; status = ODS_STATUS_OK; } else if (status != ODS_STATUS_OK) { ods_log_error("[%s] unable to publish dnskeys for zone %s: " "error adding dnskey", zone_str, zone->name); break; } } /* done */ hsm_destroy_context(ctx); return status; }