OpenDNSSEC-enforcer  1.3.8
/build/buildd/opendnssec-1.3.8/enforcer/enforcerd/enforcer.c
Go to the documentation of this file.
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(&current_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(&current_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