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