/** * Parse keys from the signer configuration file. * */ keylist_type* parse_sc_keys(void* sc, const char* cfgfile) { xmlDocPtr doc = NULL; xmlXPathContextPtr xpathCtx = NULL; xmlXPathObjectPtr xpathObj = NULL; xmlNode* curNode = NULL; xmlChar* xexpr = NULL; key_type* new_key = NULL; keylist_type* kl = NULL; char* resourcerecord; char* locator; char* flags; char* algorithm; int configerr; int ksk, zsk, publish, i; if (!cfgfile || !sc) { return NULL; } /* Load XML document */ doc = xmlParseFile(cfgfile); if (doc == NULL) { ods_log_error("[%s] unable to parse <Keys>: " "xmlParseFile() failed", parser_str); return NULL; } /* Create xpath evaluation context */ xpathCtx = xmlXPathNewContext(doc); if(xpathCtx == NULL) { xmlFreeDoc(doc); ods_log_error("[%s] unable to parse <Keys>: " "xmlXPathNewContext() failed", parser_str); return NULL; } /* Evaluate xpath expression */ xexpr = (xmlChar*) "//SignerConfiguration/Zone/Keys/Key"; xpathObj = xmlXPathEvalExpression(xexpr, xpathCtx); if(xpathObj == NULL) { xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); ods_log_error("[%s] unable to parse <Keys>: " "xmlXPathEvalExpression() failed", parser_str); return NULL; } /* Parse keys */ kl = keylist_create(sc); ods_log_assert(kl); if (xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0) { for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { resourcerecord = NULL; locator = NULL; flags = NULL; algorithm = NULL; ksk = 0; zsk = 0; publish = 0; configerr = 0; curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode; while (curNode) { if (xmlStrEqual(curNode->name, (const xmlChar *)"Locator")) { locator = (char *) xmlNodeGetContent(curNode); } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Algorithm")) { algorithm = (char *) xmlNodeGetContent(curNode); } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Flags")) { flags = (char *) xmlNodeGetContent(curNode); } else if (xmlStrEqual(curNode->name, (const xmlChar *)"KSK")) { ksk = 1; } else if (xmlStrEqual(curNode->name, (const xmlChar *)"ZSK")) { zsk = 1; } else if (xmlStrEqual(curNode->name, (const xmlChar *)"Publish")) { publish = 1; } else if (xmlStrEqual(curNode->name, (const xmlChar *)"ResourceRecord")) { resourcerecord = (char *) xmlNodeGetContent(curNode); } curNode = curNode->next; } if (!algorithm) configerr = 1; if (!flags) configerr = 1; if (!locator && !resourcerecord) configerr = 1; if (!configerr) { /* search for duplicates */ new_key = keylist_lookup_by_locator(kl, locator); if (new_key && new_key->algorithm == (uint8_t) atoi(algorithm) && new_key->flags == (uint32_t) atoi(flags) && new_key->publish == publish && new_key->ksk == ksk && new_key->zsk == zsk) { /* duplicate */ ods_log_warning("[%s] unable to push duplicate key %s " "to keylist, skipping", parser_str, locator); } else { (void) keylist_push(kl, locator, resourcerecord, (uint8_t) atoi(algorithm), (uint32_t) atoi(flags), publish, ksk, zsk); } } else { ods_log_error("[%s] unable to push key to keylist: <Key> " "is missing required elements, skipping", parser_str); } free((void*)algorithm); free((void*)flags); } } xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); if (doc) { xmlFreeDoc(doc); } return kl; }
/** * 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; }