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