Beispiel #1
0
/**
 * 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;
}
Beispiel #2
0
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;
}		
Beispiel #3
0
/**
 * 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);
}
Beispiel #4
0
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;
}
Beispiel #6
0
/**
 * 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;
}
Beispiel #7
0
/**
 * 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;
}
Beispiel #8
0
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;
}