OpenDNSSEC-enforcer 1.3.0
|
00001 /* 00002 * $Id: enforcer.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2008-2009 Nominet UK. 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 00029 /* 00030 * enforcer.c code implements the server_main 00031 * function needed by daemon.c 00032 * 00033 * The bit that makes the daemon do something useful 00034 */ 00035 00036 #include <stdlib.h> 00037 #include <errno.h> 00038 #include <string.h> 00039 #include <stdio.h> 00040 #include <syslog.h> 00041 00042 #include <libxml/xmlreader.h> 00043 #include <libxml/xpath.h> 00044 00045 #include "config.h" 00046 00047 #include "daemon.h" 00048 #include "daemon_util.h" 00049 #include "enforcer.h" 00050 #include "kaspaccess.h" 00051 00052 #include "ksm/ksm.h" 00053 #include "ksm/memory.h" 00054 #include "ksm/string_util.h" 00055 #include "ksm/string_util2.h" 00056 #include "ksm/datetime.h" 00057 #include "ksm/db_fields.h" 00058 00059 #include "libhsm.h" 00060 #include "libhsmdns.h" 00061 00062 int 00063 server_init(DAEMONCONFIG *config) 00064 { 00065 if (config == NULL) { 00066 log_msg(NULL, LOG_ERR, "Error in server_init, no config provided"); 00067 exit(1); 00068 } 00069 00070 /* set the default pidfile if nothing was provided on the command line*/ 00071 if (config->pidfile == NULL) { 00072 config->pidfile = OPENDNSSEC_ENFORCER_PIDFILE; 00073 } 00074 00075 return 0; 00076 } 00077 00078 /* 00079 * Main loop of enforcerd server 00080 */ 00081 void 00082 server_main(DAEMONCONFIG *config) 00083 { 00084 DB_RESULT handle; 00085 DB_HANDLE dbhandle; 00086 int status = 0; 00087 struct timeval tv; 00088 KSM_POLICY *policy; 00089 int result; 00090 hsm_ctx_t *ctx = NULL; 00091 char *hsm_error_message = NULL; 00092 00093 FILE *lock_fd = NULL; /* for sqlite file locking */ 00094 char *lock_filename = NULL; 00095 00096 if (config == NULL) { 00097 log_msg(NULL, LOG_ERR, "Error in server_main, no config provided"); 00098 exit(1); 00099 } 00100 00101 policy = KsmPolicyAlloc(); 00102 if (policy == NULL) { 00103 log_msg(config, LOG_ERR, "Malloc for policy struct failed"); 00104 unlink(config->pidfile); 00105 exit(1); 00106 } 00107 kaspSetPolicyDefaults(policy, NULL); 00108 00109 /* Read the config file */ 00110 status = ReadConfig(config , 0); 00111 if (status != 0) { 00112 log_msg(config, LOG_ERR, "Error reading config"); 00113 unlink(config->pidfile); 00114 exit(1); 00115 } 00116 00117 /* If we are doing key generation then connect to the hsm */ 00118 /* if (config->manualKeyGeneration == 0) {*/ 00119 /* We keep the HSM connection open for the lifetime of the daemon */ 00120 if (config->configfile != NULL) { 00121 result = hsm_open(config->configfile, hsm_prompt_pin, NULL); 00122 } else { 00123 result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_prompt_pin, NULL); 00124 } 00125 if (result) { 00126 hsm_error_message = hsm_get_error(ctx); 00127 if (hsm_error_message) { 00128 log_msg(config, LOG_ERR, "%s", hsm_error_message); 00129 free(hsm_error_message); 00130 } else { 00131 /* decode the error code ourselves 00132 TODO find if there is a better way to do this (and can all of these be returned? are there others?) */ 00133 switch (result) { 00134 case HSM_ERROR: 00135 log_msg(config, LOG_ERR, "hsm_open() result: HSM error"); 00136 break; 00137 case HSM_PIN_INCORRECT: 00138 log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN"); 00139 break; 00140 case HSM_CONFIG_FILE_ERROR: 00141 log_msg(config, LOG_ERR, "hsm_open() result: config file error"); 00142 break; 00143 case HSM_REPOSITORY_NOT_FOUND: 00144 log_msg(config, LOG_ERR, "hsm_open() result: repository not found"); 00145 break; 00146 case HSM_NO_REPOSITORIES: 00147 log_msg(config, LOG_ERR, "hsm_open() result: no repositories"); 00148 break; 00149 default: 00150 log_msg(config, LOG_ERR, "hsm_open() result: %d", result); 00151 } 00152 } 00153 unlink(config->pidfile); 00154 exit(1); 00155 } 00156 log_msg(config, LOG_INFO, "HSM opened successfully."); 00157 ctx = hsm_create_context(); 00158 /*}*/ 00159 00160 while (1) { 00161 00162 /* Read the config file */ 00163 status = ReadConfig(config, 1); 00164 if (status != 0) { 00165 log_msg(config, LOG_ERR, "Error reading config"); 00166 unlink(config->pidfile); 00167 exit(1); 00168 } 00169 /* If we are in sqlite mode then take a lock out on a file to 00170 prevent multiple access (not sure that we can be sure that sqlite is 00171 safe for multiple processes to access). */ 00172 if (DbFlavour() == SQLITE_DB) { 00173 00174 /* set up lock filename (it may have changed?) */ 00175 lock_filename = NULL; 00176 StrAppend(&lock_filename, (char *)config->schema); 00177 StrAppend(&lock_filename, ".our_lock"); 00178 00179 lock_fd = fopen(lock_filename, "w"); 00180 status = get_lite_lock(lock_filename, lock_fd); 00181 StrFree(lock_filename); 00182 if (status != 0) { 00183 log_msg(config, LOG_ERR, "Error getting db lock"); 00184 unlink(config->pidfile); 00185 exit(1); 00186 } 00187 } 00188 00189 log_msg(config, LOG_INFO, "Connecting to Database..."); 00190 kaspConnect(config, &dbhandle); 00191 00192 /* Read all policies */ 00193 status = KsmPolicyInit(&handle, NULL); 00194 if (status == 0) { 00195 /* get the first policy */ 00196 status = KsmPolicy(handle, policy); 00197 while (status == 0) { 00198 log_msg(config, LOG_INFO, "Policy %s found.", policy->name); 00199 /* Clear the policy struct */ 00200 kaspSetPolicyDefaults(policy, NULL); 00201 00202 /* Read the parameters for that policy */ 00203 status = kaspReadPolicy(policy); 00204 00205 /* Update the salt if it is not up to date */ 00206 if (policy->denial->version == 3) 00207 { 00208 status = KsmPolicyUpdateSalt(policy); 00209 if (status != 0) { 00210 /* Don't return? */ 00211 log_msg(config, LOG_ERR, "Error (%d) updating salt for %s", status, policy->name); 00212 } 00213 } 00214 00215 /* Do keygen stuff if required */ 00216 if (config->manualKeyGeneration == 0) { 00217 status = do_keygen(config, policy, ctx); 00218 } 00219 00220 /* TODO move communicated stuff here eventually */ 00221 /* Find all zones and do communication stuff */ 00222 00223 /* Purge dead keys if we are asked to in this policy */ 00224 if (policy->keys->purge != -1) { 00225 status = do_purge(policy->keys->purge, policy->id); 00226 } 00227 00228 /* get next policy */ 00229 status = KsmPolicy(handle, policy); 00230 } 00231 } else { 00232 log_msg(config, LOG_ERR, "Error querying KASP DB for policies."); 00233 unlink(config->pidfile); 00234 exit(1); 00235 } 00236 00237 /* Communicate zones to the signer */ 00238 do_communication(config, policy); 00239 00240 DbFreeResult(handle); 00241 00242 /* Disconnect from DB in case we are asleep for a long time */ 00243 log_msg(config, LOG_INFO, "Disconnecting from Database..."); 00244 kaspDisconnect(&dbhandle); 00245 00246 /* Release sqlite lock file (if we have it) */ 00247 if (DbFlavour() == SQLITE_DB) { 00248 status = release_lite_lock(lock_fd); 00249 if (status != 0) { 00250 log_msg(config, LOG_ERR, "Error releasing db lock"); 00251 unlink(config->pidfile); 00252 exit(1); 00253 } 00254 fclose(lock_fd); 00255 } 00256 00257 if (config->once == true ){ 00258 log_msg(config, LOG_INFO, "Running once only, exiting..."); 00259 break; 00260 } 00261 00262 /* If we have been sent a SIGTERM then it is time to exit */ 00263 if (config->term == 1 ){ 00264 log_msg(config, LOG_INFO, "Received SIGTERM, exiting..."); 00265 break; 00266 } 00267 /* Or SIGINT */ 00268 if (config->term == 2 ){ 00269 log_msg(config, LOG_INFO, "Received SIGINT, exiting..."); 00270 break; 00271 } 00272 00273 /* sleep for the interval */ 00274 tv.tv_sec = config->interval; 00275 tv.tv_usec = 0; 00276 log_msg(config, LOG_INFO, "Sleeping for %i seconds.",config->interval); 00277 select(0, NULL, NULL, NULL, &tv); 00278 00279 /* If we have been sent a SIGTERM then it is time to exit */ 00280 if (config->term == 1 ){ 00281 log_msg(config, LOG_INFO, "Received SIGTERM, exiting..."); 00282 break; 00283 } 00284 /* Or SIGINT */ 00285 if (config->term == 2 ){ 00286 log_msg(config, LOG_INFO, "Received SIGINT, exiting..."); 00287 break; 00288 } 00289 } 00290 00291 /* 00292 * Destroy HSM context 00293 */ 00294 if (ctx) { 00295 hsm_destroy_context(ctx); 00296 } 00297 00298 result = hsm_close(); 00299 log_msg(config, LOG_INFO, "all done! hsm_close result: %d", result); 00300 00301 KsmPolicyFree(policy); 00302 00303 if (unlink(config->pidfile) == -1) { 00304 log_msg(config, LOG_ERR, "unlink pidfile %s failed: %s", 00305 config->pidfile?config->pidfile:"(null)", 00306 strerror(errno)); 00307 } 00308 00309 xmlCleanupParser(); 00310 00311 } 00312 00313 int do_keygen(DAEMONCONFIG *config, KSM_POLICY* policy, hsm_ctx_t *ctx) 00314 { 00315 int status = 0; 00316 00317 char *rightnow; 00318 int i = 0; 00319 char *id; 00320 hsm_key_t *key = NULL; 00321 char *hsm_error_message = NULL; 00322 DB_ID ignore = 0; 00323 int ksks_needed = 0; /* Total No of ksks needed before next generation run */ 00324 int zsks_needed = 0; /* Total No of zsks needed before next generation run */ 00325 int keys_in_queue = 0; /* number of unused keys */ 00326 int new_keys = 0; /* number of keys required */ 00327 unsigned int current_count = 0; /* number of keys already in HSM */ 00328 00329 int same_keys = 0; /* Do ksks and zsks look the same ? */ 00330 int ksks_created = 0; /* Were any KSKs created? */ 00331 00332 DB_RESULT result; 00333 int zone_count = 0; /* Number of zones on policy */ 00334 00335 if (policy->shared_keys == 1 ) { 00336 log_msg(config, LOG_INFO, "Key sharing is On"); 00337 } else { 00338 log_msg(config, LOG_INFO, "Key sharing is Off."); 00339 } 00340 00341 rightnow = DtParseDateTimeString("now"); 00342 00343 /* Check datetime in case it came back NULL */ 00344 if (rightnow == NULL) { 00345 log_msg(config, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting..."); 00346 exit(1); 00347 } 00348 00349 /* See if our ZSKs and KSKs look the same */ 00350 if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) { 00351 same_keys = 1; 00352 } else { 00353 same_keys = 0; 00354 } 00355 00356 /* How many zones on this policy */ 00357 status = KsmZoneCountInit(&result, policy->id); 00358 if (status == 0) { 00359 status = KsmZoneCount(result, &zone_count); 00360 } 00361 DbFreeResult(result); 00362 00363 if (status == 0) { 00364 /* make sure that we have at least one zone */ 00365 if (zone_count == 0) { 00366 log_msg(config, LOG_INFO, "No zones on policy %s, skipping...", policy->name); 00367 StrFree(rightnow); 00368 return status; 00369 } 00370 } else { 00371 log_msg(NULL, LOG_ERR, "Could not count zones on policy %s", policy->name); 00372 StrFree(rightnow); 00373 return status; 00374 } 00375 00376 /* Find out how many ksk keys are needed for the POLICY */ 00377 status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, config->interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count); 00378 if (status != 0) { 00379 log_msg(NULL, LOG_ERR, "Could not predict ksk requirement for next interval for %s", policy->name); 00380 /* TODO exit? continue with next policy? */ 00381 } 00382 /* Find out how many suitable keys we have */ 00383 status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_KSK); 00384 if (status != 0) { 00385 log_msg(NULL, LOG_ERR, "Could not count current ksk numbers for policy %s", policy->name); 00386 /* TODO exit? continue with next policy? */ 00387 } 00388 /* Correct for shared keys */ 00389 if (policy->shared_keys == KSM_KEYS_SHARED) { 00390 keys_in_queue /= zone_count; 00391 } 00392 00393 new_keys = ksks_needed - keys_in_queue; 00394 /* fprintf(stderr, "keygen(ksk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, ksks_needed, keys_in_queue); */ 00395 00396 /* Check capacity of HSM will not be exceeded */ 00397 if (policy->ksk->sm_capacity != 0) { 00398 current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name); 00399 if (current_count >= policy->ksk->sm_capacity) { 00400 log_msg(config, LOG_ERR, "Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name); 00401 new_keys = 0; 00402 } 00403 else if (current_count + new_keys > policy->ksk->sm_capacity) { 00404 log_msg(config, LOG_WARNING, "Repository %s is nearly full, will create %lu KSKs for policy %s (reduced from %d)\n", policy->ksk->sm_name, policy->ksk->sm_capacity - current_count, policy->name, new_keys); 00405 new_keys = policy->ksk->sm_capacity - current_count; 00406 } 00407 } 00408 00409 /* Create the required keys */ 00410 for (i=new_keys ; i > 0 ; i--){ 00411 if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) { 00412 /* NOTE: for now we know that libhsm only supports RSA keys */ 00413 key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits); 00414 if (key) { 00415 log_msg(config, LOG_DEBUG, "Created key in repository %s", policy->ksk->sm_name); 00416 } else { 00417 log_msg(config, LOG_ERR, "Error creating key in repository %s", policy->ksk->sm_name); 00418 hsm_error_message = hsm_get_error(ctx); 00419 if (hsm_error_message) { 00420 log_msg(config, LOG_ERR, "%s", hsm_error_message); 00421 free(hsm_error_message); 00422 } 00423 unlink(config->pidfile); 00424 exit(1); 00425 } 00426 id = hsm_get_key_id(ctx, key); 00427 hsm_key_free(key); 00428 status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore); 00429 if (status != 0) { 00430 log_msg(config, LOG_ERR,"Error creating key in Database"); 00431 hsm_error_message = hsm_get_error(ctx); 00432 if (hsm_error_message) { 00433 log_msg(config, LOG_ERR, "%s", hsm_error_message); 00434 free(hsm_error_message); 00435 } 00436 unlink(config->pidfile); 00437 exit(1); 00438 } 00439 log_msg(config, LOG_INFO, "Created KSK size: %i, alg: %i with id: %s in repository: %s and database.", policy->ksk->bits, 00440 policy->ksk->algorithm, id, policy->ksk->sm_name); 00441 free(id); 00442 } else { 00443 log_msg(config, LOG_ERR, "Key algorithm %d unsupported by libhsm, exiting...", policy->ksk->algorithm); 00444 unlink(config->pidfile); 00445 exit(1); 00446 } 00447 } 00448 ksks_created = new_keys; 00449 00450 /* Find out how many zsk keys are needed */ 00451 keys_in_queue = 0; 00452 new_keys = 0; 00453 current_count = 0; 00454 00455 /* Find out how many zsk keys are needed for the POLICY */ 00456 status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, config->interval, &zsks_needed, 0, zone_count); 00457 if (status != 0) { 00458 log_msg(NULL, LOG_ERR, "Could not predict zsk requirement for next intervalfor %s", policy->name); 00459 /* TODO exit? continue with next policy? */ 00460 } 00461 /* Find out how many suitable keys we have */ 00462 status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK); 00463 if (status != 0) { 00464 log_msg(NULL, LOG_ERR, "Could not count current zsk numbers for policy %s", policy->name); 00465 /* TODO exit? continue with next policy? */ 00466 } 00467 /* Correct for shared keys */ 00468 if (policy->shared_keys == KSM_KEYS_SHARED) { 00469 keys_in_queue /= zone_count; 00470 } 00471 /* Might have to account for ksks */ 00472 if (same_keys) { 00473 keys_in_queue -= ksks_needed; 00474 } 00475 00476 new_keys = zsks_needed - keys_in_queue; 00477 /* fprintf(stderr, "keygen(zsk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, zsks_needed, keys_in_queue); */ 00478 00479 /* Check capacity of HSM will not be exceeded */ 00480 if (policy->zsk->sm_capacity != 0) { 00481 current_count = hsm_count_keys_repository(ctx, policy->zsk->sm_name); 00482 if (current_count >= policy->zsk->sm_capacity) { 00483 log_msg(config, LOG_ERR, "Repository %s is full, cannot create more ZSKs for policy %s\n", policy->zsk->sm_name, policy->name); 00484 new_keys = 0; 00485 } 00486 else if (current_count + new_keys > policy->zsk->sm_capacity) { 00487 log_msg(config, LOG_WARNING, "Repository %s is nearly full, will create %lu ZSKs for policy %s (reduced from %d)\n", policy->zsk->sm_name, policy->zsk->sm_capacity - current_count, policy->name, new_keys); 00488 new_keys = policy->zsk->sm_capacity - current_count; 00489 } 00490 } 00491 00492 /* Create the required keys */ 00493 for (i = new_keys ; i > 0 ; i--) { 00494 if (hsm_supported_algorithm(policy->zsk->algorithm) == 0) { 00495 /* NOTE: for now we know that libhsm only supports RSA keys */ 00496 key = hsm_generate_rsa_key(ctx, policy->zsk->sm_name, policy->zsk->bits); 00497 if (key) { 00498 log_msg(config, LOG_DEBUG, "Created key in repository %s", policy->zsk->sm_name); 00499 } else { 00500 log_msg(config, LOG_ERR, "Error creating key in repository %s", policy->zsk->sm_name); 00501 hsm_error_message = hsm_get_error(ctx); 00502 if (hsm_error_message) { 00503 log_msg(config, LOG_ERR, "%s", hsm_error_message); 00504 free(hsm_error_message); 00505 } 00506 unlink(config->pidfile); 00507 hsm_key_free(key); 00508 exit(1); 00509 } 00510 id = hsm_get_key_id(ctx, key); 00511 hsm_key_free(key); 00512 status = KsmKeyPairCreate(policy->id, id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, rightnow, &ignore); 00513 if (status != 0) { 00514 log_msg(config, LOG_ERR,"Error creating key in Database"); 00515 hsm_error_message = hsm_get_error(ctx); 00516 if (hsm_error_message) { 00517 log_msg(config, LOG_ERR, "%s", hsm_error_message); 00518 free(hsm_error_message); 00519 } 00520 unlink(config->pidfile); 00521 exit(1); 00522 } 00523 log_msg(config, LOG_INFO, "Created ZSK size: %i, alg: %i with id: %s in repository: %s and database.", policy->zsk->bits, 00524 policy->zsk->algorithm, id, policy->zsk->sm_name); 00525 free(id); 00526 } else { 00527 log_msg(config, LOG_ERR, "Key algorithm %d unsupported by libhsm, exiting...", policy->zsk->algorithm); 00528 unlink(config->pidfile); 00529 exit(1); 00530 } 00531 } 00532 StrFree(rightnow); 00533 00534 /* Log if a backup needs to be run for these keys */ 00535 if (ksks_created && policy->ksk->require_backup) { 00536 log_msg(config, LOG_INFO, "NOTE: keys generated in repository %s will not become active until they have been backed up", policy->ksk->sm_name); 00537 } 00538 if (new_keys && policy->zsk->require_backup && (policy->zsk->sm != policy->ksk->sm)) { 00539 log_msg(config, LOG_INFO, "NOTE: keys generated in repository %s will not become active until they have been backed up", policy->zsk->sm_name); 00540 } 00541 00542 return status; 00543 } 00544 00545 int do_communication(DAEMONCONFIG *config, KSM_POLICY* policy) 00546 { 00547 int status = 0; 00548 int status2 = 0; 00549 00550 xmlTextReaderPtr reader = NULL; 00551 xmlDocPtr doc = NULL; 00552 xmlXPathContextPtr xpathCtx = NULL; 00553 xmlXPathObjectPtr xpathObj = NULL; 00554 00555 int ret = 0; /* status of the XML parsing */ 00556 char* zonelist_filename = NULL; 00557 char* zone_name; 00558 char* current_policy; 00559 char* current_filename; 00560 char *tag_name; 00561 int zone_id = -1; 00562 int signer_flag = 1; /* Is the signer responding? (1 == yes) */ 00563 char* ksk_expected = NULL; /* When is the next ksk rollover expected? */ 00564 00565 xmlChar *name_expr = (unsigned char*) "name"; 00566 xmlChar *policy_expr = (unsigned char*) "//Zone/Policy"; 00567 xmlChar *filename_expr = (unsigned char*) "//Zone/SignerConfiguration"; 00568 00569 char* temp_char = NULL; 00570 00571 /* Stuff to see if we need to log an "impending rollover" warning */ 00572 char* datetime = NULL; 00573 int roll_time = 0; 00574 00575 /* Let's find our zonelist from the conf.xml */ 00576 if (config->configfile != NULL) { 00577 status = read_zonelist_filename(config->configfile, &zonelist_filename); 00578 } else { 00579 status = read_zonelist_filename(OPENDNSSEC_CONFIG_FILE, &zonelist_filename); 00580 } 00581 00582 if (status != 0) { 00583 log_msg(NULL, LOG_ERR, "couldn't read zonelist filename"); 00584 unlink(config->pidfile); 00585 exit(1); 00586 } 00587 00588 /* In case zonelist is huge use the XmlTextReader API so that we don't hold the whole file in memory */ 00589 reader = xmlNewTextReaderFilename(zonelist_filename); 00590 if (reader != NULL) { 00591 ret = xmlTextReaderRead(reader); 00592 while (ret == 1) { 00593 tag_name = (char*) xmlTextReaderLocalName(reader); 00594 /* Found <Zone> */ 00595 if (strncmp(tag_name, "Zone", 4) == 0 00596 && strncmp(tag_name, "ZoneList", 8) != 0 00597 && xmlTextReaderNodeType(reader) == 1) { 00598 /* Get the zone name (TODO what if this is null?) */ 00599 zone_name = NULL; 00600 temp_char = (char*) xmlTextReaderGetAttribute(reader, name_expr); 00601 StrAppend(&zone_name, temp_char); 00602 StrFree(temp_char); 00603 /* Make sure that we got something */ 00604 if (zone_name == NULL) { 00605 /* error */ 00606 log_msg(NULL, LOG_ERR, "Error extracting zone name from %s", zonelist_filename); 00607 /* Don't return? try to parse the rest of the zones? */ 00608 ret = xmlTextReaderRead(reader); 00609 StrFree(tag_name); 00610 continue; 00611 } 00612 00613 00614 log_msg(config, LOG_INFO, "Zone %s found.", zone_name); 00615 00616 /* Get zone ID from name (or skip if it doesn't exist) */ 00617 status = KsmZoneIdFromName(zone_name, &zone_id); 00618 if (status != 0 || zone_id == -1) 00619 { 00620 /* error */ 00621 log_msg(NULL, LOG_ERR, "Error looking up zone \"%s\" in database (please make sure that the zonelist file is up to date)", zone_name); 00622 /* Don't return? try to parse the rest of the zones? */ 00623 ret = xmlTextReaderRead(reader); 00624 StrFree(tag_name); 00625 StrFree(zone_name); 00626 continue; 00627 } 00628 00629 /* Expand this node and get the rest of the info with XPath */ 00630 xmlTextReaderExpand(reader); 00631 doc = xmlTextReaderCurrentDoc(reader); 00632 if (doc == NULL) { 00633 log_msg(config, LOG_ERR, "Error: can not read zone \"%s\"; skipping", zone_name); 00634 /* Don't return? try to parse the rest of the zones? */ 00635 ret = xmlTextReaderRead(reader); 00636 StrFree(tag_name); 00637 StrFree(zone_name); 00638 continue; 00639 } 00640 00641 /* TODO should we validate here? Or should we validate the whole document? */ 00642 00643 xpathCtx = xmlXPathNewContext(doc); 00644 if(xpathCtx == NULL) { 00645 log_msg(config, LOG_ERR,"Error: can not create XPath context for \"%s\"; skipping zone", zone_name); 00646 /* Don't return? try to parse the rest of the zones? */ 00647 ret = xmlTextReaderRead(reader); 00648 StrFree(tag_name); 00649 StrFree(zone_name); 00650 continue; 00651 } 00652 00653 /* Extract the Policy name and signer configuration filename for this zone */ 00654 /* Evaluate xpath expression for policy */ 00655 xpathObj = xmlXPathEvalExpression(policy_expr, xpathCtx); 00656 if(xpathObj == NULL) { 00657 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s; skipping zone", policy_expr); 00658 /* Don't return? try to parse the rest of the zones? */ 00659 ret = xmlTextReaderRead(reader); 00660 StrFree(tag_name); 00661 StrFree(zone_name); 00662 continue; 00663 } 00664 current_policy = NULL; 00665 temp_char = (char*) xmlXPathCastToString(xpathObj); 00666 StrAppend(¤t_policy, temp_char); 00667 StrFree(temp_char); 00668 log_msg(config, LOG_INFO, "Policy for %s set to %s.", zone_name, current_policy); 00669 xmlXPathFreeObject(xpathObj); 00670 00671 if (strcmp(current_policy, policy->name) != 0) { 00672 00673 /* Read new Policy */ 00674 kaspSetPolicyDefaults(policy, current_policy); 00675 00676 status2 = KsmPolicyRead(policy); 00677 if (status2 != 0) { 00678 /* Don't return? try to parse the rest of the zones? */ 00679 log_msg(config, LOG_ERR, "Error reading policy"); 00680 ret = xmlTextReaderRead(reader); 00681 StrFree(tag_name); 00682 StrFree(zone_name); 00683 continue; 00684 } 00685 log_msg(config, LOG_INFO, "Policy %s found in DB.", policy->name); 00686 00687 } /* else */ 00688 /* Policy is same as previous zone, do not re-read */ 00689 00690 StrFree(current_policy); 00691 00692 /* Evaluate xpath expression for signer configuration filename */ 00693 xpathObj = xmlXPathEvalExpression(filename_expr, xpathCtx); 00694 xmlXPathFreeContext(xpathCtx); 00695 00696 if(xpathObj == NULL) { 00697 log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s; skipping zone", filename_expr); 00698 /* Don't return? try to parse the rest of the zones? */ 00699 ret = xmlTextReaderRead(reader); 00700 StrFree(tag_name); 00701 StrFree(zone_name); 00702 continue; 00703 } 00704 current_filename = NULL; 00705 temp_char = (char*)xmlXPathCastToString(xpathObj); 00706 StrAppend(¤t_filename, temp_char); 00707 StrFree(temp_char); 00708 log_msg(config, LOG_INFO, "Config will be output to %s.", current_filename); 00709 xmlXPathFreeObject(xpathObj); 00710 /* TODO should we check that we have not written to this file in this run?*/ 00711 /* Make sure that enough keys are allocated to this zone */ 00712 status2 = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, 0); 00713 if (status2 != 0) { 00714 log_msg(config, LOG_ERR, "Error allocating zsks to zone %s", zone_name); 00715 /* Don't return? try to parse the rest of the zones? */ 00716 ret = xmlTextReaderRead(reader); 00717 StrFree(tag_name); 00718 StrFree(zone_name); 00719 StrFree(current_filename); 00720 continue; 00721 } 00722 status2 = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, policy->ksk->rollover_scheme); 00723 if (status2 != 0) { 00724 log_msg(config, LOG_ERR, "Error allocating ksks to zone %s", zone_name); 00725 /* Don't return? try to parse the rest of the zones? */ 00726 ret = xmlTextReaderRead(reader); 00727 StrFree(tag_name); 00728 StrFree(zone_name); 00729 StrFree(current_filename); 00730 continue; 00731 } 00732 00733 /* turn this zone and policy into a file */ 00734 status2 = commGenSignConf(zone_name, zone_id, current_filename, policy, &signer_flag, config->interval, config->manualKeyGeneration, config->DSSubmitCmd); 00735 if (status2 == -2) { 00736 log_msg(config, LOG_ERR, "Signconf not written for %s", zone_name); 00737 /* Don't return? try to parse the rest of the zones? */ 00738 ret = xmlTextReaderRead(reader); 00739 StrFree(tag_name); 00740 StrFree(zone_name); 00741 StrFree(current_filename); 00742 continue; 00743 } 00744 else if (status2 != 0) { 00745 log_msg(config, LOG_ERR, "Error writing signconf for %s", zone_name); 00746 /* Don't return? try to parse the rest of the zones? */ 00747 ret = xmlTextReaderRead(reader); 00748 StrFree(tag_name); 00749 StrFree(zone_name); 00750 StrFree(current_filename); 00751 continue; 00752 } 00753 00754 /* See if we need to send a warning about an impending rollover */ 00755 if (config->rolloverNotify != -1) { 00756 datetime = DtParseDateTimeString("now"); 00757 00758 /* Check datetime in case it came back NULL */ 00759 if (datetime == NULL) { 00760 log_msg(config, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting..."); 00761 unlink(config->pidfile); 00762 exit(1); 00763 } 00764 00765 /* First the KSK */ 00766 status2 = KsmCheckNextRollover(KSM_TYPE_KSK, zone_id, &ksk_expected); 00767 if (status2 == -1) { 00768 log_msg(config, LOG_INFO, "No active KSKs yet for zone %s, can't check for impending rollover", zone_name); 00769 } 00770 else if (status2 != 0) { 00771 log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name); 00772 /* TODO should we quit or continue? */ 00773 } else { 00774 status2 = DtDateDiff(ksk_expected, datetime, &roll_time); 00775 if (status2 != 0) { 00776 log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name); 00777 } else { 00778 00779 if (roll_time <= config->rolloverNotify) { 00780 log_msg(config, LOG_INFO, "Rollover of KSK expected at %s for %s", ksk_expected, zone_name); 00781 } 00782 StrFree(ksk_expected); 00783 } 00784 } 00785 StrFree(datetime); 00786 } 00787 00788 StrFree(current_filename); 00789 StrFree(zone_name); 00790 } 00791 /* Read the next line */ 00792 ret = xmlTextReaderRead(reader); 00793 StrFree(tag_name); 00794 } 00795 xmlFreeTextReader(reader); 00796 if (ret != 0) { 00797 log_msg(config, LOG_ERR, "%s : failed to parse", zonelist_filename); 00798 } 00799 } else { 00800 log_msg(config, LOG_ERR, "Unable to open %s", zonelist_filename); 00801 } 00802 00803 xmlFreeDoc(doc); 00804 StrFree(zonelist_filename); 00805 00806 return status; 00807 } 00808 00809 /* 00810 * generate the configuration file for the signer 00811 00812 * returns 0 on success and -1 if something went wrong 00813 * -2 if the RequestKeys call failed 00814 */ 00815 int commGenSignConf(char* zone_name, int zone_id, char* current_filename, KSM_POLICY *policy, int* signer_flag, int run_interval, int man_key_gen, const char* DSSubmitCmd) 00816 { 00817 int status = 0; 00818 int status2 = 0; 00819 FILE *file, *file2; 00820 int char1, char2; /* for the comparison between 2 files */ 00821 int same = 0; 00822 char *temp_filename; /* In case this fails we write to a temp file and only overwrite 00823 the current file when we are finished */ 00824 char *old_filename; /* Keep a copy of the previous version, just in case! (Also gets 00825 round potentially different behaviour of rename over existing 00826 file.) */ 00827 char *signer_command; /* how we will call the signer */ 00828 int gencnt; /* Number of keys in generate state */ 00829 int NewDS = 0; /* Did we change the DS Set in any way? */ 00830 char* datetime = DtParseDateTimeString("now"); 00831 00832 /* Check datetime in case it came back NULL */ 00833 if (datetime == NULL) { 00834 log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting..."); 00835 exit(1); 00836 } 00837 00838 if (zone_name == NULL || current_filename == NULL || policy == NULL) 00839 { 00840 /* error */ 00841 log_msg(NULL, LOG_ERR, "commGenSignConf, NULL policy or zone provided"); 00842 MemFree(datetime); 00843 return -1; 00844 } 00845 00846 old_filename = NULL; 00847 StrAppend(&old_filename, current_filename); 00848 StrAppend(&old_filename, ".OLD"); 00849 00850 temp_filename = NULL; 00851 StrAppend(&temp_filename, current_filename); 00852 StrAppend(&temp_filename, ".tmp"); 00853 00854 file = fopen(temp_filename, "w"); 00855 00856 if (file == NULL) 00857 { 00858 /* error */ 00859 log_msg(NULL, LOG_ERR, "Could not open: %s", temp_filename); 00860 MemFree(datetime); 00861 StrFree(temp_filename); 00862 StrFree(old_filename); 00863 return -1; 00864 } 00865 00866 fprintf(file, "<SignerConfiguration>\n"); 00867 fprintf(file, "\t<Zone name=\"%s\">\n", zone_name); 00868 00869 fprintf(file, "\t\t<Signatures>\n"); 00870 fprintf(file, "\t\t\t<Resign>PT%dS</Resign>\n", policy->signature->resign); 00871 fprintf(file, "\t\t\t<Refresh>PT%dS</Refresh>\n", policy->signer->refresh); 00872 fprintf(file, "\t\t\t<Validity>\n"); 00873 fprintf(file, "\t\t\t\t<Default>PT%dS</Default>\n", policy->signature->valdefault); 00874 fprintf(file, "\t\t\t\t<Denial>PT%dS</Denial>\n", policy->signature->valdenial); 00875 fprintf(file, "\t\t\t</Validity>\n"); 00876 fprintf(file, "\t\t\t<Jitter>PT%dS</Jitter>\n", policy->signer->jitter); 00877 fprintf(file, "\t\t\t<InceptionOffset>PT%dS</InceptionOffset>\n", policy->signature->clockskew); 00878 fprintf(file, "\t\t</Signatures>\n"); 00879 00880 fprintf(file, "\n"); 00881 00882 fprintf(file, "\t\t<Denial>\n"); 00883 if (policy->denial->version == 3) 00884 { 00885 fprintf(file, "\t\t\t<NSEC3>\n"); 00886 if (policy->denial->optout == 1) 00887 { 00888 fprintf(file, "\t\t\t\t<OptOut />\n"); 00889 } 00890 fprintf(file, "\t\t\t\t<Hash>\n"); 00891 fprintf(file, "\t\t\t\t\t<Algorithm>%d</Algorithm>\n", policy->denial->algorithm); 00892 fprintf(file, "\t\t\t\t\t<Iterations>%d</Iterations>\n", policy->denial->iteration); 00893 if (policy->denial->salt[0] == '\0') { 00894 fprintf(file, "\t\t\t\t\t<Salt>-</Salt>\n"); 00895 } else { 00896 fprintf(file, "\t\t\t\t\t<Salt>%s</Salt>\n", policy->denial->salt); 00897 } 00898 fprintf(file, "\t\t\t\t</Hash>\n"); 00899 fprintf(file, "\t\t\t</NSEC3>\n"); 00900 } else { 00901 fprintf(file, "\t\t\t<NSEC />\n"); 00902 } 00903 00904 fprintf(file, "\t\t</Denial>\n"); 00905 00906 fprintf(file, "\n"); 00907 00908 /* start of keys section */ 00909 fprintf(file, "\t\t<Keys>\n"); 00910 fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->ksk->ttl); 00911 00912 /* get new keys _only_ if we don't have them from before */ 00913 status = KsmRequestKeys(0, 0, datetime, commKeyConfig, file, policy->id, zone_id, run_interval, &NewDS); 00914 if (status != 0) { 00915 /* 00916 * Something went wrong (it should have been logged) stop this zone. 00917 * Clean up the files, don't call the signer and move on to the next zone. 00918 */ 00919 log_msg(NULL, LOG_ERR, "KsmRequestKeys returned: %d", status); 00920 00921 /* check for the specific case of not having any keys 00922 TODO check that this code can ever be executed after the restructure */ 00923 if (status == -1) { 00924 status2 = KsmRequestGenerateCount(KSM_TYPE_KSK, &gencnt, zone_id); 00925 if (status2 == 0 && gencnt == 0) { 00926 if(man_key_gen == 1) { 00927 log_msg(NULL, LOG_ERR, "There are no KSKs in the generate state; please use \"ods-ksmutil key generate\" to create some."); 00928 } else { 00929 log_msg(NULL, LOG_WARNING, "There are no KSKs in the generate state; ods-enforcerd will create some on its next run."); 00930 } 00931 } 00932 else if (status2 == 0) { 00933 status2 = KsmRequestGenerateCount(KSM_TYPE_ZSK, &gencnt, zone_id); 00934 if (status2 == 0 && gencnt == 0) { 00935 if(man_key_gen == 1) { 00936 log_msg(NULL, LOG_ERR, "There are no ZSKs in the generate state; please use \"ods-ksmutil key generate\" to create some."); 00937 } else { 00938 log_msg(NULL, LOG_WARNING, "There are no ZSKs in the generate state; ods-enforcerd will create some on its next run."); 00939 } 00940 } 00941 } 00942 else { 00943 log_msg(NULL, LOG_ERR, "KsmRequestGenerateCount returned: %d", status2); 00944 } 00945 } 00946 00947 status = fclose(file); 00948 unlink(temp_filename); 00949 MemFree(datetime); 00950 StrFree(temp_filename); 00951 StrFree(old_filename); 00952 00953 return -2; 00954 } 00955 00956 fprintf(file, "\t\t</Keys>\n"); 00957 00958 fprintf(file, "\n"); 00959 00960 fprintf(file, "\t\t<SOA>\n"); 00961 fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->signer->soattl); 00962 fprintf(file, "\t\t\t<Minimum>PT%dS</Minimum>\n", policy->signer->soamin); 00963 fprintf(file, "\t\t\t<Serial>%s</Serial>\n", KsmKeywordSerialValueToName( policy->signer->serial) ); 00964 fprintf(file, "\t\t</SOA>\n"); 00965 00966 if (strncmp(policy->audit, "NULL", 4) != 0) { 00967 fprintf(file, "\n"); 00968 fprintf(file, "\t\t<Audit />\n"); 00969 fprintf(file, "\n"); 00970 } 00971 00972 fprintf(file, "\t</Zone>\n"); 00973 fprintf(file, "</SignerConfiguration>\n"); 00974 00975 /* Force flush of stream to disc cache and then onto disc proper 00976 * Do we need to do this? It might be significant on ext4 00977 * NOTE though that there may be a significant overhead associated with it 00978 * ALSO, if we do lose power maybe we should disregard any files when we come 00979 * back as we won't know if they are now too old? */ 00980 /* 00981 if (fflush(file) != 0) { 00982 MemFree(datetime); 00983 return -1; 00984 } 00985 00986 if (fsync(fileno(file)) != 0) { 00987 MemFree(datetime); 00988 return -1; 00989 } 00990 */ 00991 00992 status = fclose(file); 00993 MemFree(datetime); 00994 00995 if (status == EOF) /* close failed... do something? */ 00996 { 00997 log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename); 00998 StrFree(temp_filename); 00999 StrFree(old_filename); 01000 return -1; 01001 } 01002 01003 /* compare our temp file with the current one (if it exists) */ 01004 file = fopen(temp_filename, "rb"); 01005 if (file == NULL) 01006 { 01007 /* error */ 01008 log_msg(NULL, LOG_ERR, "Could not reopen: %s", temp_filename); 01009 StrFree(temp_filename); 01010 StrFree(old_filename); 01011 return -1; 01012 } 01013 01014 file2 = fopen(current_filename, "rb"); /* Might not exist */ 01015 01016 /* If current_filename exists then compare its contents to temp_filename */ 01017 if (file2 != NULL) { 01018 same = 1; 01019 while(!feof(file)) { 01020 char1 = fgetc(file); 01021 if(ferror(file)) { 01022 log_msg(NULL, LOG_ERR, "Could not read: %s", temp_filename); 01023 fclose(file); 01024 fclose(file2); 01025 StrFree(temp_filename); 01026 StrFree(old_filename); 01027 return -1; 01028 } 01029 char2 = fgetc(file2); 01030 if(ferror(file2)) { 01031 log_msg(NULL, LOG_ERR, "Could not read: %s", current_filename); 01032 fclose(file); 01033 fclose(file2); 01034 StrFree(temp_filename); 01035 StrFree(old_filename); 01036 return -1; 01037 } 01038 if(char1 != char2) { 01039 same = 0; 01040 break; 01041 } 01042 } 01043 01044 status = fclose(file2); 01045 if (status == EOF) /* close failed... do something? */ 01046 { 01047 log_msg(NULL, LOG_ERR, "Could not close: %s", current_filename); 01048 fclose(file); 01049 StrFree(temp_filename); 01050 StrFree(old_filename); 01051 return -1; 01052 } 01053 } 01054 01055 status = fclose(file); 01056 if (status == EOF) /* close failed... do something? */ 01057 { 01058 log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename); 01059 StrFree(temp_filename); 01060 StrFree(old_filename); 01061 return -1; 01062 } 01063 01064 /* If either current_filename does not exist, or if it is different to temp then same will == 0 */ 01065 01066 if (same == 0) { 01067 01068 /* we now have a complete xml file. First move the old one out of the way */ 01069 status = rename(current_filename, old_filename); 01070 if (status != 0 && status != -1) 01071 { 01072 /* cope with initial condition of files not existing */ 01073 log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", current_filename, old_filename); 01074 StrFree(old_filename); 01075 StrFree(temp_filename); 01076 return -1; 01077 } 01078 01079 /* Then copy our temp into place */ 01080 if (rename(temp_filename, current_filename) != 0) 01081 { 01082 log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", temp_filename, current_filename); 01083 StrFree(old_filename); 01084 StrFree(temp_filename); 01085 return -1; 01086 } 01087 01088 if (*signer_flag == 1) { 01089 /* call the signer engine to tell it that something changed */ 01090 /* TODO for beta version connect straight to the socket 01091 should we make a blocking call on this? 01092 should we call it here or after we have written all of the files? 01093 have timeout if call is blocking */ 01094 signer_command = NULL; 01095 StrAppend(&signer_command, SIGNER_CLI_UPDATE); 01096 StrAppend(&signer_command, " "); 01097 StrAppend(&signer_command, zone_name); 01098 01099 status = system(signer_command); 01100 if (status != 0) 01101 { 01102 log_msg(NULL, LOG_ERR, "Could not call signer engine"); 01103 log_msg(NULL, LOG_INFO, "Will continue: call 'ods-signer update' to manually update zones"); 01104 *signer_flag = 0; 01105 } 01106 01107 StrFree(signer_command); 01108 } 01109 } 01110 else { 01111 log_msg(NULL, LOG_INFO, "No change to: %s", current_filename); 01112 if (remove(temp_filename) != 0) 01113 { 01114 log_msg(NULL, LOG_ERR, "Could not remove: %s", temp_filename); 01115 StrFree(old_filename); 01116 StrFree(temp_filename); 01117 return -1; 01118 } 01119 } 01120 01121 /* If the DS set changed then log/do something about it */ 01122 if (NewDS == 1) { 01123 log_msg(NULL, LOG_INFO, "DSChanged"); 01124 status = NewDSSet(zone_id, zone_name, DSSubmitCmd); 01125 } 01126 01127 StrFree(old_filename); 01128 StrFree(temp_filename); 01129 01130 return 0; 01131 } 01132 01133 /* 01134 * CallBack to print key info in signerConfiguration 01135 */ 01136 01137 int commKeyConfig(void* context, KSM_KEYDATA* key_data) 01138 { 01139 FILE *file = (FILE *)context; 01140 01141 fprintf(file, "\t\t\t<Key>\n"); 01142 fprintf(file, "\t\t\t\t<Flags>%d</Flags>\n", key_data->keytype); 01143 fprintf(file, "\t\t\t\t<Algorithm>%d</Algorithm>\n", key_data->algorithm); 01144 fprintf(file, "\t\t\t\t<Locator>%s</Locator>\n", key_data->location); 01145 01146 if (key_data->keytype == KSM_TYPE_KSK) 01147 { 01148 fprintf(file, "\t\t\t\t<KSK />\n"); 01149 } 01150 if (key_data->keytype == KSM_TYPE_ZSK && key_data->state == KSM_STATE_ACTIVE) 01151 { 01152 fprintf(file, "\t\t\t\t<ZSK />\n"); 01153 } 01154 if ((key_data->state > KSM_STATE_GENERATE && key_data->state < KSM_STATE_DEAD) || key_data->state == KSM_STATE_KEYPUBLISH) 01155 { 01156 fprintf(file, "\t\t\t\t<Publish />\n"); 01157 } 01158 fprintf(file, "\t\t\t</Key>\n"); 01159 fprintf(file, "\n"); 01160 01161 return 0; 01162 } 01163 01164 /* allocateKeysToZone 01165 * 01166 * Description: 01167 * Allocates existing keys to zones 01168 * 01169 * Arguments: 01170 * policy 01171 * policy that the keys were created for 01172 * key_type 01173 * KSK or ZSK 01174 * zone_id 01175 * ID of zone in question 01176 * interval 01177 * time before next run 01178 * zone_name 01179 * just in case we need to log something 01180 * man_key_gen 01181 * lack of keys may be an issue for the user to fix 01182 * int rollover_scheme 01183 * KSK rollover scheme in use 01184 * 01185 * Returns: 01186 * int 01187 * Status return. 0=> Success, non-zero => error. 01188 * 1 == error with input 01189 * 2 == not enough keys to satisfy policy 01190 * 3 == database error 01191 -*/ 01192 01193 01194 int allocateKeysToZone(KSM_POLICY *policy, int key_type, int zone_id, uint16_t interval, const char* zone_name, int man_key_gen, int rollover_scheme) 01195 { 01196 int status = 0; 01197 int keys_needed = 0; 01198 int keys_in_queue = 0; 01199 int keys_pending_retirement = 0; 01200 int new_keys = 0; 01201 int key_pair_id = 0; 01202 int i = 0; 01203 DB_ID ignore = 0; 01204 KSM_PARCOLL collection; /* Parameters collection */ 01205 char* datetime = DtParseDateTimeString("now"); 01206 01207 /* Check datetime in case it came back NULL */ 01208 if (datetime == NULL) { 01209 log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting..."); 01210 exit(1); 01211 } 01212 01213 if (policy == NULL) { 01214 log_msg(NULL, LOG_ERR, "NULL policy sent to allocateKeysToZone"); 01215 StrFree(datetime); 01216 return 1; 01217 } 01218 01219 if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) { 01220 log_msg(NULL, LOG_ERR, "Unknown keytype: %i in allocateKeysToZone", key_type); 01221 StrFree(datetime); 01222 return 1; 01223 } 01224 01225 /* Get list of parameters */ 01226 status = KsmParameterCollection(&collection, policy->id); 01227 if (status != 0) { 01228 StrFree(datetime); 01229 return status; 01230 } 01231 01232 /* Make sure that enough keys are allocated to this zone */ 01233 /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */ 01234 status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1); 01235 if (status != 0) { 01236 log_msg(NULL, LOG_ERR, "Could not predict key requirement for next interval for %s", zone_name); 01237 StrFree(datetime); 01238 return 3; 01239 } 01240 01241 /* How many do we have ? TODO should this include the currently active key?*/ 01242 status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id); 01243 if (status != 0) { 01244 log_msg(NULL, LOG_ERR, "Could not count current key numbers for zone %s", zone_name); 01245 StrFree(datetime); 01246 return 3; 01247 } 01248 01249 /* or about to retire */ 01250 status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval); 01251 if (status != 0) { 01252 log_msg(NULL, LOG_ERR, "Could not count keys which may retire before the next run (for zone %s)", zone_name); 01253 StrFree(datetime); 01254 return 3; 01255 } 01256 01257 StrFree(datetime); 01258 new_keys = keys_needed - (keys_in_queue - keys_pending_retirement); 01259 01260 /* fprintf(stderr, "comm(%d) %s: new_keys(%d) = keys_needed(%d) - (keys_in_queue(%d) - keys_pending_retirement(%d))\n", key_type, zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement); */ 01261 01262 /* Allocate keys */ 01263 for (i=0 ; i < new_keys ; i++){ 01264 key_pair_id = 0; 01265 if (key_type == KSM_TYPE_KSK) { 01266 status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id); 01267 if (status == -1 || key_pair_id == 0) { 01268 if (man_key_gen == 0) { 01269 log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy ksk policy for zone: %s", zone_name); 01270 log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run"); 01271 } 01272 else { 01273 log_msg(NULL, LOG_ERR, "Not enough keys to satisfy ksk policy for zone: %s", zone_name); 01274 log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys."); 01275 } 01276 return 2; 01277 } 01278 else if (status != 0) { 01279 log_msg(NULL, LOG_ERR, "Could not get an unallocated ksk for zone: %s", zone_name); 01280 return 3; 01281 } 01282 } else { 01283 status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id); 01284 if (status == -1 || key_pair_id == 0) { 01285 if (man_key_gen == 0) { 01286 log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy zsk policy for zone: %s", zone_name); 01287 log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run"); 01288 } 01289 else { 01290 log_msg(NULL, LOG_ERR, "Not enough keys to satisfy zsk policy for zone: %s", zone_name); 01291 log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys."); 01292 } 01293 return 2; 01294 } 01295 else if (status != 0) { 01296 log_msg(NULL, LOG_ERR, "Could not get an unallocated zsk for zone: %s", zone_name); 01297 return 3; 01298 } 01299 } 01300 if(key_pair_id > 0) { 01301 status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, &ignore); 01302 /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */ 01303 } else { 01304 /* This shouldn't happen */ 01305 log_msg(NULL, LOG_ERR, "KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name); 01306 exit(1); 01307 } 01308 01309 } 01310 01311 return status; 01312 } 01313 01314 /* 01315 * Read the conf.xml file, extract the location of the zonelist. 01316 */ 01317 int read_zonelist_filename(const char* filename, char** zone_list_filename) 01318 { 01319 xmlTextReaderPtr reader = NULL; 01320 xmlDocPtr doc = NULL; 01321 xmlXPathContextPtr xpathCtx = NULL; 01322 xmlXPathObjectPtr xpathObj = NULL; 01323 int ret = 0; /* status of the XML parsing */ 01324 char* temp_char = NULL; 01325 char* tag_name = NULL; 01326 01327 xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile"; 01328 01329 /* Start reading the file; we will be looking for "Common" tags */ 01330 reader = xmlNewTextReaderFilename(filename); 01331 if (reader != NULL) { 01332 ret = xmlTextReaderRead(reader); 01333 while (ret == 1) { 01334 tag_name = (char*) xmlTextReaderLocalName(reader); 01335 /* Found <Common> */ 01336 if (strncmp(tag_name, "Common", 6) == 0 01337 && xmlTextReaderNodeType(reader) == 1) { 01338 01339 /* Expand this node and get the rest of the info with XPath */ 01340 xmlTextReaderExpand(reader); 01341 doc = xmlTextReaderCurrentDoc(reader); 01342 if (doc == NULL) { 01343 log_msg(NULL, LOG_ERR, "Error: can not read Common section of %s", filename); 01344 /* Don't return? try to parse the rest of the file? */ 01345 ret = xmlTextReaderRead(reader); 01346 continue; 01347 } 01348 01349 xpathCtx = xmlXPathNewContext(doc); 01350 if(xpathCtx == NULL) { 01351 log_msg(NULL, LOG_ERR, "Error: can not create XPath context for Common section"); 01352 /* Don't return? try to parse the rest of the file? */ 01353 ret = xmlTextReaderRead(reader); 01354 continue; 01355 } 01356 01357 /* Evaluate xpath expression for ZoneListFile */ 01358 xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx); 01359 if(xpathObj == NULL) { 01360 log_msg(NULL, LOG_ERR, "Error: unable to evaluate xpath expression: %s", zonelist_expr); 01361 /* Don't return? try to parse the rest of the file? */ 01362 ret = xmlTextReaderRead(reader); 01363 continue; 01364 } 01365 *zone_list_filename = NULL; 01366 temp_char = (char *)xmlXPathCastToString(xpathObj); 01367 StrAppend(zone_list_filename, temp_char); 01368 StrFree(temp_char); 01369 xmlXPathFreeObject(xpathObj); 01370 log_msg(NULL, LOG_INFO, "zonelist filename set to %s.", *zone_list_filename); 01371 } 01372 /* Read the next line */ 01373 ret = xmlTextReaderRead(reader); 01374 StrFree(tag_name); 01375 } 01376 xmlFreeTextReader(reader); 01377 if (ret != 0) { 01378 log_msg(NULL, LOG_ERR, "%s : failed to parse", filename); 01379 return(1); 01380 } 01381 } else { 01382 log_msg(NULL, LOG_ERR, "Unable to open %s", filename); 01383 return(1); 01384 } 01385 if (xpathCtx) { 01386 xmlXPathFreeContext(xpathCtx); 01387 } 01388 if (doc) { 01389 xmlFreeDoc(doc); 01390 } 01391 01392 return 0; 01393 } 01394 01395 /*+ 01396 * do_purge - Purge dead Keys 01397 * 01398 * 01399 * Arguments: 01400 * 01401 * int interval 01402 * how long a key needs to have been dead for before we purge it 01403 * 01404 * int policy_id 01405 * ID of the policy 01406 * 01407 * Returns: 01408 * int 01409 * Status return. 0 on success. 01410 * other on fail 01411 */ 01412 01413 int do_purge(int interval, int policy_id) 01414 { 01415 char* sql = NULL; /* SQL query */ 01416 char* sql1 = NULL; /* SQL query */ 01417 char* sql2 = NULL; /* SQL query */ 01418 char* sql3 = NULL; /* SQL query */ 01419 int status = 0; /* Status return */ 01420 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 01421 DB_RESULT result; /* Result of the query */ 01422 DB_ROW row = NULL; /* Row data */ 01423 01424 char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */ 01425 unsigned int nchar; /* Number of characters converted */ 01426 01427 int temp_id = -1; /* place to store the key id returned */ 01428 char* temp_loc = NULL; /* place to store location returned */ 01429 int count = 0; /* How many keys don't match the purge */ 01430 01431 char *rightnow; 01432 01433 /* Key information */ 01434 hsm_key_t *key = NULL; 01435 01436 log_msg(NULL, LOG_DEBUG, "Purging keys..."); 01437 01438 rightnow = DtParseDateTimeString("now"); 01439 01440 /* Check datetime in case it came back NULL */ 01441 if (rightnow == NULL) { 01442 log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting..."); 01443 exit(1); 01444 } 01445 01446 /* Select rows */ 01447 StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 "); 01448 01449 if (policy_id != -1) { 01450 StrAppend(&sql, "and policy_id = "); 01451 snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id); 01452 StrAppend(&sql, stringval); 01453 } 01454 01455 DusEnd(&sql); 01456 01457 status = DbExecuteSql(DbHandle(), sql, &result); 01458 01459 if (status == 0) { 01460 status = DbFetchRow(result, &row); 01461 while (status == 0) { 01462 /* Got a row, check it */ 01463 DbInt(row, 0, &temp_id); 01464 DbString(row, 1, &temp_loc); 01465 01466 sql1 = DqsCountInit("dnsseckeys"); 01467 DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 01468 DdsConditionInt(&sql1, "(state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1); 01469 01470 #ifdef USE_MYSQL 01471 nchar = snprintf(buffer, sizeof(buffer), 01472 " or state = %d and DEAD > DATE_ADD('%s', INTERVAL -%d SECOND)) ", KSM_STATE_DEAD, rightnow, interval); 01473 #else 01474 nchar = snprintf(buffer, sizeof(buffer), 01475 " or state = %d and DEAD > DATETIME('%s', '-%d SECONDS')) ", KSM_STATE_DEAD, rightnow, interval); 01476 #endif /* USE_MYSQL */ 01477 01478 StrAppend(&sql1, buffer); 01479 DqsEnd(&sql1); 01480 01481 status = DbIntQuery(DbHandle(), &count, sql1); 01482 DqsFree(sql1); 01483 01484 if (status != 0) { 01485 log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle())); 01486 DbStringFree(temp_loc); 01487 DbFreeRow(row); 01488 StrFree(rightnow); 01489 return status; 01490 } 01491 01492 /* If the count is zero then there is no reason not to purge this key */ 01493 if (count == 0) { 01494 01495 /* Delete from dnsseckeys */ 01496 sql2 = DdsInit("dnsseckeys"); 01497 DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0); 01498 DdsEnd(&sql); 01499 01500 status = DbExecuteSqlNoResult(DbHandle(), sql2); 01501 DdsFree(sql2); 01502 if (status != 0) 01503 { 01504 log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle())); 01505 DbStringFree(temp_loc); 01506 DbFreeRow(row); 01507 StrFree(rightnow); 01508 return status; 01509 } 01510 01511 /* Delete from keypairs */ 01512 sql3 = DdsInit("keypairs"); 01513 DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0); 01514 DdsEnd(&sql); 01515 01516 status = DbExecuteSqlNoResult(DbHandle(), sql3); 01517 DdsFree(sql3); 01518 if (status != 0) 01519 { 01520 log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle())); 01521 DbStringFree(temp_loc); 01522 DbFreeRow(row); 01523 StrFree(rightnow); 01524 return status; 01525 } 01526 01527 /* Delete from the HSM */ 01528 key = hsm_find_key_by_id(NULL, temp_loc); 01529 01530 if (!key) { 01531 log_msg(NULL, LOG_ERR, "Key not found: %s\n", temp_loc); 01532 DbStringFree(temp_loc); 01533 DbFreeRow(row); 01534 StrFree(rightnow); 01535 return -1; 01536 } 01537 01538 status = hsm_remove_key(NULL, key); 01539 01540 hsm_key_free(key); 01541 01542 if (!status) { 01543 log_msg(NULL, LOG_INFO, "Key remove successful.\n"); 01544 } else { 01545 log_msg(NULL, LOG_ERR, "Key remove failed.\n"); 01546 DbStringFree(temp_loc); 01547 DbFreeRow(row); 01548 StrFree(rightnow); 01549 return -1; 01550 } 01551 } 01552 01553 /* NEXT! */ 01554 status = DbFetchRow(result, &row); 01555 } 01556 01557 /* Convert EOF status to success */ 01558 01559 if (status == -1) { 01560 status = 0; 01561 } 01562 01563 DbFreeResult(result); 01564 } 01565 01566 DusFree(sql); 01567 DbFreeRow(row); 01568 01569 DbStringFree(temp_loc); 01570 StrFree(rightnow); 01571 01572 return status; 01573 } 01574 01575 int NewDSSet(int zone_id, const char* zone_name, const char* DSSubmitCmd) { 01576 int where = 0; /* for the SELECT statement */ 01577 char* sql = NULL; /* SQL statement (when verifying) */ 01578 char* sql2 = NULL; /* SQL statement (if getting DS) */ 01579 int status = 0; /* Status return */ 01580 int count = 0; /* How many keys fit our select? */ 01581 int i = 0; /* A counter */ 01582 int j = 0; /* Another counter */ 01583 char* insql = NULL; /* SQL "IN" clause */ 01584 int* keyids; /* List of IDs of keys to promote */ 01585 DB_RESULT result; /* List result set */ 01586 KSM_KEYDATA data; /* Data for this key */ 01587 size_t nchar; /* Number of characters written */ 01588 char buffer[256]; /* For constructing part of the command */ 01589 char* count_clause = NULL; 01590 char* where_clause = NULL; 01591 int id = -1; /* ID of key which will retire */ 01592 int active_count = -1; /* Number of currently active keys */ 01593 01594 char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */ 01595 DB_RESULT result3; /* Result of DS query */ 01596 KSM_KEYDATA data3; /* DS information */ 01597 char* ds_buffer = NULL; /* Contents of DS records */ 01598 char* ds_seen_buffer = NULL; /* Which keys have we promoted */ 01599 char* temp_char = NULL; /* Contents of DS records */ 01600 01601 /* Key information */ 01602 hsm_key_t *key = NULL; 01603 ldns_rr *dnskey_rr = NULL; 01604 hsm_sign_params_t *sign_params = NULL; 01605 01606 FILE *fp; 01607 int bytes_written = -1; 01608 01609 nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d, %d, %d)", 01610 KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE, 01611 KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY, 01612 KSM_STATE_KEYPUBLISH, KSM_STATE_RETIRE); 01613 if (nchar >= sizeof(buffer)) { 01614 status = -1; 01615 return status; 01616 } 01617 01618 /* Find the oldest active key, this is the one which will be retired 01619 NOTE; this may not match any keys */ 01620 01621 count_clause = DqsCountInit("KEYDATA_VIEW"); 01622 DqsConditionInt(&count_clause, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++); 01623 DqsConditionInt(&count_clause, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++); 01624 if (zone_id != -1) { 01625 DqsConditionInt(&count_clause, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 01626 } 01627 01628 status = DbIntQuery(DbHandle(), &active_count, count_clause); 01629 StrFree(count_clause); 01630 if (status != 0) 01631 { 01632 log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n"); 01633 return status; 01634 } 01635 01636 if (active_count > 0) { 01637 01638 snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id); 01639 StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = "); 01640 StrAppend(&where_clause, stringval); 01641 StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = "); 01642 StrAppend(&where_clause, stringval); 01643 StrAppend(&where_clause, ")"); 01644 01645 /* Execute query and free up the query string */ 01646 status = DbIntQuery(DbHandle(), &id, where_clause); 01647 StrFree(where_clause); 01648 if (status != 0) 01649 { 01650 log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n"); 01651 return status; 01652 } 01653 } 01654 01655 /* First up we need to count how many DSs we will have */ 01656 where = 0; 01657 sql = DqsCountInit("KEYDATA_VIEW"); 01658 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++); 01659 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++); 01660 if (zone_id != -1) { 01661 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 01662 } 01663 if (id != -1) { 01664 DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++); 01665 } 01666 DqsEnd(&sql); 01667 01668 status = DbIntQuery(DbHandle(), &count, sql); 01669 DqsFree(sql); 01670 01671 if (status != 0) { 01672 /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/ 01673 return status; 01674 } 01675 01676 if (count == 0) { 01677 /* No KSKs in zone? */ 01678 return status; 01679 } 01680 01681 /* Allocate space for the list of key IDs */ 01682 keyids = MemMalloc(count * sizeof(int)); 01683 01684 /* Get the list of IDs */ 01685 01686 where = 0; 01687 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 01688 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++); 01689 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++); 01690 if (zone_id != -1) { 01691 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++); 01692 } 01693 if (id != -1) { 01694 DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++); 01695 } 01696 DqsEnd(&sql); 01697 01698 status = KsmKeyInitSql(&result, sql); 01699 DqsFree(sql); 01700 01701 if (status == 0) { 01702 while (status == 0) { 01703 status = KsmKey(result, &data); 01704 if (status == 0) { 01705 keyids[i] = data.keypair_id; 01706 i++; 01707 } 01708 } 01709 01710 /* Convert EOF status to success */ 01711 01712 if (status == -1) { 01713 status = 0; 01714 } else { 01715 /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/ 01716 StrFree(keyids); 01717 return status; 01718 } 01719 01720 KsmKeyEnd(result); 01721 01722 } else { 01723 /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/ 01724 StrFree(keyids); 01725 return status; 01726 } 01727 01728 /* 01729 * Now construct the "IN" statement listing the IDs of the keys we 01730 * are planning to change the state of. 01731 */ 01732 01733 StrAppend(&insql, "("); 01734 for (j = 0; j < i; ++j) { 01735 if (j != 0) { 01736 StrAppend(&insql, ","); 01737 } 01738 snprintf(buffer, sizeof(buffer), "%d", keyids[j]); 01739 StrAppend(&insql, buffer); 01740 } 01741 StrAppend(&insql, ")"); 01742 01743 StrFree(keyids); 01744 01745 /* Indicate that the DS record should now be submitted */ 01746 sql2 = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 01747 DqsConditionKeyword(&sql2, "ID", DQS_COMPARE_IN, insql, 0); 01748 DqsConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1); 01749 DqsEnd(&sql2); 01750 01751 log_msg(NULL, LOG_INFO, "DS Record set has changed, the current set looks like:"); 01752 01753 status = KsmKeyInitSql(&result3, sql2); 01754 DqsFree(sql2); 01755 if (status == 0) { 01756 status = KsmKey(result3, &data3); 01757 while (status == 0) { 01758 01759 /* Code to output the DNSKEY record (stolen from hsmutil) */ 01760 key = hsm_find_key_by_id(NULL, data3.location); 01761 01762 if (!key) { 01763 log_msg(NULL, LOG_ERR, "Key %s in DB but not repository.", data3.location); 01764 StrFree(insql); 01765 return status; 01766 } 01767 01768 StrAppend(&ds_seen_buffer, ", "); 01769 StrAppend(&ds_seen_buffer, data3.location); 01770 01771 sign_params = hsm_sign_params_new(); 01772 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name); 01773 sign_params->algorithm = data3.algorithm; 01774 sign_params->flags = LDNS_KEY_ZONE_KEY; 01775 sign_params->flags += LDNS_KEY_SEP_KEY; 01776 dnskey_rr = hsm_get_dnskey(NULL, key, sign_params); 01777 01778 temp_char = ldns_rr2str(dnskey_rr); 01779 ldns_rr_free(dnskey_rr); 01780 01781 /* Replace tab with white-space */ 01782 for (i = 0; temp_char[i]; ++i) { 01783 if (temp_char[i] == '\t') { 01784 temp_char[i] = ' '; 01785 } 01786 } 01787 log_msg(NULL, LOG_INFO, "%s", temp_char); 01788 01789 /* We need to strip off trailing comments before we send 01790 to any clients that might be listening */ 01791 for (i = 0; temp_char[i]; ++i) { 01792 if (temp_char[i] == ';') { 01793 temp_char[i] = '\n'; 01794 temp_char[i+1] = '\0'; 01795 break; 01796 } 01797 } 01798 StrAppend(&ds_buffer, temp_char); 01799 StrFree(temp_char); 01800 01801 /* StrAppend(&ds_buffer, "\n;KSK DS record (SHA1):\n"); 01802 ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1); 01803 temp_char = ldns_rr2str(ds_sha1_rr); 01804 StrAppend(&ds_buffer, temp_char); 01805 StrFree(temp_char); 01806 01807 StrAppend(&ds_buffer, "\n;KSK DS record (SHA256):\n"); 01808 ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256); 01809 temp_char = ldns_rr2str(ds_sha256_rr); 01810 StrAppend(&ds_buffer, temp_char); 01811 StrFree(temp_char); 01812 */ 01813 01814 hsm_sign_params_free(sign_params); 01815 hsm_key_free(key); 01816 status = KsmKey(result3, &data3); 01817 } 01818 /* Convert EOF status to success */ 01819 if (status == -1) { 01820 status = 0; 01821 } 01822 01823 KsmKeyEnd(result3); 01824 } 01825 01826 if (DSSubmitCmd[0] != '\0') { 01827 /* send records to the configured command */ 01828 fp = popen(DSSubmitCmd, "w"); 01829 if (fp == NULL) { 01830 log_msg(NULL, LOG_ERR, "Failed to run command: %s: %s", DSSubmitCmd, strerror(errno)); 01831 return -1; 01832 } 01833 bytes_written = fprintf(fp, "%s", ds_buffer); 01834 if (bytes_written < 0) { 01835 log_msg(NULL, LOG_ERR, "Failed to write to %s: %s", DSSubmitCmd, strerror(errno)); 01836 return -1; 01837 } 01838 01839 if (pclose(fp) == -1) { 01840 log_msg(NULL, LOG_ERR, "Failed to close %s: %s", DSSubmitCmd, strerror(errno)); 01841 return -1; 01842 } 01843 } 01844 01845 StrFree(ds_buffer); 01846 01847 log_msg(NULL, LOG_INFO, "Once the new DS records are seen in DNS please issue the ds-seen command for zone %s with the following cka_ids%s", zone_name, ds_seen_buffer); 01848 01849 StrFree(ds_seen_buffer); 01850 01851 StrFree(insql); 01852 01853 return status; 01854 }