OpenDNSSEC-enforcer  1.3.4
/build/buildd/opendnssec-1.3.4/enforcer/utils/ksmutil.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ksmutil.c 5838 2011-11-08 14:28:05Z sion $
00003  *
00004  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00016  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
00019  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00020  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00021  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
00023  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00024  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00025  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026  */
00027 
00028 #define _GNU_SOURCE
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <stdlib.h>
00032 #include <unistd.h>
00033 #include <errno.h>
00034 #include <fcntl.h>
00035 #include <limits.h>
00036 
00037 #include "config.h"
00038 
00039 #include <getopt.h>
00040 #include <string.h>
00041 #include <syslog.h>
00042 #include <sys/stat.h>
00043 #include <pwd.h>
00044 #include <grp.h>
00045 
00046 #include <ksm/ksmutil.h>
00047 #include <ksm/ksm.h>
00048 #include <ksm/database.h>
00049 #include "ksm/database_statement.h"
00050 #include "ksm/db_fields.h"
00051 #include <ksm/datetime.h>
00052 #include <ksm/string_util.h>
00053 #include <ksm/string_util2.h>
00054 #include "ksm/kmemsg.h"
00055 #include "ksm/kmedef.h"
00056 #include "ksm/dbsmsg.h"
00057 #include "ksm/dbsdef.h"
00058 #include "ksm/message.h"
00059 
00060 #include <libhsm.h>
00061 #include <libhsmdns.h>
00062 #include <ldns/ldns.h>
00063 
00064 #include <libxml/tree.h>
00065 #include <libxml/parser.h>
00066 #include <libxml/xpointer.h>
00067 #include <libxml/xpath.h>
00068 #include <libxml/xpathInternals.h>
00069 #include <libxml/relaxng.h>
00070 #include <libxml/xmlreader.h>
00071 #include <libxml/xmlsave.h>
00072 
00073 #define MAX(a, b) ((a) > (b) ? (a) : (b))
00074 
00075 /* Some value type flags */
00076 #define INT_TYPE 0
00077 #define DURATION_TYPE 1
00078 #define BOOL_TYPE 2
00079 #define REPO_TYPE 3
00080 #define SERIAL_TYPE 4
00081 #define ROLLOVER_TYPE 5
00082 #define INT_TYPE_NO_FREE 6
00083 
00084 #ifndef MAXPATHLEN
00085 # define MAXPATHLEN 4096
00086 #endif
00087 
00088 /* We write one log message to syslog */
00089 #ifdef LOG_DAEMON
00090 #define DEFAULT_LOG_FACILITY LOG_DAEMON
00091 #else
00092 #define DEFAULT_LOG_FACILITY LOG_USER
00093 #endif /* LOG_DAEMON */
00094 
00095 extern char *optarg;
00096 extern int optind;
00097 const char *progname = NULL;
00098 char *config = (char *) OPENDNSSEC_CONFIG_FILE;
00099 
00100 char *o_keystate = NULL;
00101 char *o_algo = NULL;
00102 char *o_input = NULL;
00103 char *o_cka_id = NULL;
00104 char *o_size = NULL;
00105 char *o_interval = NULL;
00106 char *o_output = NULL;
00107 char *o_policy = NULL;
00108 char *o_repository = NULL;
00109 char *o_signerconf = NULL;
00110 char *o_keytype = NULL;
00111 char *o_time = NULL;
00112 char *o_retire = NULL;
00113 char *o_zone = NULL;
00114 char *o_keytag = NULL;
00115 static int all_flag = 0;
00116 static int ds_flag = 0;
00117 static int retire_flag = 1;
00118 static int verbose_flag = 0;
00119 static int xml_flag = 1;
00120 static int td_flag = 0;
00121 
00122 static int restart_enforcerd(void);
00123 
00124     void
00125 usage_general ()
00126 {
00127     fprintf(stderr,
00128             "  help\n"
00129             "  --version                                      aka -V\n");
00130 }
00131 
00132     void
00133 usage_setup ()
00134 {
00135     fprintf(stderr,
00136             "  setup\n"
00137             "\tImport config into a database (deletes current contents)\n");
00138 }
00139 
00140     void
00141 usage_control ()
00142 {
00143     fprintf(stderr,
00144             "  start|stop|notify\n"
00145             "\tStart, stop or SIGHUP the ods-enforcerd\n");
00146 }
00147 
00148     void
00149 usage_update ()
00150 {
00151     fprintf(stderr,
00152             "  update kasp\n"
00153             "  update zonelist\n"
00154             "  update conf\n"
00155             "  update all\n"
00156             "\tUpdate database from config\n");
00157 }
00158 
00159     void
00160 usage_zoneadd ()
00161 {
00162     fprintf(stderr,
00163             "  zone add\n"
00164             "\t--zone <zone>                            aka -z\n"
00165             "\t[--policy <policy>]                      aka -p\n"
00166             "\t[--signerconf <signerconf.xml>]          aka -s\n"
00167             "\t[--input <input>]                        aka -i\n"
00168             "\t[--output <output>]                      aka -o\n"
00169             "\t[--no-xml]                               aka -m\n");
00170 }
00171 
00172     void
00173 usage_zonedel ()
00174 {
00175     fprintf(stderr,
00176             "  zone delete\n"
00177             "\t--zone <zone> | --all                    aka -z / -a\n"
00178             "\t[--no-xml]                               aka -m\n");
00179 }
00180 
00181     void
00182 usage_zonelist ()
00183 {
00184     fprintf(stderr,
00185             "  zone list\n");
00186 }
00187 
00188     void
00189 usage_zone ()
00190 {
00191     fprintf(stderr,
00192             "usage: %s [-f config] zone \n\n",
00193             progname);
00194     usage_zoneadd ();
00195     usage_zonedel ();
00196     usage_zonelist ();
00197 }
00198 
00199     void
00200 usage_repo ()
00201 {
00202     fprintf(stderr,
00203             "  repository list\n");
00204 }
00205 
00206     void
00207 usage_policyexport ()
00208 {
00209     fprintf(stderr,
00210             "  policy export\n"
00211             "\t--policy [policy_name] | --all           aka -p / -a\n");
00212 }
00213 
00214     void
00215 usage_policyimport ()
00216 {
00217     fprintf(stderr,
00218             "  policy import\n");
00219 }
00220 
00221     void
00222 usage_policylist ()
00223 {
00224     fprintf(stderr,
00225             "  policy list\n");
00226 }
00227 
00228     void
00229 usage_policypurge ()
00230 {
00231     fprintf(stderr,
00232             "  policy purge\n");
00233 }
00234 
00235     void
00236 usage_policy ()
00237 {
00238     fprintf(stderr,
00239             "usage: %s [-f config] \n\n",
00240             progname);
00241     usage_policyexport ();
00242     usage_policyimport ();
00243     usage_policylist ();
00244     usage_policypurge ();
00245 }
00246 
00247     void
00248 usage_keylist ()
00249 {
00250     fprintf(stderr,
00251             "  key list\n"
00252             "\t[--verbose]\n"
00253             "\t--zone <zone> | --all                    aka -z / -a\n"
00254 #if 0
00255             "\t(will appear soon:\n"
00256             "\t[--keystate <state>]                     aka -e\n"
00257             "\t[--keytype <type>]                       aka -t\n"
00258             "\t[--ds]                                   aka -d)\n"
00259 #endif
00260     );
00261 }
00262 
00263     void
00264 usage_keyexport ()
00265 {
00266     fprintf(stderr,
00267             "  key export\n"
00268             "\t--zone <zone> | --all                    aka -z / -a\n"
00269             "\t[--keystate <state>]                     aka -e\n"
00270             "\t[--keytype <type>]                       aka -t\n"
00271             "\t[--ds]                                   aka -d\n");
00272 }
00273 
00274     void
00275 usage_keyimport ()
00276 {
00277     fprintf(stderr,
00278             "  key import\n"
00279             "\t--cka_id <CKA_ID>                        aka -k\n"
00280             "\t--repository <repository>                aka -r\n"
00281             "\t--zone <zone>                            aka -z\n"
00282             "\t--bits <size>                            aka -b\n"
00283             "\t--algorithm <algorithm>                  aka -g\n"
00284             "\t--keystate <state>                       aka -e\n"
00285             "\t--keytype <type>                         aka -t\n"
00286             "\t--time <time>                            aka -w\n"
00287             "\t[--retire <retire>]                      aka -y\n");
00288 }
00289 
00290     void
00291 usage_keyroll ()
00292 {
00293     fprintf(stderr,
00294             "  key rollover\n"
00295             "\t--zone zone [--keytype <type>]           aka -z\n"
00296             "  key rollover\n"
00297             "\t--policy policy [--keytype <type>]       aka -p\n");
00298 }
00299 
00300     void
00301 usage_keypurge ()
00302 {
00303     fprintf(stderr,
00304             "  key purge\n"
00305             "\t--zone <zone>                            aka -z\n"
00306             "  key purge\n"
00307             "\t--policy <policy>                        aka -p\n");
00308 }
00309 
00310     void
00311 usage_keygen ()
00312 {
00313     fprintf(stderr,
00314             "  key generate\n"
00315                     "\t--policy <policy>\n"
00316             "\t--interval <interval>\n");
00317 }
00318 
00319     void
00320 usage_keykskretire ()
00321 {
00322     fprintf(stderr,
00323             "  key ksk-retire\n"
00324             "\t--zone <zone>                            aka -z\n"
00325             "\t--keytag <keytag> | --cka_id <CKA_ID>    aka -x / -k\n");
00326 }
00327 
00328     void
00329 usage_keydsseen ()
00330 {
00331     fprintf(stderr,
00332             "  key ds-seen\n"
00333             /*"\t--zone <zone> (or --all)                 aka -z\n"*/
00334             "\t--zone <zone>                            aka -z\n"
00335             "\t--keytag <keytag> | --cka_id <CKA_ID>    aka -x / -k\n"
00336             "\t--no-retire\n");
00337 }
00338 
00339     void
00340 usage_key ()
00341 {
00342     fprintf(stderr,
00343             "usage: %s [-f config] \n\n",
00344             progname);
00345     usage_keylist ();
00346     usage_keyexport ();
00347     usage_keyimport ();
00348     usage_keyroll ();
00349     usage_keypurge ();
00350     usage_keygen ();
00351     usage_keykskretire ();
00352     usage_keydsseen ();
00353 }
00354 
00355     void
00356 usage_backup ()
00357 {
00358     fprintf(stderr,
00359             "  backup prepare\n"
00360             "\t--repository <repository>                aka -r\n"
00361             "  backup commit\n"
00362             "\t--repository <repository>                aka -r\n"
00363             "  backup rollback\n"
00364             "\t--repository <repository>                aka -r\n"
00365             "  backup list\n"
00366             "\t--repository <repository>                aka -r\n"
00367             "  backup done\n"
00368             "\t--repository <repository>                aka -r\n");
00369 }
00370 
00371     void
00372 usage_rollover ()
00373 {
00374     fprintf(stderr,
00375             "  rollover list\n"
00376             "\t[--zone <zone>]\n");
00377 }
00378 
00379     void
00380 usage_database ()
00381 {
00382     fprintf(stderr,
00383             "  database backup\n"
00384             "\t[--output <output>]                      aka -o\n");
00385 }
00386 
00387     void
00388 usage_zonelist2 ()
00389 {
00390         fprintf(stderr,
00391             "  zonelist export\n"
00392             "  zonelist import\n");
00393 }
00394 
00395     void
00396 usage ()
00397 {
00398     fprintf(stderr,
00399             "usage: %s [-f config] command [options]\n\n",
00400             progname);
00401 
00402     usage_general ();
00403     usage_setup ();
00404     usage_control ();
00405     usage_update ();
00406     usage_zoneadd ();
00407     usage_zonedel ();
00408     usage_zonelist ();
00409     usage_repo ();
00410     usage_policyexport ();
00411     usage_policylist ();
00412     usage_policypurge ();
00413     usage_keylist ();
00414     usage_keyexport ();
00415     usage_keyimport ();
00416     usage_keyroll ();
00417     usage_keypurge ();
00418     usage_keygen ();
00419     usage_keykskretire ();
00420     usage_keydsseen ();
00421     usage_backup ();
00422     usage_rollover ();
00423     usage_database ();
00424     usage_zonelist2 ();
00425 
00426 }
00427 
00428     void
00429 date_help()
00430 {
00431     fprintf(stderr,
00432         "\n\tAllowed date/time strings are of the form:\n"
00433  
00434         "\tYYYYMMDD[HH[MM[SS]]]                (all numeric)\n"
00435         "\n" 
00436         "\tor  D-MMM-YYYY[:| ]HH[:MM[:SS]]     (alphabetic  month)\n"
00437         "\tor  DD-MMM-YYYY[:| ]HH[:MM[:SS]]    (alphabetic  month)\n"
00438         "\tor  YYYY-MMM-DD[:| ]HH[:MM[:SS]]    (alphabetic month)\n"
00439         "\n" 
00440         "\tD-MM-YYYY[:| ]HH[:MM[:SS]]          (numeric month)\n"
00441         "\tDD-MM-YYYY[:| ]HH[:MM[:SS]]         (numeric month)\n"
00442         "\tor  YYYY-MM-DD[:| ]HH[:MM[:SS]]     (numeric month)\n"
00443         "\n" 
00444         "\t... and the distinction between them is given by the location of the\n"
00445         "\thyphens.\n");
00446 }
00447 
00448 void
00449 states_help()
00450 {
00451     fprintf(stderr,
00452             "key states: GENERATE|PUBLISH|READY|ACTIVE|RETIRE|DEAD\n");
00453 }
00454 
00455 void
00456 types_help()
00457 {
00458     fprintf(stderr,
00459             "key types:  KSK|ZSK\n");
00460 }
00461 
00462 /* 
00463  * Do initial import of config files into database
00464  */
00465     int
00466 cmd_setup ()
00467 {
00468     DB_HANDLE   dbhandle;
00469     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
00470     char* zone_list_filename;   /* Extracted from conf.xml */
00471     char* kasp_filename;    /* Extracted from conf.xml */
00472     int status = 0;
00473 
00474     /* Database connection details */
00475     char *dbschema = NULL;
00476     char *host = NULL;
00477     char *port = NULL;
00478     char *user = NULL;
00479     char *password = NULL;
00480 
00481         char quoted_user[KSM_NAME_LENGTH];
00482         char quoted_password[KSM_NAME_LENGTH];
00483 
00484     char* setup_command = NULL;
00485     char* lock_filename = NULL;
00486 
00487     int user_certain;
00488     printf("*WARNING* This will erase all data in the database; are you sure? [y/N] ");
00489 
00490     user_certain = getchar();
00491     if (user_certain != 'y' && user_certain != 'Y') {
00492         printf("Okay, quitting...\n");
00493         exit(0);
00494     }
00495 
00496     /* Right then, they asked for it */
00497 
00498     /* Read the database details out of conf.xml */
00499     status = get_db_details(&dbschema, &host, &port, &user, &password);
00500     if (status != 0) {
00501         StrFree(host);
00502         StrFree(port);
00503         StrFree(dbschema);
00504         StrFree(user);
00505         StrFree(password);
00506         return(status);
00507     }
00508 
00509     /* If we are in sqlite mode then take a lock out on a file to
00510        prevent multiple access (not sure that we can be sure that sqlite is
00511        safe for multiple processes to access). */
00512     if (DbFlavour() == SQLITE_DB) {
00513 
00514         /* Make sure that nothing is happening to the DB */
00515         StrAppend(&lock_filename, dbschema);
00516         StrAppend(&lock_filename, ".our_lock");
00517 
00518         lock_fd = fopen(lock_filename, "w");
00519         status = get_lite_lock(lock_filename, lock_fd);
00520         if (status != 0) {
00521             printf("Error getting db lock\n");
00522             if (lock_fd != NULL) {
00523                 fclose(lock_fd);
00524             }
00525             StrFree(lock_filename);
00526             StrFree(host);
00527             StrFree(port);
00528             StrFree(dbschema);
00529             StrFree(user);
00530             StrFree(password);
00531             return(1);
00532         }
00533         StrFree(lock_filename);
00534 
00535         /* Run the setup script */
00536         /* will look like: <SQL_BIN> <DBSCHEMA> < <SQL_SETUP> */
00537         StrAppend(&setup_command, SQL_BIN);
00538         StrAppend(&setup_command, " ");
00539         StrAppend(&setup_command, dbschema);
00540         StrAppend(&setup_command, " < ");
00541         StrAppend(&setup_command, SQL_SETUP);
00542 
00543         if (system(setup_command) != 0)
00544         {
00545             printf("Could not call db setup command:\n\t%s\n", setup_command);
00546             db_disconnect(lock_fd);
00547             StrFree(host);
00548             StrFree(port);
00549             StrFree(dbschema);
00550             StrFree(user);
00551             StrFree(password);
00552             StrFree(setup_command);
00553             return(1);
00554         }
00555         StrFree(setup_command);
00556 
00557         /* If we are running as root then chmod the file so that the 
00558            final user/group can access it. */
00559         if (fix_file_perms(dbschema) != 0)
00560         {
00561             printf("Couldn't fix permissions on file %s\n", dbschema);
00562             printf("Will coninue with setup, but you may need to manually change ownership\n");
00563         }
00564     }
00565     else {
00566         /* MySQL setup */
00567         /* will look like: <SQL_BIN> -u <USER> -h <HOST> -P <PORT> -p<PASSWORD> <DBSCHEMA> < <SQL_SETUP> */
00568 
00569                 /* Get a quoted version of the username */
00570                 status = ShellQuoteString(user, quoted_user, KSM_NAME_LENGTH);
00571                 if (status != 0) {
00572                         printf("Failed to connect to database, username too long.\n");
00573                         db_disconnect(lock_fd);
00574                         StrFree(host);
00575                         StrFree(port);
00576                         StrFree(dbschema);
00577                         StrFree(user);
00578                         StrFree(password);
00579                         return(1);
00580                 }
00581 
00582                 /* Get a quoted version of the password */
00583                 status = ShellQuoteString(password, quoted_password, KSM_NAME_LENGTH);
00584                 if (status != 0) {
00585                         printf("Failed to connect to database, password too long.\n");
00586                         db_disconnect(lock_fd);
00587                         StrFree(host);
00588                         StrFree(port);
00589                         StrFree(dbschema);
00590                         StrFree(user);
00591                         StrFree(password);
00592                         return(1);
00593                 }
00594 
00595         StrAppend(&setup_command, SQL_BIN);
00596         StrAppend(&setup_command, " -u '");
00597         StrAppend(&setup_command, quoted_user);
00598                 StrAppend(&setup_command, "'");
00599         if (host != NULL) {
00600             StrAppend(&setup_command, " -h ");
00601             StrAppend(&setup_command, host);
00602             if (port != NULL) {
00603                 StrAppend(&setup_command, " -P ");
00604                 StrAppend(&setup_command, port);
00605             }
00606         }
00607         if (password != NULL) {
00608             StrAppend(&setup_command, " -p'");
00609             StrAppend(&setup_command, quoted_password);
00610                         StrAppend(&setup_command, "'");
00611         }
00612         StrAppend(&setup_command, " ");
00613         StrAppend(&setup_command, dbschema);
00614         StrAppend(&setup_command, " < ");
00615         StrAppend(&setup_command, SQL_SETUP);
00616 
00617         if (system(setup_command) != 0)
00618         {
00619             printf("Could not call db setup command:\n\t%s\n", setup_command);
00620             StrFree(host);
00621             StrFree(port);
00622             StrFree(dbschema);
00623             StrFree(user);
00624             StrFree(password);
00625             StrFree(setup_command);
00626             return(1);
00627         }
00628         StrFree(setup_command);
00629     }
00630 
00631     /* try to connect to the database */
00632     status = DbConnect(&dbhandle, dbschema, host, password, user, port);
00633     if (status != 0) {
00634         printf("Failed to connect to database\n");
00635         db_disconnect(lock_fd);
00636         StrFree(host);
00637         StrFree(port);
00638         StrFree(dbschema);
00639         StrFree(user);
00640         StrFree(password);
00641         return(1);
00642     }
00643 
00644     /* Free these up early */
00645     StrFree(host);
00646     StrFree(port);
00647     StrFree(dbschema);
00648     StrFree(user);
00649     StrFree(password);
00650 
00651     /* 
00652      *  Now we will read the conf.xml file again, but this time we will not validate.
00653      *  Instead we just learn the location of the zonelist.xml and kasp.xml files.
00654      */
00655     status = read_filenames(&zone_list_filename, &kasp_filename);
00656     if (status != 0) {
00657         printf("Failed to read conf.xml\n");
00658         db_disconnect(lock_fd);
00659         return(1);
00660     }
00661 
00662     /* 
00663      *  Now we will read the conf.xml file again, but this time we will not validate.
00664      *  Instead we just extract the RepositoryList into the database
00665      */
00666     status = update_repositories();
00667     if (status != 0) {
00668         printf("Failed to update repositories\n");
00669         db_disconnect(lock_fd);
00670         StrFree(zone_list_filename);
00671         return(1);
00672     }
00673 
00674     /*
00675      * Now read the kasp.xml which should be in the same directory.
00676      * This lists all of the policies.
00677      */
00678     status = update_policies(kasp_filename);
00679     if (status != 0) {
00680         printf("Failed to update policies\n");
00681         printf("SETUP FAILED\n");
00682         db_disconnect(lock_fd);
00683         StrFree(zone_list_filename);
00684         return(1);
00685     }
00686 
00687     StrFree(kasp_filename);
00688 
00689     /*
00690      * Take the zonelist we learnt above and read it, updating or inserting zone
00691      * records in the database as we go.
00692      */
00693     status = update_zones(zone_list_filename);
00694     StrFree(zone_list_filename);
00695     if (status != 0) {
00696         printf("Failed to update zones\n");
00697         db_disconnect(lock_fd);
00698         return(1);
00699     }
00700 
00701     /* Release sqlite lock file (if we have it) */
00702     db_disconnect(lock_fd);
00703 
00704     DbDisconnect(dbhandle);
00705 
00706     return 0;
00707 }
00708 
00709 /*
00710  * Do incremental update of config files into database
00711  *
00712  * returns 0 on success
00713  *         1 on error (and will have sent a message to stdout)
00714  */
00715     int
00716 cmd_update (const char* qualifier)
00717 {
00718     DB_HANDLE   dbhandle;
00719     FILE* lock_fd = NULL;  /* This is the lock file descriptor for a SQLite DB */
00720     char* zone_list_filename = NULL;    /* Extracted from conf.xml */
00721     char* kasp_filename = NULL;         /* Extracted from conf.xml */
00722     int status = 0;
00723     int done_something = 0;
00724 
00725     /* try to connect to the database */
00726     status = db_connect(&dbhandle, &lock_fd, 1);
00727     if (status != 0) {
00728         printf("Failed to connect to database\n");
00729         db_disconnect(lock_fd);
00730         return(1);
00731     }
00732 
00733     /* 
00734      *  Now we will read the conf.xml file again, but this time we will not validate.
00735      *  Instead we just learn the location of the zonelist.xml and kasp.xml files.
00736      */
00737     if (strncmp(qualifier, "ZONELIST", 8) == 0 ||
00738             strncmp(qualifier, "KASP", 4) == 0 ||
00739             strncmp(qualifier, "ALL", 3) == 0) {
00740         status = read_filenames(&zone_list_filename, &kasp_filename);
00741         if (status != 0) {
00742             printf("Failed to read conf.xml\n");
00743             db_disconnect(lock_fd);
00744             return(1);
00745         }
00746     }
00747 
00748     /* 
00749      *  Read the conf.xml file yet again, but this time we will not validate.
00750      *  Instead we just extract the RepositoryList into the database.
00751      */
00752     if (strncmp(qualifier, "CONF", 4) == 0 ||
00753             strncmp(qualifier, "ALL", 3) == 0) {
00754         status = update_repositories();
00755         if (status != 0) {
00756             printf("Failed to update repositories\n");
00757             db_disconnect(lock_fd);
00758             if (strncmp(qualifier, "ALL", 3) == 0) {
00759                 StrFree(kasp_filename);
00760                 StrFree(zone_list_filename);
00761             }
00762             return(1);
00763         }
00764         done_something = 1;
00765     }
00766 
00767     /*
00768      * Now read the kasp.xml which should be in the same directory.
00769      * This lists all of the policies.
00770      */
00771     if (strncmp(qualifier, "KASP", 4) == 0 ||
00772             strncmp(qualifier, "ALL", 3) == 0) {
00773         status = update_policies(kasp_filename);
00774         if (status != 0) {
00775             printf("Failed to update policies\n");
00776             db_disconnect(lock_fd);
00777             StrFree(kasp_filename);
00778             StrFree(zone_list_filename);
00779             return(1);
00780         }
00781         done_something = 1;
00782     }
00783 
00784     /*
00785      * Take the zonelist we learnt above and read it, updating or inserting zone
00786      * records in the database as we go.
00787      */
00788     if (strncmp(qualifier, "ZONELIST", 8) == 0 ||
00789             strncmp(qualifier, "ALL", 3) == 0) {
00790         status = update_zones(zone_list_filename);
00791         if (status != 0) {
00792             printf("Failed to update zones\n");
00793             db_disconnect(lock_fd);
00794             StrFree(kasp_filename);
00795             StrFree(zone_list_filename);
00796             return(1);
00797         }
00798         done_something = 1;
00799     }
00800 
00801     /*
00802      * See if we did anything, otherwise log an error
00803      */
00804     if (done_something == 0) {
00805         printf("Unrecognised command update %s. Please specify one of:\n", qualifier);
00806                 usage_update();
00807         } else {
00808                 /* Need to poke the enforcer to wake it up */
00809                 if (restart_enforcerd() != 0)
00810                 {
00811                         fprintf(stderr, "Could not HUP ods-enforcerd\n");
00812                 }
00813         }
00814 
00815 
00816     /* Release sqlite lock file (if we have it) */
00817     db_disconnect(lock_fd);
00818 
00819     DbDisconnect(dbhandle);
00820 
00821     if (kasp_filename != NULL) {
00822         StrFree(kasp_filename);
00823     }
00824     if (zone_list_filename != NULL) {
00825         StrFree(zone_list_filename);
00826     }
00827 
00828     return 0;
00829 }
00830 
00831 /* 
00832  * Add a zone to the config and database.
00833  *
00834  * Use XMLwriter to update the zonelist.xml found in conf.xml.
00835  * Then call update_zones to push these changes into the database.
00836  * zonelist.xml will be backed up, as will the DB file if we are using sqlite
00837  *
00838  */
00839     int
00840 cmd_addzone ()
00841 {
00842     DB_HANDLE   dbhandle;
00843     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
00844     char* zonelist_filename = NULL;
00845     char* backup_filename = NULL;
00846     /* The settings that we need for the zone */
00847     char* sig_conf_name = NULL;
00848     char* input_name = NULL;
00849     char* output_name = NULL;
00850     int policy_id = 0;
00851     int new_zone;   /* ignored */
00852 
00853     DB_RESULT      result;         /* Result of parameter query */
00854     KSM_PARAMETER   data;           /* Parameter information */
00855 
00856     xmlDocPtr doc = NULL;
00857 
00858     int status = 0;
00859 
00860     char *path = getcwd(NULL, MAXPATHLEN);
00861     if (path == NULL) {
00862         printf("Couldn't malloc path: %s\n", strerror(errno));
00863         exit(1);
00864     }
00865 
00866     /* See what arguments we were passed (if any) otherwise set the defaults */
00867     if (o_zone == NULL) {
00868         printf("Please specify a zone with the --zone option\n");
00869         usage_zone();
00870         return(1);
00871     }
00872 
00873     if (o_policy == NULL) {
00874         o_policy = StrStrdup("default");
00875     }
00876     /*
00877      * Set defaults and turn any relative paths into absolute 
00878      * (sort of, not the neatest output)
00879      */
00880     if (o_signerconf == NULL) {
00881         StrAppend(&sig_conf_name, OPENDNSSEC_STATE_DIR);
00882         StrAppend(&sig_conf_name, "/signconf/");
00883         StrAppend(&sig_conf_name, o_zone);
00884         StrAppend(&sig_conf_name, ".xml");
00885     }
00886     else if (*o_signerconf != '/') {
00887         StrAppend(&sig_conf_name, path);
00888         StrAppend(&sig_conf_name, "/");
00889         StrAppend(&sig_conf_name, o_signerconf);
00890     } else {
00891         StrAppend(&sig_conf_name, o_signerconf);
00892     }
00893 
00894     if (o_input == NULL) {
00895         StrAppend(&input_name, OPENDNSSEC_STATE_DIR);
00896         StrAppend(&input_name, "/unsigned/");
00897         StrAppend(&input_name, o_zone);
00898     }
00899     else if (*o_input != '/') {
00900         StrAppend(&input_name, path);
00901         StrAppend(&input_name, "/");
00902         StrAppend(&input_name, o_input);
00903     } else {
00904         StrAppend(&input_name, o_input);
00905     }
00906 
00907     if (o_output == NULL) {
00908         StrAppend(&output_name, OPENDNSSEC_STATE_DIR);
00909         StrAppend(&output_name, "/signed/");
00910         StrAppend(&output_name, o_zone);
00911     }
00912     else if (*o_output != '/') {
00913         StrAppend(&output_name, path);
00914         StrAppend(&output_name, "/");
00915         StrAppend(&output_name, o_output);
00916     } else {
00917         StrAppend(&output_name, o_output);
00918     }
00919 
00920     free(path);
00921 
00922     /* Set zonelist from the conf.xml that we have got */
00923     status = read_zonelist_filename(&zonelist_filename);
00924     if (status != 0) {
00925         printf("couldn't read zonelist\n");
00926         StrFree(zonelist_filename);
00927         StrFree(sig_conf_name);
00928         StrFree(input_name);
00929         StrFree(output_name);
00930         return(1);
00931     }
00932 
00933     /*
00934      * Push this new zonelist into the database
00935      */
00936 
00937     /* try to connect to the database */
00938     status = db_connect(&dbhandle, &lock_fd, 1);
00939     if (status != 0) {
00940         printf("Failed to connect to database\n");
00941         db_disconnect(lock_fd);
00942         StrFree(zonelist_filename);
00943         StrFree(sig_conf_name);
00944         StrFree(input_name);
00945         StrFree(output_name);
00946         return(1);
00947     } 
00948 
00949     /* Now stick this zone into the database */
00950     status = KsmPolicyIdFromName(o_policy, &policy_id);
00951     if (status != 0) {
00952         printf("Error, can't find policy : %s\n", o_policy);
00953         printf("Failed to update zones\n");
00954         db_disconnect(lock_fd);
00955         StrFree(zonelist_filename);
00956         StrFree(sig_conf_name);
00957         StrFree(input_name);
00958         StrFree(output_name);
00959         return(1);
00960     }
00961     status = KsmImportZone(o_zone, policy_id, 1, &new_zone, sig_conf_name, input_name, output_name);
00962     if (status != 0) {
00963         if (status == -2) {
00964             printf("Failed to Import zone %s; it already exists\n", o_zone);
00965                 } else if (status == -3) {
00966             printf("Failed to Import zone %s; it already exists both with and without a trailing dot\n", o_zone);
00967         } else {
00968             printf("Failed to Import zone\n");
00969         }
00970         db_disconnect(lock_fd);
00971         StrFree(zonelist_filename);
00972         StrFree(sig_conf_name);
00973         StrFree(input_name);
00974         StrFree(output_name);
00975         return(1);
00976     }
00977 
00978     /* If need be (keys shared on policy) link existing keys to zone */
00979     /* First work out if the keys are shared on this policy */
00980     status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
00981     if (status != 0) {
00982         printf("Can't retrieve shared-keys parameter for policy\n");
00983         db_disconnect(lock_fd);
00984         StrFree(zonelist_filename);
00985         StrFree(sig_conf_name);
00986         StrFree(input_name);
00987         StrFree(output_name);
00988         return(1);
00989     }
00990     status = KsmParameter(result, &data);
00991     if (status != 0) {
00992         printf("Can't retrieve shared-keys parameter for policy\n");
00993         db_disconnect(lock_fd);
00994         StrFree(zonelist_filename);
00995         StrFree(sig_conf_name);
00996         StrFree(input_name);
00997         StrFree(output_name);
00998         return(1);
00999     }
01000     KsmParameterEnd(result);
01001     
01002     /* If the policy does not share keys then skip this */
01003     if (data.value == 1) {
01004         status = LinkKeys(o_zone, policy_id);
01005         if (status != 0) {
01006             printf("Failed to Link Keys to zone\n");
01007             /* Carry on and write the xml if the error code was 2 
01008                (not enough keys) */
01009             if (status != 2) {
01010                 db_disconnect(lock_fd);
01011                 StrFree(zonelist_filename);
01012                 StrFree(sig_conf_name);
01013                 StrFree(input_name);
01014                 StrFree(output_name);
01015                 return(1);
01016             }
01017         }
01018     }
01019 
01020     /* Release sqlite lock file (if we have it) */
01021     db_disconnect(lock_fd);
01022     DbDisconnect(dbhandle);
01023 
01024     if (xml_flag == 1) {
01025         /* Read the file and add our new node in memory */
01026         /* TODO don't add if it already exists */
01027         xmlKeepBlanksDefault(0);
01028         xmlTreeIndentString = "\t";
01029         doc = add_zone_node(zonelist_filename, o_zone, o_policy, sig_conf_name, input_name, output_name);
01030 
01031         StrFree(sig_conf_name);
01032         StrFree(input_name);
01033         StrFree(output_name);
01034 
01035         if (doc == NULL) {
01036             StrFree(zonelist_filename);
01037             return(1);
01038         }
01039 
01040         /* Backup the current zonelist */
01041         StrAppend(&backup_filename, zonelist_filename);
01042         StrAppend(&backup_filename, ".backup");
01043         status = backup_file(zonelist_filename, backup_filename);
01044         StrFree(backup_filename);
01045         if (status != 0) {
01046             StrFree(zonelist_filename);
01047             return(status);
01048         }
01049 
01050         /* Save our new one over, TODO should we validate it first? */
01051         status = xmlSaveFormatFile(zonelist_filename, doc, 1);
01052         StrFree(zonelist_filename);
01053         xmlFreeDoc(doc);
01054 
01055         if (status == -1) {
01056             printf("couldn't save zonelist\n");
01057             return(1);
01058         }
01059     }
01060 
01061     /* TODO - KICK THE ENFORCER? */
01062     /* <matthijs> TODO - ods-signer update? */
01063 
01064     if (xml_flag == 0) {
01065         printf("Imported zone: %s into database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone);
01066     } else {
01067         printf("Imported zone: %s\n", o_zone);
01068     }
01069 
01070 
01071     return 0;
01072 }
01073 
01074 /*
01075  * Delete a zone from the config 
01076  */
01077     int
01078 cmd_delzone ()
01079 {
01080 
01081     char* zonelist_filename = NULL;
01082     char* backup_filename = NULL;
01083     /* The settings that we need for the zone */
01084     int zone_id = -1;
01085     int policy_id = -1;
01086     int zone_count = -1;
01087 
01088     DB_RESULT   result;         /* Result of parameter query */
01089     DB_RESULT   result2;        /* Result of zone count query */
01090     KSM_PARAMETER shared;       /* Parameter information */
01091 
01092     xmlDocPtr doc = NULL;
01093 
01094     int status = 0;
01095     int user_certain;           /* Continue ? */
01096 
01097     /* Database connection details */
01098     DB_HANDLE   dbhandle;
01099     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
01100 
01101     /* We should either have a policy name or --all but not both */
01102     if (all_flag && o_zone != NULL) {
01103         printf("can not use --all with --zone\n");
01104         return(1);
01105     } 
01106     else if (!all_flag && o_zone == NULL) {
01107         printf("please specify either --zone <zone> or --all\n");
01108         return(1);
01109     }
01110 
01111     /* Warn and confirm if they have asked to delete all zones */
01112     if (all_flag == 1) {
01113         printf("*WARNING* This will remove all zones from OpenDNSSEC; are you sure? [y/N] ");
01114 
01115         user_certain = getchar();
01116         if (user_certain != 'y' && user_certain != 'Y') {
01117             printf("Okay, quitting...\n");
01118             exit(0);
01119         }
01120     }
01121 
01122     /* try to connect to the database */
01123     status = db_connect(&dbhandle, &lock_fd, 1);
01124     if (status != 0) {
01125         printf("Failed to connect to database\n");
01126         db_disconnect(lock_fd);
01127         return(1);
01128     }
01129 
01130         /* Put dot back in if we need to; delete zone is the only time we do this */
01131         if (td_flag == 1) {
01132                 StrAppend(&o_zone, ".");
01133         }
01134     /*
01135      * DO XML STUFF FIRST
01136      */
01137 
01138     if (xml_flag == 1) {
01139         /* Set zonelist from the conf.xml that we have got */
01140         status = read_zonelist_filename(&zonelist_filename);
01141         if (status != 0) {
01142             printf("couldn't read zonelist\n");
01143             db_disconnect(lock_fd);
01144             StrFree(zonelist_filename);
01145             return(1);
01146         }
01147 
01148         /* Read the file and delete our zone node(s) in memory */
01149                 /* N.B. This is deliberately _not_ trailing dot agnostic; the user will have to ask to delete the exact zone */
01150         doc = del_zone_node(zonelist_filename, o_zone);
01151         if (doc == NULL) {
01152             db_disconnect(lock_fd);
01153             StrFree(zonelist_filename);
01154             return(1);
01155         }
01156 
01157         /* Backup the current zonelist */
01158         StrAppend(&backup_filename, zonelist_filename);
01159         StrAppend(&backup_filename, ".backup");
01160         status = backup_file(zonelist_filename, backup_filename);
01161         StrFree(backup_filename);
01162         if (status != 0) {
01163             StrFree(zonelist_filename);
01164             db_disconnect(lock_fd);
01165             return(status);
01166         }
01167 
01168         /* Save our new one over, TODO should we validate it first? */
01169         status = xmlSaveFormatFile(zonelist_filename, doc, 1);
01170         xmlFreeDoc(doc);
01171         StrFree(zonelist_filename);
01172         if (status == -1) {
01173             printf("Could not save %s\n", zonelist_filename);
01174             db_disconnect(lock_fd);
01175             return(1);
01176         }
01177     }
01178 
01179     /*
01180      * NOW SORT OUT THE DATABASE (zone_id will still be -1 if we are deleting all)
01181      */
01182 
01183     /* See if the zone exists and get its ID, assuming we are not deleting all */
01184     if (all_flag == 0) {
01185         status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
01186         if (status != 0) {
01187             printf("Couldn't find zone %s\n", o_zone);
01188             db_disconnect(lock_fd);
01189             return(1);
01190         }
01191 
01192         /* Get the shared_keys parameter */
01193         status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
01194         if (status != 0) {
01195             db_disconnect(lock_fd);
01196             return(status);
01197         }
01198         status = KsmParameter(result, &shared);
01199         if (status != 0) {
01200             db_disconnect(lock_fd);
01201             return(status);
01202         }
01203         KsmParameterEnd(result);
01204     
01205         /* how many zones on this policy (needed to unlink keys) */ 
01206         status = KsmZoneCountInit(&result2, policy_id); 
01207         if (status == 0) { 
01208             status = KsmZoneCount(result2, &zone_count); 
01209         } 
01210         DbFreeResult(result2);
01211     }
01212 
01213     /* Mark keys as dead if appropriate */
01214     if (all_flag == 1 || (shared.value == 1 && zone_count == 1) || shared.value == 0) {
01215         status = KsmMarkKeysAsDead(zone_id);
01216         if (status != 0) {
01217             printf("Error: failed to mark keys as dead in database\n");
01218             db_disconnect(lock_fd);
01219             return(status);
01220         }
01221     }
01222 
01223     /* Finally, we can delete the zone (and any dnsseckeys entries) */
01224     status = KsmDeleteZone(zone_id);
01225 
01226     if (status != 0) {
01227         printf("Error: failed to remove zone%s from database\n", (all_flag == 1) ? "s" : "");
01228         db_disconnect(lock_fd);
01229         return status;
01230     }
01231     
01232     /* Call the signer_engine_cli to tell it that the zonelist has changed */
01233     /* TODO Should we do this when we remove a zone? */
01234     if (all_flag == 0) {
01235         if (system(SIGNER_CLI_UPDATE) != 0)
01236         {
01237             printf("Could not call signer engine\n");
01238         }
01239     }
01240 
01241     /* Release sqlite lock file (if we have it) */
01242     db_disconnect(lock_fd);
01243 
01244     if (xml_flag == 0) {
01245         printf("Deleted zone: %s from database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone);
01246     }
01247 
01248     return 0;
01249 }
01250 
01251 /*
01252  * List a zone 
01253  */
01254     int
01255 cmd_listzone ()
01256 {
01257 
01258     DB_HANDLE   dbhandle;
01259     FILE* lock_fd = NULL;  /* This is the lock file descriptor for a SQLite DB */
01260 
01261     char* zonelist_filename = NULL;
01262     int* zone_ids;      /* List of zone_ids seen from zonelist.xml */
01263 
01264     xmlTextReaderPtr reader = NULL;
01265     int ret = 0; /* status of the XML parsing */
01266     char* tag_name = NULL;
01267 
01268     int file_zone_count = 0; /* As a quick check we will compare the number of */
01269     int     j = 0;          /* Another counter */
01270     char    buffer[256];    /* For constructing part of the command */
01271     char*   sql = NULL;   /* SQL "IN" query */
01272     DB_RESULT   result;         /* Result of the query */
01273     DB_ROW      row = NULL;     /* Row data */
01274     char*       temp_name = NULL;
01275 
01276     int status = 0;
01277 
01278     /* Set zonelist from the conf.xml that we have got */
01279     status = read_zonelist_filename(&zonelist_filename);
01280     if (status != 0) {
01281         printf("couldn't read zonelist\n");
01282         if (zonelist_filename != NULL) {
01283             StrFree(zonelist_filename);
01284         }
01285         return(1);
01286     }
01287 
01288     /* try to connect to the database */
01289     status = db_connect(&dbhandle, &lock_fd, 1);
01290     if (status != 0) {
01291         printf("Failed to connect to database\n");
01292         db_disconnect(lock_fd);
01293         return(1);
01294     }
01295 
01296     /* Read through the file counting zones TODO better way to do this? */
01297     reader = xmlNewTextReaderFilename(zonelist_filename);
01298     if (reader != NULL) {
01299         ret = xmlTextReaderRead(reader);
01300         while (ret == 1) {
01301             tag_name = (char*) xmlTextReaderLocalName(reader);
01302             /* Found <Zone> */
01303             if (strncmp(tag_name, "Zone", 4) == 0 
01304                     && strncmp(tag_name, "ZoneList", 8) != 0
01305                     && xmlTextReaderNodeType(reader) == 1) {
01306                 file_zone_count++;
01307             }
01308             /* Read the next line */
01309             ret = xmlTextReaderRead(reader);
01310             StrFree(tag_name);
01311         }
01312         xmlFreeTextReader(reader);
01313         if (ret != 0) {
01314             printf("%s : failed to parse\n", zonelist_filename);
01315         }
01316     } else {
01317         printf("Unable to open %s\n", zonelist_filename);
01318     }
01319 
01320     /* Allocate space for the list of zone IDs */
01321     zone_ids = MemMalloc(file_zone_count * sizeof(int));
01322 
01323     /* Read the file and list the zones as we go */
01324     list_zone_node(zonelist_filename, zone_ids);
01325 
01326         /* Now see if there are any zones in the DB which are not in the file */
01327         if (file_zone_count != 0) {
01328                 StrAppend(&sql, "select name from zones where id not in (");
01329                 for (j = 0; j < file_zone_count; ++j) {
01330                         if (j != 0) {
01331                                 StrAppend(&sql, ",");
01332                         }
01333                         snprintf(buffer, sizeof(buffer), "%d", zone_ids[j]);
01334                         StrAppend(&sql, buffer);
01335                 }
01336                 StrAppend(&sql, ")");
01337         } else {
01338                 StrAppend(&sql, "select name from zones");
01339         }
01340 
01341     status = DbExecuteSql(DbHandle(), sql, &result);
01342     if (status == 0) {
01343         status = DbFetchRow(result, &row);
01344         while (status == 0) {
01345             /* Got a row, print it */
01346             DbString(row, 0, &temp_name);
01347 
01348             printf("Found zone %s in DB but not zonelist.\n", temp_name);
01349             status = DbFetchRow(result, &row);
01350                         file_zone_count++;
01351         }
01352 
01353         /* Convert EOF status to success */
01354 
01355         if (status == -1) {
01356             status = 0;
01357         }
01358 
01359         DbFreeResult(result);
01360     }
01361 
01362     db_disconnect(lock_fd);
01363     DbDisconnect(dbhandle);
01364 
01365         if (file_zone_count == 0) {
01366                 printf("No zones in DB or zonelist.\n");
01367         }
01368 
01369     MemFree(zone_ids);
01370     StrFree(sql);
01371     StrFree(zonelist_filename);
01372     StrFree(temp_name);
01373 
01374     return 0;
01375 }
01376 
01377 /*
01378  * To export: 
01379  *          keys|ds for zone
01380  */
01381     int
01382 cmd_exportkeys ()
01383 {
01384     int status = 0;
01385     /* Database connection details */
01386     DB_HANDLE   dbhandle;
01387 
01388     int zone_id = -1;
01389     int state_id = -1;
01390     int keytype_id = KSM_TYPE_KSK;
01391 
01392     char *case_keytype = NULL;
01393     char *case_keystate = NULL;
01394     char *zone_name = NULL;
01395 
01396     /* Key information */
01397     hsm_key_t *key = NULL;
01398     ldns_rr *dnskey_rr = NULL;
01399     ldns_rr *ds_sha1_rr = NULL;
01400     ldns_rr *ds_sha256_rr = NULL;
01401     hsm_sign_params_t *sign_params = NULL;
01402 
01403     char* sql = NULL;
01404     KSM_KEYDATA data;       /* Data for each key */
01405     DB_RESULT   result;     /* Result set from query */
01406     size_t  nchar;          /* Number of characters written */
01407     char    buffer[256];    /* For constructing part of the command */
01408 
01409     /* See what arguments we were passed (if any) otherwise set the defaults */
01410     /* Check keystate, can be state or keytype */
01411     if (o_keystate != NULL) {
01412         case_keystate = StrStrdup(o_keystate);
01413         (void) StrToUpper(case_keystate);
01414         if (strncmp(case_keystate, "KEYPUBLISH", 10) == 0 || strncmp(o_keystate, "10", 2) == 0) {
01415             state_id =  KSM_STATE_KEYPUBLISH;
01416         }
01417         else if (strncmp(case_keystate, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) {
01418             state_id = KSM_STATE_GENERATE;
01419         }
01420         else if (strncmp(case_keystate, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) {
01421             state_id =  KSM_STATE_PUBLISH;
01422         }
01423         else if (strncmp(case_keystate, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) {
01424             state_id =  KSM_STATE_READY;
01425         }
01426         else if (strncmp(case_keystate, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) {
01427             state_id =  KSM_STATE_ACTIVE;
01428         }
01429         else if (strncmp(case_keystate, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) {
01430             state_id =  KSM_STATE_RETIRE;
01431         }
01432         else if (strncmp(case_keystate, "DEAD", 4) == 0 || strncmp(o_keystate, "6", 1) == 0) {
01433             state_id =  KSM_STATE_DEAD;
01434         }
01435         else if (strncmp(case_keystate, "DSSUB", 5) == 0 || strncmp(o_keystate, "7", 1) == 0) {
01436             state_id =  KSM_STATE_DSSUB;
01437         }
01438         else if (strncmp(case_keystate, "DSPUBLISH", 9) == 0 || strncmp(o_keystate, "8", 1) == 0) {
01439             state_id =  KSM_STATE_DSPUBLISH;
01440         }
01441         else if (strncmp(case_keystate, "DSREADY", 7) == 0 || strncmp(o_keystate, "9", 1) == 0) {
01442             state_id =  KSM_STATE_DSREADY;
01443         }
01444         else {
01445             printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE, RETIRE, DEAD, DSSUB, DSPUBLISH, DSREADY or KEYPUBLISH\n", o_keystate);
01446 
01447             StrFree(case_keystate);
01448             return(1);
01449         }
01450         StrFree(case_keystate);
01451     }
01452 
01453     /* Check keytype */
01454     if (o_keytype != NULL) {
01455         case_keytype = StrStrdup(o_keytype);
01456         (void) StrToUpper(case_keytype);
01457         if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) {
01458             keytype_id = KSM_TYPE_KSK;
01459         }
01460         else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) {
01461             keytype_id = KSM_TYPE_ZSK;
01462         }
01463         else {
01464             printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype);
01465 
01466             StrFree(case_keytype);
01467             return(1);
01468         }
01469         StrFree(case_keytype);
01470     }
01471 
01472     /* try to connect to the database */
01473     status = db_connect(&dbhandle, NULL, 0);
01474     if (status != 0) {
01475         printf("Failed to connect to database\n");
01476         return(1);
01477     }
01478 
01479     /* check that the zone name is valid and use it to get some ids */
01480     if (o_zone != NULL) {
01481         status = KsmZoneIdFromName(o_zone, &zone_id);
01482         if (status != 0) {
01483                         /* Try again with td */
01484                         StrAppend(&o_zone, ".");
01485                         status = KsmZoneIdFromName(o_zone, &zone_id);
01486                         if (status != 0) {
01487                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
01488                                 return(status);
01489                         }
01490                 }
01491     }
01492 
01493     status = hsm_open(config, hsm_prompt_pin, NULL);
01494     if (status) {
01495         hsm_print_error(NULL);
01496         exit(-1);
01497     }
01498 
01499     sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
01500     if (state_id != -1) {
01501         DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, state_id, 0);
01502     } else {
01503         nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d)",
01504                 KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB, 
01505                 KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY, KSM_STATE_KEYPUBLISH);
01506         if (nchar >= sizeof(buffer)) {
01507             status = -1;
01508             return status;
01509         }
01510         DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, 0);
01511 
01512     }
01513     DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype_id, 1);
01514     if (zone_id != -1) {
01515         DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 2);
01516     }
01517     DqsOrderBy(&sql, "STATE");
01518     DqsEnd(&sql);
01519 
01520     status = KsmKeyInitSql(&result, sql);
01521     if (status == 0) {
01522         status = KsmKey(result, &data);
01523         while (status == 0) {
01524 
01525             /* Code to output the DNSKEY record  (stolen from hsmutil) */
01526             key = hsm_find_key_by_id(NULL, data.location);
01527 
01528             if (!key) {
01529                 printf("Key %s in DB but not repository\n", data.location);
01530                 return -1;
01531             }
01532 
01533             sign_params = hsm_sign_params_new();
01534             /* If zone_id == -1 then we need to work out the zone name from data.zone_id */
01535             if (zone_id == -1) {
01536                 status = KsmZoneNameFromId(data.zone_id, &zone_name);
01537                 if (status != 0) {
01538                     printf("Error: unable to find zone name for id %d\n", zone_id);
01539                     hsm_sign_params_free(sign_params);
01540                     return(status);
01541                 }
01542                 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name);
01543                 StrFree(zone_name);
01544             }
01545             else {
01546                 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, o_zone);
01547             }
01548 
01549             sign_params->algorithm = data.algorithm;
01550             sign_params->flags = LDNS_KEY_ZONE_KEY;
01551             if (keytype_id == KSM_TYPE_KSK) {
01552                 sign_params->flags += LDNS_KEY_SEP_KEY;
01553             }
01554             dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
01555             sign_params->keytag = ldns_calc_keytag(dnskey_rr);
01556 
01557             if (ds_flag == 0) {
01558                 printf("\n;%s %s DNSKEY record:\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
01559                 ldns_rr_print(stdout, dnskey_rr);
01560             }
01561             else {
01562 
01563                 printf("\n;%s %s DS record (SHA1):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
01564                 ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
01565                 ldns_rr_print(stdout, ds_sha1_rr);
01566 
01567                 printf("\n;%s %s DS record (SHA256):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
01568                 ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
01569                 ldns_rr_print(stdout, ds_sha256_rr);
01570             }
01571 
01572             hsm_sign_params_free(sign_params);
01573             hsm_key_free(key);
01574             status = KsmKey(result, &data);
01575 
01576         }
01577         /* Convert EOF status to success */
01578         if (status == -1) {
01579             status = 0;
01580         }
01581 
01582         KsmKeyEnd(result);
01583     }
01584 
01585     /* TODO when the above is working then replicate it twice for the case where keytype == -1 */
01586 
01587     if (dnskey_rr != NULL) {
01588         ldns_rr_free(dnskey_rr);
01589     }
01590     if (ds_sha1_rr != NULL) {
01591         ldns_rr_free(ds_sha1_rr);
01592     }
01593     if (ds_sha256_rr != NULL) {
01594         ldns_rr_free(ds_sha256_rr);
01595     }
01596 
01597     DbDisconnect(dbhandle);
01598 
01599     return 0;
01600 }
01601 
01602 /*
01603  * To export: 
01604  *          policies (all, unless one is named) to xml
01605  */
01606     int
01607 cmd_exportpolicy ()
01608 {
01609     int status = 0;
01610     /* Database connection details */
01611     DB_HANDLE   dbhandle;
01612 
01613     xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0");
01614     xmlNodePtr root;
01615     KSM_POLICY *policy;
01616 
01617     DB_RESULT   result;     /* Result set from query */
01618 
01619     /* We should either have a policy name or --all but not both */
01620     if (all_flag && o_policy != NULL) {
01621         printf("can not use --all with --policy\n");
01622         return(1);
01623     } 
01624     else if (!all_flag && o_policy == NULL) {
01625         printf("please specify either --policy <policy> or --all\n");
01626         return(1);
01627     } 
01628 
01629     /* try to connect to the database */
01630     status = db_connect(&dbhandle, NULL, 0);
01631     if (status != 0) {
01632         printf("Failed to connect to database\n");
01633         return(1);
01634     }
01635 
01636     /* Make some space for the policy */ 
01637     policy = (KSM_POLICY *)malloc(sizeof(KSM_POLICY));
01638     policy->signer = (KSM_SIGNER_POLICY *)malloc(sizeof(KSM_SIGNER_POLICY));
01639     policy->signature = (KSM_SIGNATURE_POLICY *)malloc(sizeof(KSM_SIGNATURE_POLICY));
01640     policy->zone = (KSM_ZONE_POLICY *)malloc(sizeof(KSM_ZONE_POLICY));
01641     policy->parent = (KSM_PARENT_POLICY *)malloc(sizeof(KSM_PARENT_POLICY));
01642     policy->keys = (KSM_COMMON_KEY_POLICY *)malloc(sizeof(KSM_COMMON_KEY_POLICY));
01643     policy->ksk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY));
01644     policy->zsk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY));
01645     policy->denial = (KSM_DENIAL_POLICY *)malloc(sizeof(KSM_DENIAL_POLICY));
01646     policy->enforcer = (KSM_ENFORCER_POLICY *)malloc(sizeof(KSM_ENFORCER_POLICY));
01647     /*    policy->audit = (KSM_AUDIT_POLICY *)malloc(sizeof(KSM_AUDIT_POLICY)); */
01648     policy->audit = (char *)calloc(KSM_POLICY_AUDIT_LENGTH, sizeof(char));
01649     policy->description = (char *)calloc(KSM_POLICY_DESC_LENGTH, sizeof(char));
01650     if (policy->signer == NULL || policy->signature == NULL || 
01651             policy->zone == NULL || policy->parent == NULL ||
01652             policy->keys == NULL ||
01653             policy->ksk == NULL || policy->zsk == NULL || 
01654             policy->denial == NULL || policy->enforcer == NULL) {
01655         fprintf(stderr, "Malloc for policy struct failed\n");
01656         exit(1);
01657     }
01658 
01659     /* Setup doc with a root node of <KASP> */
01660     xmlKeepBlanksDefault(0);
01661     xmlTreeIndentString = "    ";
01662     root = xmlNewDocNode(doc, NULL, (const xmlChar *)"KASP", NULL);
01663     (void) xmlDocSetRootElement(doc, root);
01664 
01665     /* Read policies (all if policy_name == NULL; else named policy only) */
01666     status = KsmPolicyInit(&result, o_policy);
01667     if (status == 0) {
01668         /* get the first policy */
01669         status = KsmPolicy(result, policy);
01670         KsmPolicyRead(policy);
01671 
01672         while (status == 0) {
01673             append_policy(doc, policy);
01674 
01675             /* get next policy */
01676             status = KsmPolicy(result, policy);
01677             KsmPolicyRead(policy);
01678 
01679         }
01680     }
01681 
01682     xmlSaveFormatFile("-", doc, 1);
01683 
01684     xmlFreeDoc(doc);
01685     KsmPolicyFree(policy);
01686 
01687     DbDisconnect(dbhandle);
01688 
01689     return 0;
01690 }
01691 
01692 /*
01693  * To export: 
01694  *          zonelist to xml
01695  */
01696     int
01697 cmd_exportzonelist ()
01698 {
01699     int status = 0;
01700     /* Database connection details */
01701     DB_HANDLE   dbhandle;
01702 
01703     xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0");
01704     xmlNodePtr root;
01705     KSM_ZONE *zone;
01706     int prev_policy_id = -1;
01707 
01708     DB_RESULT   result;     /* Result set from query */
01709 
01710     /* try to connect to the database */
01711     status = db_connect(&dbhandle, NULL, 0);
01712     if (status != 0) {
01713         printf("Failed to connect to database\n");
01714         return(1);
01715     }
01716 
01717     /* Make some space for the zone */ 
01718     zone = (KSM_ZONE *)malloc(sizeof(KSM_ZONE));
01719     if (zone == NULL) {
01720         fprintf(stderr, "Malloc for zone struct failed\n");
01721         exit(1);
01722     }
01723 
01724     /* Setup doc with a root node of <ZoneList> */
01725     xmlKeepBlanksDefault(0);
01726     xmlTreeIndentString = "    ";
01727     root = xmlNewDocNode(doc, NULL, (const xmlChar *)"ZoneList", NULL);
01728     (void) xmlDocSetRootElement(doc, root);
01729 
01730     /* Read zones */
01731     status = KsmZoneInit(&result, -1);
01732     if (status == 0) {
01733         /* get the first zone */
01734         status = KsmZone(result, zone);
01735 
01736         while (status == 0) {
01737             if (zone->policy_id != prev_policy_id) {
01738                 prev_policy_id = zone->policy_id;
01739                 status = get_policy_name_from_id(zone);
01740                 if (status != 0) {
01741                     fprintf(stderr, "Couldn't get name for policy with ID: %d, exiting...\n", zone->policy_id);
01742                     return(1);
01743                 }
01744             }
01745             append_zone(doc, zone);
01746 
01747             /* get next zone */
01748             status = KsmZone(result, zone);
01749 
01750         }
01751     }
01752 
01753     xmlSaveFormatFile("-", doc, 1);
01754 
01755     xmlFreeDoc(doc);
01756     /*KsmZoneFree(zone);*/
01757 
01758     DbDisconnect(dbhandle);
01759 
01760     return 0;
01761 }
01762 
01763 /*
01764  * To rollover a zone (or all zones on a policy if keys are shared)
01765  */
01766     int
01767 cmd_rollzone ()
01768 {
01769     /* Database connection details */
01770     DB_HANDLE   dbhandle;
01771     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
01772     DB_RESULT   result;         /* Result of parameter query */
01773     KSM_PARAMETER data;         /* Parameter information */
01774     
01775     int key_type = -1;
01776     int zone_id = -1;
01777     int policy_id = -1;
01778 
01779     int status = 0;
01780     int user_certain;
01781 
01782     /* If we were given a keytype, turn it into a number */
01783     if (o_keytype != NULL) {
01784         StrToLower(o_keytype);
01785         key_type = KsmKeywordTypeNameToValue(o_keytype);
01786     }
01787 
01788     /* try to connect to the database */
01789     status = db_connect(&dbhandle, &lock_fd, 1);
01790     if (status != 0) {
01791         printf("Failed to connect to database\n");
01792         db_disconnect(lock_fd);
01793         return(1);
01794     }
01795 
01796     status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
01797         if (status != 0) {
01798                 /* Try again with td */
01799                 StrAppend(&o_zone, ".");
01800                 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
01801                 if (status != 0) {
01802                         db_disconnect(lock_fd);
01803                         return(status);
01804                 }
01805     }
01806 
01807     /* Get the shared_keys parameter */
01808     status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
01809     if (status != 0) {
01810         db_disconnect(lock_fd);
01811         return(status);
01812     }
01813     status = KsmParameter(result, &data);
01814     if (status != 0) {
01815         db_disconnect(lock_fd);
01816         return(status);
01817     }
01818     KsmParameterEnd(result);
01819     
01820     /* Warn and confirm if this will roll more than one zone */
01821     if (data.value == 1) {
01822         printf("*WARNING* This zone shares keys with others, all instances of the active key on this zone will be retired; are you sure? [y/N] ");
01823 
01824         user_certain = getchar();
01825         if (user_certain != 'y' && user_certain != 'Y') {
01826             printf("Okay, quitting...\n");
01827             db_disconnect(lock_fd);
01828             exit(0);
01829         }
01830     }
01831 
01832     status = keyRoll(zone_id, -1, key_type);
01833     if (status != 0) {
01834         db_disconnect(lock_fd);
01835         return(status);
01836     }
01837 
01838     /* Release sqlite lock file (if we have it) */
01839     db_disconnect(lock_fd);
01840 
01841     /* Need to poke the enforcer to wake it up */
01842     if (restart_enforcerd() != 0)
01843     {
01844         fprintf(stderr, "Could not HUP ods-enforcerd\n");
01845     }
01846 
01847     DbDisconnect(dbhandle);
01848 
01849     return 0;
01850 }
01851 
01852 /*
01853  * To rollover all zones on a policy
01854  */
01855     int
01856 cmd_rollpolicy ()
01857 {
01858     /* Database connection details */
01859     DB_HANDLE   dbhandle;
01860     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
01861 
01862     DB_RESULT   result;     /* To see if the policy shares keys or not */
01863 
01864     int zone_count = -1;
01865     
01866     int key_type = 0;
01867     int policy_id = 0;
01868 
01869     int status = 0;
01870     int user_certain;
01871 
01872     /* If we were given a keytype, turn it into a number */
01873     if (o_keytype != NULL) {
01874         StrToLower(o_keytype);
01875         key_type = KsmKeywordTypeNameToValue(o_keytype);
01876     }
01877 
01878     /* try to connect to the database */
01879     status = db_connect(&dbhandle, &lock_fd, 1);
01880     if (status != 0) {
01881         printf("Failed to connect to database\n");
01882         db_disconnect(lock_fd);
01883         return(1);
01884     }
01885 
01886     status = KsmPolicyIdFromName(o_policy, &policy_id);
01887     if (status != 0) {
01888         printf("Error, can't find policy : %s\n", o_policy);
01889         db_disconnect(lock_fd);
01890         return(status);
01891     }
01892 
01893     /* Warn and confirm */
01894     printf("*WARNING* This will roll all keys on the policy; are you sure? [y/N] ");
01895 
01896     user_certain = getchar();
01897     if (user_certain != 'y' && user_certain != 'Y') {
01898         printf("Okay, quitting...\n");
01899         db_disconnect(lock_fd);
01900         exit(0);
01901     }
01902 
01903     /* Find out how many zones we will need to do */
01904     /* how many zones on this policy */ 
01905     status = KsmZoneCountInit(&result, policy_id); 
01906     if (status == 0) { 
01907         status = KsmZoneCount(result, &zone_count); 
01908     } 
01909     DbFreeResult(result); 
01910 
01911     if (status == 0) { 
01912         /* make sure that we have at least one zone */ 
01913         if (zone_count == 0) {
01914             printf("No zones on policy; nothing to roll\n");
01915             db_disconnect(lock_fd);
01916             return status; 
01917         } 
01918     } else { 
01919         printf("Couldn't count zones on policy; quitting...\n");
01920         db_disconnect(lock_fd);
01921         exit(1); 
01922     }
01923 
01924     status = keyRoll(-1, policy_id, key_type);
01925 
01926     /* Release sqlite lock file (if we have it) */
01927     db_disconnect(lock_fd);
01928 
01929     /* Need to poke the enforcer to wake it up */
01930     if (restart_enforcerd() != 0)
01931     {
01932         fprintf(stderr, "Could not HUP ods-enforcerd\n");
01933     }
01934 
01935     DbDisconnect(dbhandle);
01936 
01937     return 0;
01938 }
01939 
01940 /*
01941  * purge dead keys from the database
01942  */
01943     int
01944 cmd_keypurge ()
01945 {
01946     int status = 0;
01947 
01948     int policy_id = -1;
01949     int zone_id = -1;
01950 
01951     /* Database connection details */
01952     DB_HANDLE   dbhandle;
01953     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
01954 
01955     /* try to connect to the database */
01956     status = db_connect(&dbhandle, &lock_fd, 1);
01957     if (status != 0) {
01958         printf("Failed to connect to database\n");
01959         db_disconnect(lock_fd);
01960         return(1);
01961     }
01962 
01963     /* Turn policy name into an id (if provided) */
01964     if (o_policy != NULL) {
01965         status = KsmPolicyIdFromName(o_policy, &policy_id);
01966         if (status != 0) {
01967             printf("Error: unable to find a policy named \"%s\" in database\n", o_policy);
01968             db_disconnect(lock_fd);
01969             return status;
01970         }
01971     }
01972 
01973     /* Turn zone name into an id (if provided) */
01974     if (o_zone != NULL) {
01975         status = KsmZoneIdFromName(o_zone, &zone_id);
01976         if (status != 0) {
01977                 /* Try again with td */
01978                         StrAppend(&o_zone, ".");
01979                         status = KsmZoneIdFromName(o_zone, &zone_id);
01980                         if (status != 0) {
01981                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
01982                                 db_disconnect(lock_fd);
01983                                 return(status);
01984                         }
01985         }
01986     }
01987 
01988     status = PurgeKeys(zone_id, policy_id);
01989 
01990     if (status != 0) {
01991         printf("Error: failed to purge dead keys\n");
01992         db_disconnect(lock_fd);
01993         return status;
01994     }
01995 
01996     /* Release sqlite lock file (if we have it) */
01997     db_disconnect(lock_fd);
01998 
01999     DbDisconnect(dbhandle);
02000     return 0;
02001 }
02002 
02003 /*
02004  * note that fact that a backup has been performed
02005  */
02006     int
02007 cmd_backup (const char* qualifier)
02008 {
02009     int status = 0;
02010 
02011     int repo_id = -1;
02012 
02013     /* Database connection details */
02014     DB_HANDLE   dbhandle;
02015     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02016 
02017     char* datetime = DtParseDateTimeString("now");
02018 
02019     /* Check datetime in case it came back NULL */
02020     if (datetime == NULL) {
02021         printf("Couldn't turn \"now\" into a date, quitting...\n");
02022         exit(1);
02023     }
02024 
02025     /* try to connect to the database */
02026     status = db_connect(&dbhandle, &lock_fd, 1);
02027     if (status != 0) {
02028         printf("Failed to connect to database\n");
02029         db_disconnect(lock_fd);
02030         StrFree(datetime);
02031         return(1);
02032     }
02033 
02034     /* Turn repo name into an id (if provided) */
02035     if (o_repository != NULL) {
02036         status = KsmSmIdFromName(o_repository, &repo_id);
02037         if (status != 0) {
02038             printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
02039             db_disconnect(lock_fd);
02040             StrFree(datetime);
02041             return status;
02042         }
02043     }
02044 
02045     /* Do Pre first */
02046     if (strncmp(qualifier, "PREPARE", 7) == 0 ||
02047             strncmp(qualifier, "DONE", 4) == 0 ) {
02048         status = KsmMarkPreBackup(repo_id, datetime);
02049         if (status == -1) {
02050             printf("There were no keys to mark\n");
02051         }
02052         else if (status != 0) {
02053             printf("Error: failed to mark pre_backup as done\n");
02054             db_disconnect(lock_fd);
02055             StrFree(datetime);
02056             return status;
02057         } else {
02058             if (strncmp(qualifier, "PREPARE", 7) == 0) {
02059                 if (o_repository != NULL) {
02060                     printf("Marked repository %s as pre-backed up at %s\n", o_repository, datetime);
02061                 } else {
02062                     printf("Marked all repositories as pre-backed up at %s\n", datetime);
02063                 }
02064             }
02065         }
02066     }
02067 
02068     /* Then commit */
02069     if (strncmp(qualifier, "COMMIT", 6) == 0 ||
02070             strncmp(qualifier, "DONE", 4) == 0 ) {
02071         status = KsmMarkBackup(repo_id, datetime);
02072         if (status == -1) {
02073             printf("There were no keys to mark\n");
02074         }
02075         else if (status != 0) {
02076             printf("Error: failed to mark backup as done\n");
02077             db_disconnect(lock_fd);
02078             StrFree(datetime);
02079             return status;
02080         } else {
02081             if (o_repository != NULL) {
02082                 printf("Marked repository %s as backed up at %s\n", o_repository, datetime);
02083             } else {
02084                 printf("Marked all repositories as backed up at %s\n", datetime);
02085             }
02086         }
02087     }
02088 
02089     /* Finally rollback */
02090     if (strncmp(qualifier, "ROLLBACK", 6) == 0 ) {
02091         status = KsmRollbackMarkPreBackup(repo_id);
02092         if (status == -1) {
02093             printf("There were no keys to rollback\n");
02094         }
02095         else if (status != 0) {
02096             printf("Error: failed to mark backup as done\n");
02097             db_disconnect(lock_fd);
02098             StrFree(datetime);
02099             return status;
02100         } else {
02101             if (o_repository != NULL) {
02102                 printf("Rolled back pre-backup of repository %s\n", o_repository);
02103             } else {
02104                 printf("Rolled back pre-backup of all repositories\n");
02105             }
02106         }
02107     }
02108 
02109     StrFree(datetime);
02110     /* Release sqlite lock file (if we have it) */
02111     db_disconnect(lock_fd);
02112 
02113     DbDisconnect(dbhandle);
02114     return 0;
02115 }
02116 
02117 /*
02118  * List rollovers
02119  */
02120     int
02121 cmd_listrolls ()
02122 {
02123     int status = 0;
02124 
02125     int qualifier_id = -1;      /* ID of qualifer (if given) */
02126 
02127     /* Database connection details */
02128     DB_HANDLE   dbhandle;
02129     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02130 
02131     /* try to connect to the database */
02132     status = db_connect(&dbhandle, &lock_fd, 1);
02133     if (status != 0) {
02134         printf("Failed to connect to database\n");
02135         db_disconnect(lock_fd);
02136         return(1);
02137     }
02138 
02139     /* Turn zone name into an id (if provided) */
02140     if (o_zone != NULL) {
02141         status = KsmZoneIdFromName(o_zone, &qualifier_id);
02142         if (status != 0) {
02143                         /* Try again with td */
02144                         StrAppend(&o_zone, ".");
02145                         status = KsmZoneIdFromName(o_zone, &qualifier_id);
02146                         if (status != 0) {
02147                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
02148                                 db_disconnect(lock_fd);
02149                                 return(status);
02150                         }
02151         }
02152     }
02153 
02154     printf("Rollovers:\n");
02155 
02156     status = KsmListRollovers(qualifier_id);
02157 
02158     if (status != 0) {
02159         printf("Error: failed to list rollovers\n");
02160         db_disconnect(lock_fd);
02161         return status;
02162     }
02163 
02164     printf("\n");
02165 
02166     /* Release sqlite lock file (if we have it) */
02167     db_disconnect(lock_fd);
02168 
02169     DbDisconnect(dbhandle);
02170     return 0;
02171 }
02172 
02173 /*
02174  * List backups
02175  */
02176     int
02177 cmd_listbackups ()
02178 {
02179     int status = 0;
02180 
02181     int qualifier_id = -1;      /* ID of qualifer (if given) */
02182 
02183     /* Database connection details */
02184     DB_HANDLE   dbhandle;
02185     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02186 
02187     /* try to connect to the database */
02188     status = db_connect(&dbhandle, &lock_fd, 0);
02189     if (status != 0) {
02190         printf("Failed to connect to database\n");
02191         db_disconnect(lock_fd);
02192         return(1);
02193     }
02194 
02195     /* Turn repo name into an id (if provided) */
02196     if (o_repository != NULL) {
02197         status = KsmSmIdFromName(o_repository, &qualifier_id);
02198         if (status != 0) {
02199             printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
02200             db_disconnect(lock_fd);
02201             return status;
02202         }
02203     }
02204 
02205     printf("Backups:\n");
02206     status = KsmListBackups(qualifier_id, verbose_flag);
02207 
02208     if (status != 0) {
02209         printf("Error: failed to list backups\n");
02210         db_disconnect(lock_fd);
02211         return status;
02212     }
02213     printf("\n");
02214 
02215     /* Release sqlite lock file (if we have it) */
02216     db_disconnect(lock_fd);
02217 
02218     DbDisconnect(dbhandle);
02219     return 0;
02220 }
02221 
02222 /*
02223  * List repos
02224  */
02225     int
02226 cmd_listrepo ()
02227 {
02228     int status = 0;
02229 
02230     /* Database connection details */
02231     DB_HANDLE   dbhandle;
02232     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02233 
02234     /* try to connect to the database */
02235     status = db_connect(&dbhandle, &lock_fd, 0);
02236     if (status != 0) {
02237         printf("Failed to connect to database\n");
02238         db_disconnect(lock_fd);
02239         return(1);
02240     }
02241 
02242     printf("Repositories:\n");
02243 
02244     status = KsmListRepos();
02245 
02246     if (status != 0) {
02247         printf("Error: failed to list repositories\n");
02248         if (lock_fd != NULL) {
02249             fclose(lock_fd);
02250         }
02251         return status;
02252     }
02253 
02254     printf("\n");
02255 
02256     /* Release sqlite lock file (if we have it) */
02257     db_disconnect(lock_fd);
02258 
02259     DbDisconnect(dbhandle);
02260     return 0;
02261 }
02262 
02263 /*
02264  * List policy
02265  */
02266     int
02267 cmd_listpolicy ()
02268 {
02269     int status = 0;
02270 
02271     /* Database connection details */
02272     DB_HANDLE   dbhandle;
02273     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02274 
02275     /* try to connect to the database */
02276     status = db_connect(&dbhandle, &lock_fd, 0);
02277     if (status != 0) {
02278         printf("Failed to connect to database\n");
02279         db_disconnect(lock_fd);
02280         return(1);
02281     }
02282 
02283     printf("Policies:\n");
02284 
02285     status = KsmListPolicies();
02286 
02287     if (status != 0) {
02288         printf("Error: failed to list policies\n");
02289         db_disconnect(lock_fd);
02290         return status;
02291     }
02292 
02293     printf("\n");
02294 
02295     /* Release sqlite lock file (if we have it) */
02296     db_disconnect(lock_fd);
02297 
02298     DbDisconnect(dbhandle);
02299     return 0;
02300 }
02301 
02302 /*
02303  * List keys
02304  */
02305     int
02306 cmd_listkeys ()
02307 {
02308     int status = 0;
02309     int qualifier_id = -1;
02310 
02311     /* Database connection details */
02312     DB_HANDLE   dbhandle;
02313     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02314 
02315     /* try to connect to the database */
02316     status = db_connect(&dbhandle, &lock_fd, 0);
02317     if (status != 0) {
02318         printf("Failed to connect to database\n");
02319         db_disconnect(lock_fd);
02320         return(1);
02321     }
02322 
02323     /* Turn zone name into an id (if provided) */
02324     if (o_zone != NULL) {
02325         status = KsmZoneIdFromName(o_zone, &qualifier_id);
02326         if (status != 0) {
02327                         /* Try again with td */
02328                         StrAppend(&o_zone, ".");
02329                         status = KsmZoneIdFromName(o_zone, &qualifier_id);
02330                         if (status != 0) {
02331                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
02332                                 db_disconnect(lock_fd);
02333                                 return(status);
02334                         }
02335         }
02336     }
02337 
02338     printf("Keys:\n");
02339 
02340     status = ListKeys(qualifier_id);
02341 
02342     if (status != 0) {
02343         printf("Error: failed to list keys\n");
02344         db_disconnect(lock_fd);
02345         return status;
02346     }
02347 
02348     printf("\n");
02349 
02350     /* Release sqlite lock file (if we have it) */
02351     db_disconnect(lock_fd);
02352 
02353     DbDisconnect(dbhandle);
02354     return 0;
02355 }
02356 
02357 /*
02358  * KSKretire
02359        find key (either by details provided or oldest active), 
02360        make sure that it is unique and in active state,
02361        retire key and set its dead time,
02362  */
02363     int
02364 cmd_kskretire()
02365 {
02366     int status = 0;
02367     int zone_id = -1;
02368     int policy_id = -1;
02369     int key_count = -1;
02370     int keytag_int = -1;
02371     int temp_key_state = -1;
02372     int temp_keypair_id = -1;
02373     char* temp_cka_id = NULL; /* This will be set if we find a single matching key */
02374     int user_certain;           /* Continue ? */
02375 
02376     /* Database connection details */
02377     DB_HANDLE   dbhandle;
02378     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02379 
02380     char*   datetime = DtParseDateTimeString("now");
02381 
02382     /* Check datetime in case it came back NULL */
02383     if (datetime == NULL) {
02384         printf("Couldn't turn \"now\" into a date, quitting...\n");
02385         StrFree(datetime);
02386         exit(1);
02387     }
02388 
02389     /* Warn and confirm that they realise this will retire the old key */
02390     printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] ");
02391 
02392     user_certain = getchar();
02393     if (user_certain != 'y' && user_certain != 'Y') {
02394         printf("Okay, quitting...\n");
02395         exit(0);
02396     }
02397 
02398     /* try to connect to the database */
02399     status = db_connect(&dbhandle, &lock_fd, 1);
02400     if (status != 0) {
02401         printf("Failed to connect to database\n");
02402         db_disconnect(lock_fd);
02403         StrFree(datetime);
02404         return(1);
02405     }
02406 
02407     /* Turn zone name into an id (if provided) */
02408     if (o_zone != NULL) {
02409         status = KsmZoneIdFromName(o_zone, &zone_id);
02410         if (status != 0) {
02411                         /* Try again with td */
02412                         StrAppend(&o_zone, ".");
02413                         status = KsmZoneIdFromName(o_zone, &zone_id);
02414                         if (status != 0) {
02415                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
02416                                 db_disconnect(lock_fd);
02417                                 StrFree(datetime);
02418                                 return(status);
02419                         }
02420         }
02421     }
02422 
02423     /* Check the keytag is numeric */
02424     if (o_keytag != NULL) {
02425         if (StrIsDigits(o_keytag)) {
02426             status = StrStrtoi(o_keytag, &keytag_int);
02427             if (status != 0) {
02428                 printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag);
02429                 db_disconnect(lock_fd);
02430                 StrFree(datetime);
02431                 return(status);
02432             }
02433         } else {
02434             printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag);
02435             db_disconnect(lock_fd);
02436             StrFree(datetime);
02437             return(1);
02438         }
02439     }
02440 
02441     if (o_keytag == NULL && o_cka_id == NULL) {
02442         /* We will retire the oldest key if there are 2 or more active keys */
02443         if (o_zone == NULL) {
02444             printf("Please provide a zone or details of the key to roll\n");
02445             usage_keykskretire();
02446             db_disconnect(lock_fd);
02447             StrFree(datetime);
02448             return(-1);
02449         }
02450 
02451         status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
02452         if (status != 0) {
02453             printf("Error: failed to count active keys\n");
02454             db_disconnect(lock_fd);
02455             StrFree(datetime);
02456             return status;
02457         }
02458 
02459         /* If there are not at least 2 active keys then quit */
02460         if (key_count < 2) {
02461             printf("Error: completing this action would leave no active keys on zone, quitting...\n");
02462             db_disconnect(lock_fd);
02463             StrFree(datetime);
02464             return -1;
02465         }
02466 
02467         /* We will need a policy id for the next bit */
02468         status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
02469         if (status != 0) {
02470             printf("Error: failed to find policy for zone\n");
02471             db_disconnect(lock_fd);
02472             StrFree(datetime);
02473             return status;
02474         }
02475 
02476         status = RetireOldKey(zone_id, policy_id, datetime);
02477 
02478         if (status == 0) {
02479             printf("Old key retired\n");
02480         } else {
02481             printf("Old key NOT retired\n");
02482         }
02483     } else {
02484 
02485         /* 
02486          * Get a count of keys that match our specifiers, will also print out
02487          * matching keys; note that zone_id may be overwritten
02488          */
02489         status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id);
02490         if (status != 0) {
02491             printf("Error: failed to count keys\n");
02492             db_disconnect(lock_fd);
02493             StrFree(datetime);
02494             return status;
02495         }
02496 
02497         /* If the keycount is more than 1 then display the cka_ids of the keys */
02498         if (key_count > 1) {
02499             printf("More than one key matched your parameters, please include more information from the above keys\n");
02500             db_disconnect(lock_fd);
02501             StrFree(datetime);
02502             return -1;
02503         }
02504 
02505         /* If the keycount is 0 or the key is not ACTIVE then write a message and exit */
02506         if (key_count == 0 || temp_key_state != KSM_STATE_ACTIVE) {
02507             printf("No keys in the ACTIVE state matched your parameters, please check the parameters\n");
02508             db_disconnect(lock_fd);
02509             StrFree(datetime);
02510             return -1;
02511         }
02512 
02513         status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
02514         if (status != 0) {
02515             printf("Error: failed to count active keys\n");
02516             db_disconnect(lock_fd);
02517             StrFree(datetime);
02518             return status;
02519         }
02520 
02521         /* If there are not at least 2 active keys then quit */
02522         if (key_count < 2) {
02523             printf("Error: completing this action would leave no active keys on zone, quitting...\n");
02524             db_disconnect(lock_fd);
02525             StrFree(datetime);
02526             return -1;
02527         }
02528 
02529         /* We will need a policy id for the next bit */
02530         status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
02531         if (status != 0) {
02532             printf("Error: failed to find policy for zone\n");
02533             db_disconnect(lock_fd);
02534             StrFree(datetime);
02535             return status;
02536         }
02537 
02538         /* Retire the key */
02539         status = ChangeKeyState(KSM_TYPE_KSK, temp_cka_id, zone_id, policy_id, datetime, KSM_STATE_RETIRE);
02540 
02541         /* Let them know that it seemed to work */
02542         if (status == 0) {
02543             printf("Key %s retired\n", temp_cka_id);
02544         }
02545     }
02546 
02547     /* Release sqlite lock file (if we have it) */
02548     db_disconnect(lock_fd);
02549 
02550     DbDisconnect(dbhandle);
02551 
02552     StrFree(datetime);
02553     
02554     return status;
02555 }
02556 
02557 /*
02558  * DS Seen
02559        mark key as having had its DS published
02560        i.e. change its state to ACTIVE and set the time
02561             also set the time at which it will go to RETIRED
02562  */
02563     int
02564 cmd_dsseen()
02565 {
02566     int status = 0;
02567     int zone_id = -1;
02568     int policy_id = -1;
02569     int key_count = -1;
02570     int retired_count = -1;
02571     int keytag_int = -1;
02572     int temp_key_state = -1;
02573     int temp_keypair_id = -1;
02574     char* temp_cka_id = NULL; /* This will be set if we find a single matching key */
02575     int user_certain;           /* Continue ? */
02576 
02577     /* Database connection details */
02578     DB_HANDLE   dbhandle;
02579     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02580 
02581     char logmsg[256]; /* For the message that we log when a key moves */
02582 
02583     char*   datetime = DtParseDateTimeString("now");
02584 
02585     /* Check datetime in case it came back NULL */
02586     if (datetime == NULL) {
02587         printf("Couldn't turn \"now\" into a date, quitting...\n");
02588         StrFree(datetime);
02589         exit(1);
02590     }
02591 
02592     /* Check that we have either a keytag or a cka_id */
02593     if (o_keytag == NULL && o_cka_id == NULL) {
02594         printf("Please provide a keytag or a CKA_ID for the key (CKA_ID will be used if both are provided\n");
02595         usage_keydsseen();
02596         StrFree(datetime);
02597         return(-1);
02598     }
02599 
02600     /* Warn and confirm that they realise this will retire the old key */
02601     if (0) {
02602         printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] ");
02603 
02604         user_certain = getchar();
02605         if (user_certain != 'y' && user_certain != 'Y') {
02606             printf("Okay, quitting...\n");
02607             exit(0);
02608         }
02609     }
02610     /* try to connect to the database */
02611     status = db_connect(&dbhandle, &lock_fd, 1);
02612     if (status != 0) {
02613         printf("Failed to connect to database\n");
02614         db_disconnect(lock_fd);
02615         StrFree(datetime);
02616         return(1);
02617     }
02618 
02619     /* Turn zone name into an id (if provided) */
02620     /* TODO sort out all flag */
02621     /*if (o_zone == NULL && !all_flag) {
02622         printf("Please specify a zone or use the --all flag to indicate all zones using this key\n");*/
02623     if (o_zone == NULL) {
02624         printf("Please specify a zone using the --zone flag\n");
02625         usage_keydsseen();
02626         StrFree(datetime);
02627         db_disconnect(lock_fd);
02628         return(-1);
02629     } 
02630         else if (o_zone != NULL) {
02631                 status = KsmZoneIdFromName(o_zone, &zone_id);
02632                 if (status != 0) {
02633                         /* Try again with td */
02634                         StrAppend(&o_zone, ".");
02635                         status = KsmZoneIdFromName(o_zone, &zone_id);
02636                         if (status != 0) {
02637                                 printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
02638                                 db_disconnect(lock_fd);
02639                                 StrFree(datetime);
02640                                 return(status);
02641                         }
02642                 }
02643         }
02644     else if (all_flag) {
02645         printf("*WARNING* This will act on every zone where this key is in use; are you sure? [y/N] ");
02646 
02647         user_certain = getchar();
02648         if (user_certain != 'y' && user_certain != 'Y') {
02649             printf("Okay, quitting...\n");
02650             exit(0);
02651         }
02652         
02653         zone_id = -1;
02654     }
02655 
02656     /* Check the keytag is numeric */
02657     if (o_keytag != NULL) {
02658         if (StrIsDigits(o_keytag)) {
02659             status = StrStrtoi(o_keytag, &keytag_int);
02660             if (status != 0) {
02661                 printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag);
02662                 db_disconnect(lock_fd);
02663                 StrFree(datetime);
02664                 return(status);
02665             }
02666         } else {
02667             printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag);
02668             db_disconnect(lock_fd);
02669             StrFree(datetime);
02670             return(1);
02671         }
02672     }
02673 
02674     /* 
02675      * Get a count of keys that match our specifiers, will also print out
02676      * matching keys; note that zone_id may be overwritten
02677      */
02678     status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id);
02679     if (status != 0) {
02680         printf("Error: failed to count keys\n");
02681         db_disconnect(lock_fd);
02682         StrFree(datetime);
02683         return status;
02684     }
02685 
02686     /* If the keycount is more than 1 then display the cka_ids of the keys */
02687     if (key_count > 1) {
02688         printf("More than one key matched your parameters, please include more information from the above keys\n");
02689         db_disconnect(lock_fd);
02690         StrFree(datetime);
02691         return -1;
02692     }
02693 
02694     /* If the key is already active then write a message and exit */
02695     if (temp_key_state == KSM_STATE_ACTIVE) {
02696         printf("Key is already active\n");
02697         db_disconnect(lock_fd);
02698         StrFree(datetime);
02699         return -1;
02700     }
02701 
02702     /* If the keycount is 0 then write a message and exit */
02703     if (key_count == 0) {
02704         printf("No keys in the READY state matched your parameters, please check the parameters\n");
02705         db_disconnect(lock_fd);
02706         StrFree(datetime);
02707         return -1;
02708     }
02709 
02710     /* We will need a policy id for the next bit */
02711     status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
02712     if (status != 0) {
02713         printf("Error: failed to find policy for zone\n");
02714         db_disconnect(lock_fd);
02715         StrFree(datetime);
02716         return status;
02717     }
02718 
02719     /* Do stuff */
02720     status = MarkDSSeen(temp_keypair_id, zone_id, policy_id, datetime, temp_key_state);
02721 
02722     /* Let them know that it seemed to work */
02723     if (status == 0) {
02724         snprintf(logmsg, 256, "Key %s made %s", temp_cka_id, (temp_key_state == KSM_STATE_READY) ? "active" : "into standby");
02725         printf("%s\n", logmsg);
02726         
02727         /* send the msg to syslog */
02728         openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY);
02729         syslog(LOG_INFO, "%s", logmsg);
02730         closelog();
02731         
02732     }
02733 
02734     /* Retire old key, unless asked not to */
02735     if (temp_key_state == KSM_STATE_READY) {
02736         if (retire_flag == 1) {
02737 
02738             /* We will retire the oldest key if there are 2 or more active keys */
02739             status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
02740             if (status != 0) {
02741                 printf("Error: failed to count active keys\n");
02742                 db_disconnect(lock_fd);
02743                 StrFree(datetime);
02744                 return status;
02745             }
02746 
02747             /* If there are not at least 2 active keys then quit */
02748             if (key_count < 2) {
02749                 /* Count retired keys to work out if this is a new zone */
02750                 /* TODO MAKE SURE THIS IS RIGHT !!! */
02751                 status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_RETIRE, &retired_count, zone_id);
02752                 if (status != 0) {
02753                     printf("Error: failed to count retired keys\n");
02754                     db_disconnect(lock_fd);
02755                     StrFree(datetime);
02756                     return status;
02757                 }
02758 
02759                                 /* Cleanup and print an error message... */
02760                 db_disconnect(lock_fd);
02761                 StrFree(datetime);
02762                 if (retired_count != 0) {
02763                     printf("Error: retiring a key would leave no active keys on zone, skipping...\n");
02764                                         return -1;
02765                 } else {
02766                                         /* ...Unless this looks like a new zone, in which case poke
02767                                            the enforcerd */
02768                                         if (restart_enforcerd() != 0)
02769                                         {
02770                                                 fprintf(stderr, "Could not HUP ods-enforcerd\n");
02771                                         }
02772                                         return 0;
02773                                 }
02774             }
02775 
02776             status = RetireOldKey(zone_id, policy_id, datetime);
02777 
02778             /* Let them know that it seemed to work */
02779             if (status == 0) {
02780                 printf("Old key retired\n");
02781             } else {
02782                 printf("Old key NOT retired\n");
02783             }
02784         } else {
02785             printf("Old key NOT retired\n");
02786         }
02787     }
02788 
02789     /* Need to poke the enforcer to wake it up */
02790     if (restart_enforcerd() != 0)
02791     {
02792         fprintf(stderr, "Could not HUP ods-enforcerd\n");
02793     }
02794 
02795     /* Release sqlite lock file (if we have it) */
02796     db_disconnect(lock_fd);
02797 
02798     DbDisconnect(dbhandle);
02799 
02800     StrFree(datetime);
02801     
02802     return status;
02803 }
02804 
02805 /*
02806  * import a key into the ksm and set its values as specified
02807  */
02808     int
02809 cmd_import ()
02810 {
02811     int status = 0;
02812 
02813     /* some strings to hold upper case versions of arguments */
02814     char* case_keytype = NULL;    /* KSK or ZSK */
02815     char* case_algorithm = NULL;  /* RSASHA1 or RSASHA1-NSEC3-SHA1 (5 or 7) */
02816     char* case_state = NULL;      /* GENERATE, PUBLISH, READY, ACTIVE or RETIRE */
02817 
02818     int repo_id = -1;
02819     int zone_id = -1;
02820     int policy_id = -1;
02821     int cka_id_exists = -1; /* do we already have this id in the HSM */
02822     int keytype_id = -1;
02823     int size_int = -1;
02824     int algo_id = -1;
02825     int state_id = -1;
02826     char form_time[KSM_TIME_LENGTH]; /* YYYY-MM-DD HH:MM:SS + NULL Time after we reformat it */
02827     char form_opt_time[KSM_TIME_LENGTH]; /* Opt_time after we reformat it */
02828 
02829     DB_ID   keypair_id = 0;    /* This will be set when we enter the keypair */
02830     DB_ID   ignore = 0;        /* This will be set when we enter the dnsseckey */
02831 
02832     struct tm   datetime;       /* Used for getting the date/time */
02833 
02834         int fix_time = 0;       /* Will we be setting the retire time? */
02835 
02836     /* Database connection details */
02837     DB_HANDLE   dbhandle;
02838     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
02839 
02840     DB_RESULT   result;         /* Result of parameter query */
02841     KSM_PARAMETER data;         /* Parameter information */
02842 
02843     int user_certain;           /* Continue ? */
02844 
02845     /* Chech that we got all arguments. */
02846 
02847     if (o_cka_id == NULL) {
02848         printf("Error: please specify a CKA_ID with the --cka_id <CKA_ID>\n");
02849         return(1);
02850     }
02851     if (o_repository == NULL) {
02852         printf("Error: please specify a repository with the --repository <repository>\n");
02853         return(1);
02854     }
02855     if (o_zone == NULL) {
02856         printf("Error: please specify a zone with the --zone <zone>\n");
02857         return(1);
02858     }
02859     if (o_size == NULL) {
02860         printf("Error: please specify the number of bits with the --bits <size>\n");
02861         return(1);
02862     }
02863     if (o_algo == NULL) {
02864         printf("Error: please specify the algorithm with the --algorithm <algorithm>\n");
02865         return(1);
02866     }
02867     if (o_keystate == NULL) {
02868         printf("Error: please specify the state with the --keystate <state>\n");
02869         return(1);
02870     }
02871     if (o_keytype == NULL) {
02872         printf("Error: please specify a keytype, KSK or ZSK, with the --keytype <type>\n");
02873         return(1);
02874     }
02875     if (o_time == NULL) {
02876         printf("Error: please specify the time of when the key entered the given state with the --time <time>\n");
02877         return(1);
02878     }
02879 
02880     /* try to connect to the database */
02881     status = db_connect(&dbhandle, &lock_fd, 1);
02882     if (status != 0) {
02883         printf("Failed to connect to database\n");
02884         db_disconnect(lock_fd);
02885         return(1);
02886     }
02887 
02888     /* check that the repository exists */
02889     status = KsmSmIdFromName(o_repository, &repo_id);
02890     if (status != 0) {
02891         printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
02892         db_disconnect(lock_fd);
02893         return status;
02894     }
02895 
02896     /* check that the zone name is valid and use it to get some ids */
02897         status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
02898         if (status != 0) {
02899                 /* Try again with td */
02900                 StrAppend(&o_zone, ".");
02901                 status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
02902                 if (status != 0) {
02903                         printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
02904                         db_disconnect(lock_fd);
02905                         return(status);
02906                 }
02907         }
02908 
02909     /* Check that the cka_id does not exist (in the specified HSM) */
02910     status = (KsmCheckHSMkeyID(repo_id, o_cka_id, &cka_id_exists));
02911     if (status != 0) {
02912         db_disconnect(lock_fd);
02913         return(status);
02914     }
02915     if (cka_id_exists == 1) {
02916         printf("Error: key with CKA_ID \"%s\" already exists in database\n", o_cka_id);
02917         db_disconnect(lock_fd);
02918         return(1);
02919     }
02920 
02921     /* Check the Keytype */
02922     case_keytype = StrStrdup(o_keytype);
02923     (void) StrToUpper(case_keytype);
02924     if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) {
02925         keytype_id = 257;
02926     }
02927     else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) {
02928         keytype_id = 256;
02929     }
02930     else {
02931         printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype);
02932 
02933         db_disconnect(lock_fd);
02934         StrFree(case_keytype);
02935         return(1);
02936     }
02937     StrFree(case_keytype);
02938         
02939     /* Check the size is numeric */
02940     if (StrIsDigits(o_size)) {
02941         status = StrStrtoi(o_size, &size_int);
02942         if (status != 0) {
02943             printf("Error: Unable to convert bits \"%s\"; to an integer\n", o_size);
02944             db_disconnect(lock_fd);
02945             return(status);
02946         }
02947     } else {
02948         printf("Error: Bits \"%s\"; should be numeric only\n", o_size);
02949         db_disconnect(lock_fd);
02950         return(1);
02951     }
02952         
02953     /* Check the algorithm */
02954     if (StrIsDigits(o_algo)) {
02955         /* Accept it as-is; The HSM will tell us if the number is not valid */
02956         status = StrStrtoi(o_algo, &algo_id);
02957     } else {
02958         /* Convert name to an id, we get 0 if it is unrecognised */
02959         case_algorithm = StrStrdup(o_algo);
02960         (void) StrToLower(case_algorithm);
02961 
02962         algo_id = KsmKeywordAlgorithmNameToValue(case_algorithm);
02963         StrFree(case_algorithm);
02964     }
02965 
02966     if (status != 0 || algo_id == 0 || hsm_supported_algorithm(algo_id) != 0) {
02967         printf("Error: Key algorithm %s not supported; try one of RSASHA1, RSASHA1-NSEC3-SHA1 or RSASHA256\n", o_algo);
02968         db_disconnect(lock_fd);
02969         return(status);
02970     }
02971 
02972     /* Check the state */
02973     case_state = StrStrdup(o_keystate);
02974     (void) StrToUpper(case_state);
02975     if (strncmp(case_state, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) {
02976         state_id = 1;
02977     }
02978     else if (strncmp(case_state, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) {
02979         state_id = 2;
02980     }
02981     else if (strncmp(case_state, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) {
02982         state_id = 3;
02983     }
02984     else if (strncmp(case_state, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) {
02985         state_id = 4;
02986     }
02987     else if (strncmp(case_state, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) {
02988         state_id = 5;
02989     }
02990     else {
02991         printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE or RETIRE\n", o_keystate);
02992 
02993         db_disconnect(lock_fd);
02994         StrFree(case_state);
02995         return(1);
02996     }
02997     StrFree(case_state);
02998 
02999     /* Check, and convert, the time(s) */
03000     status = DtGeneral(o_time, &datetime);
03001     if (status != 0) {
03002         printf("Error: unable to convert \"%s\" into a date\n", o_time);
03003         date_help();
03004 
03005         db_disconnect(lock_fd);
03006         return(status);
03007     }
03008     else {
03009         snprintf(form_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
03010             datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday,
03011             datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
03012     }
03013 
03014     if (o_retire != NULL) {
03015         /* can only specify a retire time if the key is being inserted in the active state */
03016         if (state_id != KSM_STATE_ACTIVE) {
03017             printf("Error: unable to specify retire time for a key in state \"%s\"\n", o_keystate);
03018             db_disconnect(lock_fd);
03019             return(status);
03020         }
03021 
03022         status = DtGeneral(o_retire, &datetime);
03023         if (status != 0) {
03024             printf("Error: unable to convert retire time \"%s\" into a date\n", o_retire);
03025             date_help();
03026 
03027             db_disconnect(lock_fd);
03028             return(status);
03029         }
03030         else {
03031             snprintf(form_opt_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
03032                     datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday,
03033                     datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
03034                         fix_time = 1;
03035         }
03036     } else {
03037         form_opt_time[0] = '\0';
03038     }
03039 
03040     /* Find out if this zone has any others on a "shared keys" policy and warn */
03041     status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
03042     if (status != 0) {
03043         db_disconnect(lock_fd);
03044         return(status);
03045     }
03046     status = KsmParameter(result, &data);
03047     if (status != 0) {
03048         db_disconnect(lock_fd);
03049         return(status);
03050     }
03051     KsmParameterEnd(result);
03052     
03053     /* Warn and confirm if this will roll more than one zone */
03054     if (data.value == 1) {
03055         printf("*WARNING* This zone shares keys with others, the key will be added to all; are you sure? [y/N] ");
03056 
03057         user_certain = getchar();
03058         if (user_certain != 'y' && user_certain != 'Y') {
03059             printf("Okay, quitting...\n");
03060             db_disconnect(lock_fd);
03061             exit(0);
03062         }
03063     }
03064 
03065     /* create basic keypair */
03066     status = KsmImportKeyPair(policy_id, o_cka_id, repo_id, size_int, algo_id, state_id, form_time, fix_time, &keypair_id);
03067     if (status != 0) {
03068         printf("Error: couldn't import key\n");
03069         db_disconnect(lock_fd);
03070         return(status);
03071     }
03072 
03073     /* allocate key to zone(s) */
03074     /* TODO might not need this any more */
03075 /*    if (data.value == 1) {
03076         status = KsmDnssecKeyCreateOnPolicy(policy_id, (int) keypair_id, keytype_id);
03077     } else {*/
03078     status = KsmDnssecKeyCreate(zone_id, (int) keypair_id, keytype_id, state_id, form_time, form_opt_time, &ignore);
03079 
03080     if (status != 0) {
03081         printf("Error: couldn't allocate key to zone(s)\n");
03082         db_disconnect(lock_fd);
03083         return(status);
03084     }
03085 
03086     printf("Key imported into zone(s)\n");
03087 
03088     /* Release sqlite lock file (if we have it) */
03089     db_disconnect(lock_fd);
03090 
03091     DbDisconnect(dbhandle);
03092     return 0;
03093 }
03094 
03095 /*
03096  * make a backup of a sqlite database
03097  */
03098     int
03099 cmd_dbbackup ()
03100 {
03101     /* Database details */
03102     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
03103 
03104     /* what we will read from the file */
03105     char *dbschema = NULL;
03106     char *host = NULL;
03107     char *port = NULL;
03108     char *user = NULL;
03109     char *password = NULL;
03110 
03111     int status;
03112 
03113     char* backup_filename = NULL;
03114     char* lock_filename;
03115 
03116     char *path = getenv("PWD");
03117 
03118     if (DbFlavour() != SQLITE_DB) {
03119         printf("Sorry, currently this utility can only backup a sqlite database file\n");
03120         return -1;
03121     }
03122 
03123     /* Read the database details out of conf.xml */
03124     status = get_db_details(&dbschema, &host, &port, &user, &password);
03125     if (status != 0) {
03126         StrFree(host);
03127         StrFree(port);
03128         StrFree(dbschema);
03129         StrFree(user);
03130         StrFree(password);
03131         return(status);
03132     }
03133 
03134     /* set up DB lock */
03135     lock_filename = NULL;
03136     StrAppend(&lock_filename, dbschema);
03137     StrAppend(&lock_filename, ".our_lock");
03138 
03139     lock_fd = fopen(lock_filename, "w");
03140     status = get_lite_lock(lock_filename, lock_fd);
03141     if (status != 0) {
03142         printf("Error getting db lock\n");
03143         if (lock_fd != NULL) {
03144             fclose(lock_fd);
03145         }
03146         StrFree(host);
03147         StrFree(port);
03148         StrFree(dbschema);
03149         StrFree(user);
03150         StrFree(password);
03151         return(1);
03152     }
03153     StrFree(lock_filename);
03154 
03155     /* Work out what file to output */
03156     if (o_output == NULL) {
03157         StrAppend(&backup_filename, dbschema);
03158         StrAppend(&backup_filename, ".backup");
03159     } else if (*o_output != '/') {
03160         StrAppend(&backup_filename, path);
03161         StrAppend(&backup_filename, "/");
03162         StrAppend(&backup_filename, o_output);
03163     } else {
03164         StrAppend(&backup_filename, o_output);
03165     }
03166 
03167     status = backup_file(dbschema, backup_filename);
03168 
03169     StrFree(backup_filename);
03170 
03171     /* Cleanup */
03172     StrFree(host);
03173     StrFree(port);
03174     StrFree(dbschema);
03175     StrFree(user);
03176     StrFree(password);
03177 
03178     /* Release sqlite lock */
03179     db_disconnect(lock_fd);
03180 
03181     return status;
03182 }
03183 
03184 /*
03185  * Delete any policies with no zones 
03186  */
03187     int 
03188 cmd_purgepolicy ()
03189 {
03190     int status = 0;
03191 
03192     char* kasp_filename = NULL;
03193     char* zonelist_filename = NULL;
03194     char* backup_filename = NULL;
03195 
03196     DB_HANDLE   dbhandle;
03197     FILE* lock_fd = NULL;
03198     KSM_POLICY *policy;
03199     DB_RESULT   result;     /* Result set from policy query */
03200     DB_RESULT   result2;    /* Result set from zone count query */
03201     char        sql[KSM_SQL_SIZE];
03202     int         size = -1;
03203     char* sql2;
03204 
03205     FILE *test;
03206     int zone_count = -1;
03207 
03208     xmlDocPtr doc = NULL;
03209     
03210     int user_certain;
03211     printf("*WARNING* This feature is experimental and has not been fully tested; are you sure? [y/N] ");
03212 
03213     user_certain = getchar();
03214     if (user_certain != 'y' && user_certain != 'Y') {
03215         printf("Okay, quitting...\n");
03216         exit(0);
03217     }
03218 
03219     /* Read the conf.xml file to learn the location of the kasp.xml file. */
03220     status = read_filenames(&zonelist_filename, &kasp_filename);
03221     if (status != 0) {
03222         printf("Failed to read conf.xml\n");
03223         db_disconnect(lock_fd);
03224         return(1);
03225     }
03226 
03227     /* Backup the current kasp.xml */
03228     StrAppend(&backup_filename, kasp_filename);
03229     StrAppend(&backup_filename, ".backup");
03230     status = backup_file(kasp_filename, backup_filename);
03231     StrFree(backup_filename);
03232     if (status != 0) {
03233         StrFree(kasp_filename);
03234         db_disconnect(lock_fd);
03235         return(status);
03236     }
03237 
03238     /* Check that we will be able to make the changes to kasp.xml */
03239     if ((test = fopen(kasp_filename, "ab"))==NULL) {
03240         printf("Cannot open kasp.xml for writing: %s\n", strerror(errno));
03241         return(-1);
03242     } else {
03243         fclose(test);
03244     }
03245 
03246     /* try to connect to the database */
03247     status = db_connect(&dbhandle, &lock_fd, 1);
03248     if (status != 0) {
03249         printf("Failed to connect to database\n");
03250         db_disconnect(lock_fd);
03251         return(1);
03252     }
03253 
03254     /* Start a transaction */
03255     status = DbBeginTransaction();
03256     if (status != 0) {
03257         /* Something went wrong */
03258 
03259         MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
03260         db_disconnect(lock_fd);
03261         return status;
03262     }
03263 
03264     /* Loop through each policy */
03265     policy = KsmPolicyAlloc();
03266     if (policy == NULL) {
03267         printf("Malloc for policy struct failed\n");
03268         exit(1);
03269     }
03270 
03271     /* Read all policies */
03272     status = KsmPolicyInit(&result, NULL);
03273     if (status == 0) {
03274         /* get the first policy */
03275         status = KsmPolicy(result, policy);
03276         while (status == 0) {
03277             /* Count zones on this policy */
03278             status = KsmZoneCountInit(&result2, policy->id); 
03279             if (status == 0) { 
03280                 status = KsmZoneCount(result2, &zone_count); 
03281             } 
03282             DbFreeResult(result2); 
03283 
03284             if (status == 0) { 
03285                 /* Only carry on if we have no zones */
03286                 if (zone_count == 0) {
03287                     printf("No zones on policy %s; purging...\n", policy->name);
03288                     /* set keystate to 6 across the board */
03289                     size = snprintf(sql, KSM_SQL_SIZE, "update dnsseckeys set state = %d where keypair_id in (select id from keypairs where policy_id = %d)", KSM_STATE_DEAD, policy->id);
03290 
03291                     /* Quick check that we didn't run out of space */
03292                     if (size < 0 || size >= KSM_SQL_SIZE) {
03293                         printf("Couldn't construct SQL to kill orphaned keys\n");
03294                         db_disconnect(lock_fd);
03295                         KsmPolicyFree(policy);
03296                         return -1;
03297                     }
03298 
03299                     status = DbExecuteSqlNoResult(DbHandle(), sql);
03300 
03301                     /* Report any errors */
03302                     if (status != 0) {
03303                         printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
03304                         db_disconnect(lock_fd);
03305                         KsmPolicyFree(policy);
03306                         return status;
03307                     }
03308 
03309                     /* call purge keys on that policy (all zones) */
03310                     status = PurgeKeys(-1, policy->id);
03311                     if (status != 0) {
03312                         printf("Key purge failed for policy %s\n", policy->name);
03313                         db_disconnect(lock_fd);
03314                         KsmPolicyFree(policy);
03315                         return status;
03316                     }
03317 
03318                     /* Delete the policy from DB */
03319                     sql2 = DdsInit("parameters_policies");
03320                     DdsConditionInt(&sql2, "policy_id", DQS_COMPARE_EQ,  policy->id, 0); 
03321                     DdsEnd(&sql2); 
03322                     status = DbExecuteSqlNoResult(DbHandle(), sql2); 
03323                     DdsFree(sql2); 
03324 
03325                     if (status != 0) 
03326                     { 
03327                         printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
03328                         db_disconnect(lock_fd);
03329                         KsmPolicyFree(policy);
03330                         return status; 
03331                     }
03332 
03333                     sql2 = DdsInit("policies"); 
03334                     DdsConditionInt(&sql2, "id", DQS_COMPARE_EQ,  policy->id, 0); 
03335                     DdsEnd(&sql2); 
03336                     status = DbExecuteSqlNoResult(DbHandle(), sql2); 
03337                     DdsFree(sql2); 
03338 
03339                     if (status != 0) 
03340                     { 
03341                         printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
03342                         db_disconnect(lock_fd);
03343                         KsmPolicyFree(policy);
03344                         return status; 
03345                     }
03346 
03347                     /* Delete the policy from the XML */
03348                     /* Read the file and delete our policy node(s) in memory */
03349                     doc = del_policy_node(kasp_filename, policy->name);
03350                     if (doc == NULL) {
03351                         db_disconnect(lock_fd);
03352                         KsmPolicyFree(policy);
03353                         StrFree(kasp_filename);
03354                         return(1);
03355                     }
03356 
03357                     /* Save our new file over the old, TODO should we validate it first? */
03358                     status = xmlSaveFormatFile(kasp_filename, doc, 1);
03359                     xmlFreeDoc(doc);
03360                     if (status == -1) {
03361                         printf("Could not save %s\n", kasp_filename);
03362                         StrFree(kasp_filename);
03363                         db_disconnect(lock_fd);
03364                         KsmPolicyFree(policy);
03365                         return(1);
03366                     }
03367 
03368                 } 
03369             } else { 
03370                 printf("Couldn't count zones on policy; quitting...\n");
03371                 db_disconnect(lock_fd);
03372                 exit(1); 
03373             }
03374 
03375             /* get next policy */
03376             status = KsmPolicy(result, policy);
03377         }
03378         /* Reset EOF */
03379         if (status == -1) {
03380             status = 0;
03381         }
03382         DbFreeResult(result);
03383     }
03384 
03385     /* Commit or Rollback */
03386     if (status == 0) {
03387         /* Everything worked by the looks of it */
03388         DbCommit();
03389     } else {
03390         /* Whatever happened, it was not good */
03391         DbRollback();
03392     }
03393 
03394     StrFree(kasp_filename);
03395     db_disconnect(lock_fd);
03396     KsmPolicyFree(policy);
03397     return status;
03398 }
03399 
03400 /*
03401  * Send command to ods-control
03402  */
03403     int 
03404 cmd_control(char *command)
03405 {
03406     int status = 0;
03407     char* ods_control_cmd = NULL;
03408     char* ptr = command;
03409 
03410     /* We need the command in lower case */
03411     if (ptr) {
03412         while (*ptr) {
03413             *ptr = tolower((int) *ptr);
03414             ++ptr;
03415         }
03416     }
03417 
03418     /* Call "ods-control enforcer COMMAND" */
03419     StrAppend(&ods_control_cmd, ODS_EN_CONTROL);
03420     StrAppend(&ods_control_cmd, command);
03421 
03422     status = system(ods_control_cmd);
03423     if (status != 0)
03424     {
03425         fprintf(stderr, "Couldn't run %s\n", ods_control_cmd);
03426     }
03427 
03428     StrFree(ods_control_cmd);
03429 
03430     return(status);
03431 }
03432 
03433 /* 
03434  * Fairly basic main, just pass most things through to their handlers
03435  */
03436     int
03437 main (int argc, char *argv[])
03438 {
03439     int result;
03440     int ch;
03441     char* case_command = NULL;
03442     char* case_verb = NULL;
03443 
03444     int option_index = 0;
03445     static struct option long_options[] =
03446     {
03447         {"all",     no_argument,       0, 'a'},
03448         {"bits",    required_argument, 0, 'b'},
03449         {"config",  required_argument, 0, 'c'},
03450         {"ds",      no_argument,       0, 'd'},
03451         {"keystate", required_argument, 0, 'e'},
03452         {"no-retire", no_argument,       0, 'f'},
03453         {"algorithm", required_argument, 0, 'g'},
03454         {"help",    no_argument,       0, 'h'},
03455         {"input",   required_argument, 0, 'i'},
03456         {"cka_id",  required_argument, 0, 'k'},
03457         {"no-xml",  no_argument,        0, 'm'},
03458         {"interval",  required_argument, 0, 'n'},
03459         {"output",  required_argument, 0, 'o'},
03460         {"policy",  required_argument, 0, 'p'},
03461         {"repository",  required_argument, 0, 'r'},
03462         {"signerconf",  required_argument, 0, 's'},
03463         {"keytype", required_argument, 0, 't'},
03464         {"time",    required_argument, 0, 'w'},
03465         {"verbose", no_argument,       0, 'v'},
03466         {"version", no_argument,       0, 'V'},
03467         {"keytag",  required_argument, 0, 'x'},
03468         {"retire",  required_argument, 0, 'y'},
03469         {"zone",    required_argument, 0, 'z'},
03470         {0,0,0,0}
03471     };
03472 
03473     progname = argv[0];
03474 
03475     while ((ch = getopt_long(argc, argv, "ab:c:de:fg:hi:k:n:o:p:r:s:t:vVw:x:y:z:", long_options, &option_index)) != -1) {
03476         switch (ch) {
03477             case 'a':
03478                 all_flag = 1;
03479                 break;
03480             case 'b':
03481                 o_size = StrStrdup(optarg);
03482                 break;
03483             case 'c':
03484                 config = StrStrdup(optarg);
03485                 break;
03486             case 'd':
03487                 ds_flag = 1;
03488                 break;
03489             case 'e':
03490                 o_keystate = StrStrdup(optarg);
03491                 break;
03492             case 'f':
03493                 retire_flag = 0;
03494                 break;
03495             case 'g':
03496                 o_algo = StrStrdup(optarg);
03497                 break;
03498             case 'h':
03499                 usage();
03500                 states_help();
03501                 types_help();
03502                 date_help();
03503                 exit(0);
03504                 break;
03505             case 'i':
03506                 o_input = StrStrdup(optarg);
03507                 break;
03508             case 'k':
03509                 o_cka_id = StrStrdup(optarg);
03510                 break;
03511             case 'm':
03512                 xml_flag = 0;
03513                 break;
03514             case 'n':
03515                 o_interval = StrStrdup(optarg);
03516                 break;
03517             case 'o':
03518                 o_output = StrStrdup(optarg);
03519                 break;
03520             case 'p':
03521                 o_policy = StrStrdup(optarg);
03522                 break;
03523             case 'r':
03524                 o_repository = StrStrdup(optarg);
03525                 break;
03526             case 's':
03527                 o_signerconf = StrStrdup(optarg);
03528                 break;
03529             case 't':
03530                 o_keytype = StrStrdup(optarg);
03531                 break;
03532             case 'V':
03533                 printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
03534                 exit(0);
03535                 break;
03536             case 'v':
03537                 verbose_flag = 1;
03538                 break;
03539             case 'w':
03540                 o_time = StrStrdup(optarg);
03541                 break;
03542             case 'x':
03543                 o_keytag = StrStrdup(optarg);
03544                 break;
03545             case 'y':
03546                 o_retire = StrStrdup(optarg);
03547                 break;
03548             case 'z':
03549                                 /* Remove trailing dot here */
03550                 o_zone = StrStrdup(optarg);
03551                                 if (strlen(o_zone) > 1 && o_zone[strlen(o_zone)-1] == '.') {
03552                                         o_zone[strlen(o_zone)-1] = '\0';
03553                                         td_flag = 1;
03554                                 }
03555 
03556                 break;
03557             default:
03558                 usage();
03559                 exit(1);
03560         }
03561     }
03562     argc -= optind;
03563     argv += optind;
03564 
03565     if (!argc) {
03566         usage();
03567         exit(1);
03568     }
03569 
03570 
03571     /*(void) KsmInit();*/
03572     MsgInit();
03573     MsgRegister(KME_MIN_VALUE, KME_MAX_VALUE, m_messages, ksm_log_msg);
03574     MsgRegister(DBS_MIN_VALUE, DBS_MAX_VALUE, d_messages, ksm_log_msg);
03575 
03576     /* command should be one of SETUP UPDATE ZONE REPOSITORY POLICY KEY BACKUP or ROLLOVER */
03577     case_command = StrStrdup(argv[0]);
03578     (void) StrToUpper(case_command);
03579     if (argc > 1) {
03580         /* verb should be stuff like ADD, LIST, DELETE, etc */
03581         case_verb = StrStrdup(argv[1]);
03582         (void) StrToUpper(case_verb);
03583     } else {
03584         case_verb = StrStrdup("NULL");
03585     }
03586     
03587 
03588     if (!strncmp(case_command, "SETUP", 5)) {
03589         argc --;
03590         argv ++;
03591         result = cmd_setup();
03592     } else if (!strncmp(case_command, "UPDATE", 6)) {
03593         argc --;
03594         argv ++;
03595         result = cmd_update(case_verb);
03596     } else if (!strncmp(case_command, "START", 5) ||
03597                !strncmp(case_command, "STOP", 4) ||
03598                !strncmp(case_command, "NOTIFY", 6)) {
03599         argc --;
03600         argv ++;
03601         result = cmd_control(case_command);
03602     } else if (!strncmp(case_command, "ZONE", 4) && strlen(case_command) == 4) {
03603         argc --; argc --;
03604         argv ++; argv ++;
03605 
03606         /* verb should be add, delete or list */
03607         if (!strncmp(case_verb, "ADD", 3)) {
03608             result = cmd_addzone();
03609         } else if (!strncmp(case_verb, "DELETE", 6)) {
03610             result = cmd_delzone();
03611         } else if (!strncmp(case_verb, "LIST", 4)) {
03612             result = cmd_listzone();
03613         } else {
03614             printf("Unknown command: zone %s\n", case_verb);
03615             usage_zone();
03616             result = -1;
03617         }
03618     } else if (!strncmp(case_command, "REPOSITORY", 10)) {
03619         argc --; argc --;
03620         argv ++; argv ++;
03621         /* verb should be list */
03622         if (!strncmp(case_verb, "LIST", 4)) {
03623             result = cmd_listrepo();
03624         } else {
03625             printf("Unknown command: repository %s\n", case_verb);
03626             usage_repo();
03627             result = -1;
03628         }
03629     } else if (!strncmp(case_command, "POLICY", 6)) {
03630         argc --; argc --;
03631         argv ++; argv ++;
03632         /* verb should be export, import, list or purge */
03633         if (!strncmp(case_verb, "EXPORT", 6)) {
03634             result = cmd_exportpolicy();
03635         } else if (!strncmp(case_verb, "IMPORT", 6)) {
03636             result = cmd_update("KASP");
03637         } else if (!strncmp(case_verb, "LIST", 4)) {
03638             result = cmd_listpolicy();
03639         } else if (!strncmp(case_verb, "PURGE", 5)) {
03640             result = cmd_purgepolicy();
03641         } else {
03642             printf("Unknown command: policy %s\n", case_verb);
03643             usage_policy();
03644             result = -1;
03645         }
03646     } else if (!strncmp(case_command, "KEY", 3)) {
03647         argc --; argc --;
03648         argv ++; argv ++;
03649         /* verb should be list, export import, rollover, purge, generate, ksk-retire or ds-seen */
03650         if (!strncmp(case_verb, "LIST", 4)) {
03651             result = cmd_listkeys();
03652         }
03653         else if (!strncmp(case_verb, "EXPORT", 6)) {
03654             result = cmd_exportkeys();
03655         }
03656         else if (!strncmp(case_verb, "IMPORT", 6)) {
03657             result = cmd_import();
03658         }
03659         else if (!strncmp(case_verb, "ROLLOVER", 8)) {
03660             /* Are we rolling a zone or a whole policy? */
03661             if (o_zone != NULL && o_policy == NULL) {
03662                 result = cmd_rollzone();
03663             }
03664             else if (o_zone == NULL && o_policy != NULL) {
03665                 result = cmd_rollpolicy();
03666             }
03667             else {
03668                 printf("Please provide either a zone OR a policy to rollover\n");
03669                 usage_keyroll();
03670                 result = -1;
03671             }
03672         }
03673         else if (!strncmp(case_verb, "PURGE", 5)) {
03674             if ((o_zone != NULL && o_policy == NULL) || 
03675                     (o_zone == NULL && o_policy != NULL)){
03676                 result = cmd_keypurge();
03677             }
03678             else {
03679                 printf("Please provide either a zone OR a policy to key purge\n");
03680                 usage_keypurge();
03681                 result = -1;
03682             }
03683         }
03684         else if (!strncmp(case_verb, "GENERATE", 8)) {
03685             result = cmd_genkeys();
03686         }
03687         else if (!strncmp(case_verb, "KSK-RETIRE", 10)) {
03688             result = cmd_kskretire();
03689         }
03690         else if (!strncmp(case_verb, "DS-SEEN", 7)) {
03691             result = cmd_dsseen();
03692         } else {
03693             printf("Unknown command: key %s\n", case_verb);
03694             usage_key();
03695             result = -1;
03696         }
03697     } else if (!strncmp(case_command, "BACKUP", 6)) {
03698         argc --; argc --;
03699         argv ++; argv ++;
03700         /* verb should be done, prepare, commit, rollback or list */
03701         if (!strncmp(case_verb, "DONE", 4) ||
03702                 !strncmp(case_verb, "PREPARE", 7) ||
03703                 !strncmp(case_verb, "COMMIT", 6) ||
03704                 !strncmp(case_verb, "ROLLBACK", 8)) {
03705             result = cmd_backup(case_verb);
03706         }
03707         else if (!strncmp(case_verb, "LIST", 4)) {
03708             result = cmd_listbackups();
03709         } else {
03710             printf("Unknown command: backup %s\n", case_verb);
03711             usage_backup();
03712             result = -1;
03713         }
03714     } else if (!strncmp(case_command, "ROLLOVER", 8)) {
03715         argc --; argc --;
03716         argv ++; argv ++;
03717         if (!strncmp(case_verb, "LIST", 4)) {
03718             result = cmd_listrolls();
03719         } else {
03720             printf("Unknown command: rollover %s\n", case_verb);
03721             usage_rollover();
03722             result = -1;
03723         }
03724     } else if (!strncmp(case_command, "DATABASE", 8)) {
03725         argc --; argc --;
03726         argv ++; argv ++;
03727         /* verb should be backup */
03728         if (!strncmp(case_verb, "BACKUP", 6)) {
03729             result = cmd_dbbackup();
03730         } else {
03731             printf("Unknown command: database %s\n", case_verb);
03732             usage_database();
03733             result = -1;
03734         }
03735     } else if (!strncmp(case_command, "ZONELIST", 8)) {
03736         argc --; argc --;
03737         argv ++; argv ++;
03738         /* verb should be import or export */
03739         if (!strncmp(case_verb, "EXPORT", 6)) {
03740             result = cmd_exportzonelist();
03741         }
03742         else if (!strncmp(case_verb, "IMPORT", 6)) {
03743             result = cmd_update("ZONELIST");
03744         } else {
03745             printf("Unknown command: zonelist %s\n", case_verb);
03746             usage_zonelist2();
03747             result = -1;
03748         }
03749     } else {
03750         printf("Unknown command: %s\n", argv[0]);
03751         usage();
03752         result = -1;
03753     }
03754 
03755     StrFree(case_command);
03756     StrFree(case_verb);
03757 
03758     /*(void) hsm_close();*/
03759     /*if (config) free(config);*/
03760 
03761     xmlCleanupParser();
03762     xmlCleanupGlobals();
03763     xmlCleanupThreads();
03764 
03765     exit(result);
03766 }
03767 
03768 
03769 /* 
03770  * Given a conf.xml location connect to the database contained within it
03771  *
03772  * A lock will be taken out on the DB if it is SQLite; so it is important to release it
03773  * in the calling Fn when we are done with it.
03774  * If backup is set to 1 then a backup will be made (of a sqlite DB file)
03775  *
03776  * Returns 0 if a connection was made.
03777  *         1 if a connection could not be made.
03778  *        -1 if any of the config files could not be read/parsed
03779  *
03780  */
03781     int
03782 db_connect(DB_HANDLE *dbhandle, FILE** lock_fd, int backup)
03783 {
03784     /* what we will read from the file */
03785     char *dbschema = NULL;
03786     char *host = NULL;
03787     char *port = NULL;
03788     char *user = NULL;
03789     char *password = NULL;
03790 
03791     int status;
03792 
03793     char* backup_filename = NULL;
03794     char* lock_filename;
03795 
03796     /* Read the database details out of conf.xml */
03797     status = get_db_details(&dbschema, &host, &port, &user, &password);
03798     if (status != 0) {
03799         StrFree(host);
03800         StrFree(port);
03801         StrFree(dbschema);
03802         StrFree(user);
03803         StrFree(password);
03804         return(status);
03805     }
03806 
03807     /* If we are in sqlite mode then take a lock out on a file to
03808        prevent multiple access (not sure that we can be sure that sqlite is
03809        safe for multiple processes to access). */
03810     if (DbFlavour() == SQLITE_DB) {
03811 
03812         /* set up lock filename (it may have changed?) */
03813         if (lock_fd != NULL) {
03814             lock_filename = NULL;
03815             StrAppend(&lock_filename, dbschema);
03816             StrAppend(&lock_filename, ".our_lock");
03817 
03818             *lock_fd = fopen(lock_filename, "w");
03819             status = get_lite_lock(lock_filename, *lock_fd);
03820             if (status != 0) {
03821                 printf("Error getting db lock\n");
03822                 if (*lock_fd != NULL) {
03823                     fclose(*lock_fd);
03824                 }
03825                 StrFree(host);
03826                 StrFree(port);
03827                 StrFree(dbschema);
03828                 StrFree(user);
03829                 StrFree(password);
03830                 return(1);
03831             }
03832             StrFree(lock_filename);
03833         }
03834 
03835         /* Make a backup of the sqlite DB */
03836         if (backup == 1) {
03837             StrAppend(&backup_filename, dbschema);
03838             StrAppend(&backup_filename, ".backup");
03839 
03840             status = backup_file(dbschema, backup_filename);
03841 
03842             StrFree(backup_filename);
03843 
03844             if (status == 1) {
03845                 if (lock_fd != NULL) {
03846                     fclose(*lock_fd);
03847                 }
03848                 StrFree(host);
03849                 StrFree(port);
03850                 StrFree(dbschema);
03851                 StrFree(user);
03852                 StrFree(password);
03853                 return(status);
03854             }
03855         }
03856 
03857     }
03858 
03859     /* Finally we can do what we came here to do, connect to the database */
03860     status = DbConnect(dbhandle, dbschema, host, password, user, port);
03861 
03862     /* Cleanup */
03863     StrFree(host);
03864     StrFree(port);
03865     StrFree(dbschema);
03866     StrFree(user);
03867     StrFree(password);
03868 
03869     return(status);
03870 }
03871 
03872 /* 
03873  * Release the lock if the DB is SQLite
03874  *
03875  */
03876     void
03877 db_disconnect(FILE* lock_fd)
03878 {
03879     int status = 0;
03880 
03881     if (DbFlavour() == SQLITE_DB) {
03882         if (lock_fd != NULL) {
03883             status = release_lite_lock(lock_fd);
03884             if (status != 0) {
03885                 printf("Error releasing db lock");
03886                 /*fclose(lock_fd);*/
03887                 return;
03888             }
03889             fclose(lock_fd);
03890         }
03891     }
03892     return;
03893 }
03894 
03895 /* To overcome the potential differences in sqlite compile flags assume that it is not
03896    happy with multiple connections.
03897 
03898    The following 2 functions take out a lock and release it
03899  */
03900 
03901 int get_lite_lock(char *lock_filename, FILE* lock_fd)
03902 {
03903     struct flock fl;
03904     struct timeval tv;
03905 
03906     if (lock_fd == NULL) {
03907         printf("%s could not be opened\n", lock_filename);
03908         return 1;
03909     }
03910 
03911     memset(&fl, 0, sizeof(struct flock));
03912     fl.l_type = F_WRLCK;
03913     fl.l_whence = SEEK_SET;
03914     fl.l_pid = getpid();
03915 
03916     while (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
03917         if (errno == EACCES || errno == EAGAIN) {
03918             printf("%s already locked, sleep\n", lock_filename);
03919 
03920             /* sleep for 10 seconds TODO make this configurable? */
03921             tv.tv_sec = 10;
03922             tv.tv_usec = 0;
03923             select(0, NULL, NULL, NULL, &tv);
03924 
03925         } else {
03926             printf("couldn't get lock on %s; %s\n", lock_filename, strerror(errno));
03927             return 1;
03928         }
03929     }
03930 
03931     return 0;
03932 
03933 }
03934 
03935 int release_lite_lock(FILE* lock_fd)
03936 {
03937     struct flock fl;
03938 
03939     if (lock_fd == NULL) {
03940         return 1;
03941     }
03942 
03943     memset(&fl, 0, sizeof(struct flock));
03944     fl.l_type = F_UNLCK;
03945     fl.l_whence = SEEK_SET;
03946 
03947     if (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
03948         return 1;
03949     }
03950 
03951     return 0;
03952 }
03953 
03954 /* 
03955  *  Now we will read the conf.xml file again, but this time we will not validate.
03956  *  Instead we just learn the location of the zonelist.xml and kasp.xml files.
03957  */
03958 int read_filenames(char** zone_list_filename, char** kasp_filename)
03959 {
03960     xmlTextReaderPtr reader = NULL;
03961     xmlDocPtr doc = NULL;
03962     xmlXPathContextPtr xpathCtx = NULL;
03963     xmlXPathObjectPtr xpathObj = NULL;
03964     int ret = 0; /* status of the XML parsing */
03965     char* tag_name = NULL;
03966     char* temp_char = NULL;
03967 
03968     xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
03969     xmlChar *kaspfile_expr = (unsigned char*) "//Common/PolicyFile";
03970 
03971     /* Start reading the file; we will be looking for "Repository" tags */ 
03972     reader = xmlNewTextReaderFilename(config);
03973     if (reader != NULL) {
03974         ret = xmlTextReaderRead(reader);
03975         while (ret == 1) {
03976             tag_name = (char*) xmlTextReaderLocalName(reader);
03977             /* Found <Common> */
03978             if (strncmp(tag_name, "Common", 6) == 0 
03979                     && xmlTextReaderNodeType(reader) == 1) {
03980 
03981                 /* Expand this node and get the rest of the info with XPath */
03982                 xmlTextReaderExpand(reader);
03983                 doc = xmlTextReaderCurrentDoc(reader);
03984                 if (doc == NULL) {
03985                     printf("Error: can not read Common section\n");
03986                     /* Don't return? try to parse the rest of the file? */
03987                     ret = xmlTextReaderRead(reader);
03988                     continue;
03989                 }
03990 
03991                 xpathCtx = xmlXPathNewContext(doc);
03992                 if(xpathCtx == NULL) {
03993                     printf("Error: can not create XPath context for Common section\n");
03994                     /* Don't return? try to parse the rest of the file? */
03995                     ret = xmlTextReaderRead(reader);
03996                     continue;
03997                 }
03998 
03999                 /* Evaluate xpath expression for ZoneListFile */
04000                 xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
04001                 if(xpathObj == NULL) {
04002                     printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr);
04003                     /* Don't return? try to parse the rest of the file? */
04004                     ret = xmlTextReaderRead(reader);
04005                     continue;
04006                 }
04007                 *zone_list_filename = NULL;
04008                 temp_char = (char*) xmlXPathCastToString(xpathObj);
04009                 StrAppend(zone_list_filename, temp_char);
04010                 StrFree(temp_char);
04011                 xmlXPathFreeObject(xpathObj);
04012                 printf("zonelist filename set to %s.\n", *zone_list_filename);
04013 
04014                 /* Evaluate xpath expression for KaspFile */
04015                 xpathObj = xmlXPathEvalExpression(kaspfile_expr, xpathCtx);
04016                 xmlXPathFreeContext(xpathCtx);
04017                 if(xpathObj == NULL) {
04018                     printf("Error: unable to evaluate xpath expression: %s\n", kaspfile_expr);
04019                     /* Don't return? try to parse the rest of the file? */
04020                     ret = xmlTextReaderRead(reader);
04021                     continue;
04022                 }
04023                 *kasp_filename = NULL;
04024                 if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
04025                     /*
04026                      * Found Something, set it
04027                      */
04028                     temp_char = (char*) xmlXPathCastToString(xpathObj);
04029                     StrAppend(kasp_filename, temp_char);
04030                     StrFree(temp_char);
04031                 } else {
04032                     /*
04033                      * Set a default
04034                      */
04035                     /* XXX this should be parse from the the main config */
04036                     StrAppend(kasp_filename, OPENDNSSEC_CONFIG_DIR);
04037                     StrAppend(kasp_filename, "/kasp.xml");
04038                 }
04039                 printf("kasp filename set to %s.\n", *kasp_filename);
04040 
04041                 xmlXPathFreeObject(xpathObj);
04042             }
04043             /* Read the next line */
04044             ret = xmlTextReaderRead(reader);
04045 
04046             StrFree(tag_name);
04047         }
04048         xmlFreeTextReader(reader);
04049         if (ret != 0) {
04050             printf("%s : failed to parse\n", config);
04051             return(1);
04052         }
04053     } else {
04054         printf("Unable to open %s\n", config);
04055             return(1);
04056     }
04057     if (doc) {
04058         xmlFreeDoc(doc);
04059     }
04060 
04061     return 0;
04062 }
04063 
04064 /* 
04065  *  Read the conf.xml file yet again, but this time we will not validate.
04066  *  Instead we just extract the RepositoryList into the database.
04067  */
04068 int update_repositories()
04069 {
04070     int status = 0;
04071     xmlDocPtr doc = NULL;
04072     xmlXPathContextPtr xpathCtx = NULL;
04073     xmlXPathObjectPtr xpathObj = NULL;
04074     xmlNode *curNode;
04075     char* repo_name = NULL;
04076     char* repo_capacity = NULL;
04077     int require_backup = 0;
04078     int i = 0;
04079 
04080     xmlChar *node_expr = (unsigned char*) "//Configuration/RepositoryList/Repository";
04081 
04082     /* Start reading the file; we will be looking for "Repository" tags */
04083     /* Load XML document */
04084     doc = xmlParseFile(config);
04085     if (doc == NULL) {
04086         printf("Unable to open %s\n", config);
04087         return(1);
04088     }
04089 
04090     /* Create xpath evaluation context */
04091     xpathCtx = xmlXPathNewContext(doc);
04092     if(xpathCtx == NULL) {
04093         xmlFreeDoc(doc);
04094         return(1);
04095     }
04096 
04097     /* Evaluate xpath expression */
04098     xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx);
04099     if(xpathObj == NULL) {
04100         xmlXPathFreeContext(xpathCtx);
04101         xmlFreeDoc(doc);
04102         return(1);
04103     }
04104 
04105     if (xpathObj->nodesetval) {
04106         for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
04107 
04108             require_backup = 0;
04109             StrAppend(&repo_capacity, "");
04110 
04111             curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
04112             repo_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i],
04113                                              (const xmlChar *)"name");
04114             while (curNode) {
04115                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Capacity")) {
04116                     repo_capacity = (char *) xmlNodeGetContent(curNode);
04117                 }
04118                 if (xmlStrEqual(curNode->name, (const xmlChar *)"RequireBackup")) {
04119                     require_backup = 1;
04120                 }
04121 
04122                 curNode = curNode->next;
04123             }
04124 
04125             if (strlen(repo_name) != 0) {
04126                 /* Log what we are about to do */
04127                 printf("Repository %s found\n", repo_name);
04128                 if (strlen(repo_capacity) == 0) {
04129                     printf("No Maximum Capacity set.\n");
04130                     /*
04131                      * We have all the information, update/insert this repository
04132                      */
04133                     status = KsmImportRepository(repo_name, "0", require_backup);
04134                 } else {
04135                     printf("Capacity set to %s.\n", repo_capacity);
04136                     /*
04137                      * We have all the information, update/insert this repository
04138                      */
04139                     status = KsmImportRepository(repo_name, repo_capacity, require_backup);
04140                 }
04141                 if (require_backup == 0) {
04142                     printf("RequireBackup NOT set; please make sure that you know the potential problems of using keys which are not recoverable\n");
04143                 } else {
04144                     printf("RequireBackup set.\n");
04145                 }
04146 
04147                 if (status != 0) {
04148                     printf("Error Importing Repository %s", repo_name);
04149                     /* Don't return? try to parse the rest of the zones? */
04150                 }
04151             } else {
04152                 printf("WARNING: Repository found with NULL name, skipping...\n");
04153             }
04154             StrFree(repo_name);
04155             StrFree(repo_capacity);
04156         }
04157     }
04158 
04159     if (xpathObj) {
04160         xmlXPathFreeObject(xpathObj);
04161     }
04162     if (xpathCtx) {
04163         xmlXPathFreeContext(xpathCtx);
04164     }
04165     if (doc) {
04166         xmlFreeDoc(doc);
04167     }
04168 
04169     return 0;
04170 }
04171 
04172 /* Read kasp.xml, validate it and grab each policy in it as we go. */
04173 int update_policies(char* kasp_filename)
04174 {
04175     int status;
04176 
04177     /* what we will read from the file */
04178     char *policy_name = NULL;
04179     char *policy_description = NULL;
04180 
04181     /* All of the XML stuff */
04182     xmlDocPtr doc = NULL;
04183     xmlDocPtr pol_doc = NULL;
04184     xmlDocPtr rngdoc = NULL;
04185     xmlNode *curNode;
04186     xmlNode *childNode;
04187     xmlNode *childNode2;
04188     xmlNode *childNode3;
04189     xmlChar *opt_out_flag = (xmlChar *)"N";
04190     xmlChar *share_keys_flag = (xmlChar *)"N";
04191     xmlChar *man_roll_flag = (xmlChar *)"N";
04192     xmlChar *rfc5011_flag = (xmlChar *)"N";
04193     int standby_keys_flag = 0;
04194     xmlXPathContextPtr xpathCtx = NULL;
04195     xmlXPathObjectPtr xpathObj = NULL;
04196     xmlRelaxNGParserCtxtPtr rngpctx = NULL;
04197     xmlRelaxNGValidCtxtPtr rngctx = NULL;
04198     xmlRelaxNGPtr schema = NULL;
04199     int i = 0;
04200 
04201     xmlChar *node_expr = (unsigned char*) "//Policy";
04202 
04203 
04204 /*    xmlChar *audit_expr = (unsigned char*) "//Policy/Audit"; */
04205     int audit_found = 0;    /* flag to say whether an Audit flag was found or not */
04206 
04207     KSM_POLICY *policy;
04208 
04209     /* Some files, the xml and rng */
04210     const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/kasp.rng";
04211     char* kaspcheck_cmd = NULL;
04212     char* kaspcheck_cmd_version = NULL;
04213     
04214     StrAppend(&kaspcheck_cmd, ODS_AU_KASPCHECK);
04215     StrAppend(&kaspcheck_cmd, " -k ");
04216     StrAppend(&kaspcheck_cmd, kasp_filename);
04217 
04218     StrAppend(&kaspcheck_cmd_version, ODS_AU_KASPCHECK);
04219     StrAppend(&kaspcheck_cmd_version, " -v > /dev/null");
04220 
04221     /* Run kaspcheck */
04222     status = system(kaspcheck_cmd_version);
04223     if (status == 0)
04224     {
04225         status = system(kaspcheck_cmd);
04226         if (status != 0)
04227         {
04228             fprintf(stderr, "ods-kaspcheck returned an error, please check your policy\n");
04229             StrFree(kaspcheck_cmd);
04230             StrFree(kaspcheck_cmd_version);
04231             return(-1);
04232         }
04233     }
04234     else
04235     {
04236             fprintf(stderr, "Couldn't run ods-kaspcheck (Auditor is not installed), will carry on\n");
04237     }
04238 
04239     StrFree(kaspcheck_cmd);
04240     StrFree(kaspcheck_cmd_version);
04241 
04242     /* Load XML document */
04243     doc = xmlParseFile(kasp_filename);
04244     if (doc == NULL) {
04245         printf("Error: unable to parse file \"%s\"\n", kasp_filename);
04246         return(-1);
04247     }
04248 
04249     /* Load rng document: TODO make the rng stuff optional? */
04250     rngdoc = xmlParseFile(rngfilename);
04251     if (rngdoc == NULL) {
04252         printf("Error: unable to parse file \"%s\"\n", rngfilename);
04253         return(-1);
04254     }
04255 
04256     /* Create an XML RelaxNGs parser context for the relax-ng document. */
04257     rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
04258     if (rngpctx == NULL) {
04259         printf("Error: unable to create XML RelaxNGs parser context\n");
04260         return(-1);
04261     }
04262 
04263     /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
04264     schema = xmlRelaxNGParse(rngpctx);
04265     if (schema == NULL) {
04266         printf("Error: unable to parse a schema definition resource\n");
04267         return(-1);
04268     }
04269 
04270     /* Create an XML RelaxNGs validation context based on the given schema */
04271     rngctx = xmlRelaxNGNewValidCtxt(schema);
04272     if (rngctx == NULL) {
04273         printf("Error: unable to create RelaxNGs validation context based on the schema\n");
04274         return(-1);
04275     }
04276 
04277     /* Validate a document tree in memory. */
04278     status = xmlRelaxNGValidateDoc(rngctx,doc);
04279     if (status != 0) {
04280         printf("Error validating file \"%s\"\n", kasp_filename);
04281         return(-1);
04282     }
04283 
04284     /* Allocate some space for our policy */
04285     policy = KsmPolicyAlloc();
04286     if (policy == NULL) {
04287         printf("Malloc for policy struct failed");
04288         exit(1);
04289     }
04290 
04291     /* Create xpath evaluation context */
04292     xpathCtx = xmlXPathNewContext(doc);
04293     if(xpathCtx == NULL) {
04294         xmlFreeDoc(doc);
04295         KsmPolicyFree(policy);
04296         return(1);
04297     }
04298 
04299     /* Evaluate xpath expression */
04300     xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx);
04301     if(xpathObj == NULL) {
04302         xmlXPathFreeContext(xpathCtx);
04303         xmlFreeDoc(doc);
04304         KsmPolicyFree(policy);
04305         return(1);
04306     }
04307 
04308     if (xpathObj->nodesetval) {
04309         for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
04310 
04311             curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
04312             policy_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], (const xmlChar *)"name");
04313             if (strlen(policy_name) == 0) {
04314                 /* error */
04315                 printf("Error extracting policy name from %s\n", kasp_filename);
04316                 break;
04317             }
04318             audit_found = 0;
04319 
04320             printf("Policy %s found\n", policy_name);
04321             while (curNode) {
04322                 if (xmlStrEqual(curNode->name, (const xmlChar *)"Description")) {
04323                     policy_description = (char *) xmlNodeGetContent(curNode);
04324                     
04325                     /* Insert or update this policy with the description found,
04326                        we will need the policy_id too */
04327                     SetPolicyDefaults(policy, policy_name);
04328                     status = KsmPolicyExists(policy_name);
04329                     if (status == 0) {
04330                         /* Policy exists; we will be updating it */
04331                         status = KsmPolicyRead(policy);
04332                         if(status != 0) {
04333                             printf("Error: unable to read policy %s; skipping\n", policy_name);
04334                             curNode = curNode->next;
04335                             break;
04336                         }
04337                         /* TODO Set description here ? */
04338                     }
04339                     else {
04340                         /* New policy, insert it and get the new policy_id */
04341                         status = KsmImportPolicy(policy_name, policy_description);
04342                         if(status != 0) {
04343                             printf("Error: unable to insert policy %s; skipping\n", policy_name);
04344                             /* Don't return? try to parse the rest of the file? */
04345                             continue;
04346                         }
04347                         status = KsmPolicySetIdFromName(policy);
04348 
04349                         if (status != 0) {
04350                             printf("Error: unable to get policy id for %s; skipping\n", policy_name);
04351                             continue;
04352                         }
04353                     }
04354                 }
04355             /* SIGNATURES */
04356                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Signatures")) {
04357                     childNode = curNode->children;
04358                     while (childNode){
04359                         if (xmlStrEqual(childNode->name, (const xmlChar *)"Resign")) {
04360                             SetParamOnPolicy(xmlNodeGetContent(childNode), "resign", "signature", policy->signature->resign, policy->id, DURATION_TYPE);
04361                         }
04362                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"Refresh")) {
04363                             SetParamOnPolicy(xmlNodeGetContent(childNode), "refresh", "signature", policy->signer->refresh, policy->id, DURATION_TYPE);
04364                         }
04365                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"Validity")) {
04366                             childNode2 = childNode->children;
04367                             while (childNode2){
04368                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Default")) {
04369                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdefault", "signature", policy->signature->valdefault, policy->id, DURATION_TYPE);
04370                                 }
04371                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Denial")) {
04372                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdenial", "signature", policy->signature->valdenial, policy->id, DURATION_TYPE);
04373                                 }
04374                                 childNode2 = childNode2->next;
04375                             }
04376                         }
04377                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"Jitter")) {
04378                             SetParamOnPolicy(xmlNodeGetContent(childNode), "jitter", "signature", policy->signer->jitter, policy->id, DURATION_TYPE);
04379                         }
04380                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"InceptionOffset")) {
04381                             SetParamOnPolicy(xmlNodeGetContent(childNode), "clockskew", "signature", policy->signature->clockskew, policy->id, DURATION_TYPE);
04382                         }
04383                         childNode = childNode->next;
04384                     }
04385                 } /* End of Signatures */
04386                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Denial")) {
04387                     opt_out_flag = (xmlChar *)"N";
04388                     childNode = curNode->children;
04389                     while (childNode){
04390                         if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC3")) {
04391                             /* NSEC3 */
04392                             status = KsmParameterSet("version", "denial", 3, policy->id);
04393                             if (status != 0) {
04394                                 printf("Error: unable to insert/update %s for policy\n", "Denial version");
04395                             }
04396                             childNode2 = childNode->children;
04397                             while (childNode2){
04398                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"OptOut")) {
04399                                     opt_out_flag = (xmlChar *)"Y";
04400                                 }
04401                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Resalt")) {
04402                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "resalt", "denial", policy->denial->resalt, policy->id, DURATION_TYPE);
04403                                 }
04404                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Hash")) {
04405                                     childNode3 = childNode2->children;
04406                                     while (childNode3){
04407                                         if (xmlStrEqual(childNode3->name, (const xmlChar *)"Algorithm")) {
04408                                             SetParamOnPolicy(xmlNodeGetContent(childNode3), "algorithm", "denial", policy->denial->algorithm, policy->id, INT_TYPE);
04409                                         }
04410                                         else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Iterations")) {
04411                                             SetParamOnPolicy(xmlNodeGetContent(childNode3), "iterations", "denial", policy->denial->iteration, policy->id, INT_TYPE);
04412                                         }
04413                                         else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Salt")) {
04414                                             SetParamOnPolicy(xmlGetProp(childNode3, (const xmlChar *)"length"), "saltlength", "denial", policy->denial->saltlength, policy->id, INT_TYPE);
04415                                         }
04416                                         childNode3 = childNode3->next;
04417                                     }
04418                                 }
04419 
04420                                 childNode2 = childNode2->next;
04421                             }
04422                             /* Set things that we flagged */
04423                             SetParamOnPolicy(opt_out_flag, "optout", "denial", policy->denial->optout, policy->id, BOOL_TYPE);
04424                         } /* End of NSEC3 */
04425                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC")) {
04426                             status = KsmParameterSet("version", "denial", 1, policy->id);
04427                             if (status != 0) {
04428                                 printf("Error: unable to insert/update %s for policy\n", "Denial version");
04429                             }
04430                         }
04431                         childNode = childNode->next;
04432                     }
04433                 } /* End of Denial */
04434                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Keys")) {
04435                     share_keys_flag = (xmlChar *)"N";
04436                     childNode = curNode->children;
04437                     while (childNode){
04438                         if (xmlStrEqual(childNode->name, (const xmlChar *)"TTL")) {
04439                             SetParamOnPolicy(xmlNodeGetContent(childNode), "ttl", "keys", policy->keys->ttl, policy->id, DURATION_TYPE);
04440                         }
04441                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"RetireSafety")) {
04442                             SetParamOnPolicy(xmlNodeGetContent(childNode), "retiresafety", "keys", policy->keys->retire_safety, policy->id, DURATION_TYPE);
04443                         }
04444                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"PublishSafety")) {
04445                             SetParamOnPolicy(xmlNodeGetContent(childNode), "publishsafety", "keys", policy->keys->publish_safety, policy->id, DURATION_TYPE);
04446                         }
04447                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"ShareKeys")) {
04448                             share_keys_flag = (xmlChar *)"Y";
04449                         }
04450                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"Purge")) {
04451                             SetParamOnPolicy(xmlNodeGetContent(childNode), "purge", "keys", policy->keys->purge, policy->id, DURATION_TYPE);
04452                         }
04453                         /* KSK */
04454                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"KSK")) {
04455                             man_roll_flag = (xmlChar *)"N";
04456                             rfc5011_flag = (xmlChar *)"N";
04457                             childNode2 = childNode->children;
04458                             while (childNode2){
04459                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
04460                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "ksk", policy->ksk->algorithm, policy->id, INT_TYPE);
04461                                     SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "ksk", policy->ksk->bits, policy->id, INT_TYPE);
04462 
04463                                 }
04464                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) {
04465                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "ksk", policy->ksk->lifetime, policy->id, DURATION_TYPE);
04466                                 }
04467                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) {
04468                                     if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "ksk", policy->ksk->sm, policy->id, REPO_TYPE) != 0) {
04469                                         printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n");
04470                                         /* return the error, we do not want to continue */
04471                                         xmlFreeDoc(pol_doc);
04472                                         xmlXPathFreeContext(xpathCtx);
04473                                         xmlRelaxNGFree(schema);
04474                                         xmlRelaxNGFreeValidCtxt(rngctx);
04475                                         xmlRelaxNGFreeParserCtxt(rngpctx);
04476                                         xmlFreeDoc(doc);
04477                                         xmlFreeDoc(rngdoc);
04478                                         KsmPolicyFree(policy);
04479 
04480                                         return(1);
04481                                     }
04482                                 }
04483                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) {
04484                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE);
04485                                     standby_keys_flag = 1;
04486                                 }
04487                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) {
04488                                     man_roll_flag = (xmlChar *)"Y";
04489                                 }
04490                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RFC5011")) {
04491                                     rfc5011_flag = (xmlChar *)"Y";
04492                                 }
04493                                 /*else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RolloverScheme")) {
04494                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "rollover_scheme", "ksk", policy->ksk->rollover_scheme, policy->id, ROLLOVER_TYPE);
04495                                 }*/
04496                                 childNode2 = childNode2->next;
04497                             }
04498                             /* Set things that we flagged */
04499                             SetParamOnPolicy(man_roll_flag, "manual_rollover", "ksk", policy->ksk->manual_rollover, policy->id, BOOL_TYPE);
04500                             SetParamOnPolicy(rfc5011_flag, "rfc5011", "ksk", policy->ksk->rfc5011, policy->id, BOOL_TYPE);
04501                             if (standby_keys_flag == 0) {
04502                                 SetParamOnPolicy((xmlChar *)"0", "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE_NO_FREE);
04503                             } else {
04504                                 standby_keys_flag = 0;
04505                             }
04506                         } /* End of KSK */
04507                         /* ZSK */
04508                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"ZSK")) {
04509                             man_roll_flag = (xmlChar *)"N";
04510                             childNode2 = childNode->children;
04511                             while (childNode2){
04512                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
04513                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "zsk", policy->zsk->algorithm, policy->id, INT_TYPE);
04514                                     SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "zsk", policy->zsk->bits, policy->id, INT_TYPE);
04515 
04516                                 }
04517                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) {
04518                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "zsk", policy->zsk->lifetime, policy->id, DURATION_TYPE);
04519                                 }
04520                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) {
04521                                     if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "zsk", policy->zsk->sm, policy->id, REPO_TYPE) != 0) {
04522                                         printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n");
04523                                         /* return the error, we do not want to continue */
04524                                         xmlFreeDoc(pol_doc);
04525                                         xmlXPathFreeContext(xpathCtx);
04526                                         xmlRelaxNGFree(schema);
04527                                         xmlRelaxNGFreeValidCtxt(rngctx);
04528                                         xmlRelaxNGFreeParserCtxt(rngpctx);
04529                                         xmlFreeDoc(doc);
04530                                         xmlFreeDoc(rngdoc);
04531                                         KsmPolicyFree(policy);
04532 
04533                                         return(1);
04534                                     }
04535                                 }
04536                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) {
04537                                     SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE);
04538                                     standby_keys_flag = 1;
04539                                 }
04540                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) {
04541                                     man_roll_flag = (xmlChar *)"Y";
04542                                 }
04543                                 childNode2 = childNode2->next;
04544                             }
04545                         /* Set things that we flagged */
04546                         SetParamOnPolicy(man_roll_flag, "manual_rollover", "zsk", policy->zsk->manual_rollover, policy->id, BOOL_TYPE);
04547                         } /* End of ZSK */
04548 
04549                         childNode = childNode->next;
04550                     }
04551                     /* Set things that we flagged */
04552                     SetParamOnPolicy(share_keys_flag, "zones_share_keys", "keys", policy->keys->share_keys, policy->id, BOOL_TYPE);
04553                     if (standby_keys_flag == 0) {
04554                         SetParamOnPolicy((xmlChar *)"0", "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE_NO_FREE);
04555                     } else {
04556                         standby_keys_flag = 0;
04557                     }
04558 
04559                 } /* End of Keys */
04560                 /* Zone */
04561                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Zone")) {
04562                     childNode = curNode->children;
04563                     while (childNode){
04564                         if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) {
04565                             SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "zone", policy->zone->propdelay, policy->id, DURATION_TYPE);
04566                         }
04567                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) {
04568                             childNode2 = childNode->children;
04569                             while (childNode2){
04570                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
04571                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "zone", policy->zone->soa_ttl, policy->id, DURATION_TYPE);
04572                                 }
04573                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) {
04574                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "zone", policy->zone->soa_min, policy->id, DURATION_TYPE);
04575                                 }
04576                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Serial")) {
04577                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "serial", "zone", policy->zone->serial, policy->id, SERIAL_TYPE);
04578                                 }
04579                                 childNode2 = childNode2->next;
04580                             }
04581                         }
04582                         childNode = childNode->next;
04583                     }
04584                 } /* End of Zone */
04585                 /* Parent */
04586                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Parent")) {
04587                     childNode = curNode->children;
04588                     while (childNode){
04589                         if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) {
04590                             SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "parent", policy->parent->propdelay, policy->id, DURATION_TYPE);
04591                         }
04592                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"DS")) {
04593                             childNode2 = childNode->children;
04594                             while (childNode2){
04595                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
04596                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttlds", "parent", policy->parent->ds_ttl, policy->id, DURATION_TYPE);
04597                                 }
04598                                 childNode2 = childNode2->next;
04599                             }
04600                         }
04601                         else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) {
04602                             childNode2 = childNode->children;
04603                             while (childNode2){
04604                                 if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
04605                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "parent", policy->parent->soa_ttl, policy->id, DURATION_TYPE);
04606                                 }
04607                                 else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) {
04608                             SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "parent", policy->parent->soa_min, policy->id, DURATION_TYPE);
04609                                 }
04610                                 childNode2 = childNode2->next;
04611                             }
04612                         }
04613                         childNode = childNode->next;
04614                     }
04615                 } /* End of Parent */
04616                 /* Audit */
04617                 else if (xmlStrEqual(curNode->name, (const xmlChar *)"Audit")) {
04618                     status = KsmImportAudit(policy->id, "");
04619                     childNode = curNode->children;
04620                     while (childNode){
04621                         if (xmlStrEqual(childNode->name, (const xmlChar *)"Partial")) {
04622                             status = KsmImportAudit(policy->id, "<Partial/>");
04623                         }
04624                         childNode = childNode->next;
04625                     }
04626                     audit_found = 1;
04627                     if(status != 0) {
04628                         printf("Error: unable to insert Audit info for policy %s\n", policy->name);
04629                     }
04630                 }
04631 
04632                 curNode = curNode->next;
04633             }
04634             /* Indicate in the database if we didn't find an audit tag */
04635             if (audit_found == 0) {
04636                 status = KsmImportAudit(policy->id, "NULL");
04637             }
04638 
04639             /* Free up some stuff that we don't need any more */
04640             StrFree(policy_name);
04641             StrFree(policy_description);
04642 
04643         } /* End of <Policy> */
04644     }
04645 
04646     /* Cleanup */
04647     xmlXPathFreeContext(xpathCtx);
04648     xmlRelaxNGFree(schema);
04649     xmlRelaxNGFreeValidCtxt(rngctx);
04650     xmlRelaxNGFreeParserCtxt(rngpctx);
04651     xmlFreeDoc(doc);
04652     xmlFreeDoc(rngdoc);
04653     KsmPolicyFree(policy);
04654 
04655     return(status);
04656 }
04657 
04658 /* Read zonelist (as passed in) and insert/update any zones seen */
04659 int update_zones(char* zone_list_filename)
04660 {
04661     int status = 0;
04662     xmlTextReaderPtr reader = NULL;
04663     xmlDocPtr doc = NULL;
04664     xmlXPathContextPtr xpathCtx = NULL;
04665     xmlXPathObjectPtr xpathObj = NULL;
04666     int ret = 0; /* status of the XML parsing */
04667     char* zone_name = NULL;
04668     char* policy_name = NULL;
04669     char* current_policy = NULL;
04670     char* current_signconf = NULL;
04671     char* current_input = NULL;
04672     char* current_output = NULL;
04673     char* temp_char = NULL;
04674     char* tag_name = NULL;
04675     int policy_id = 0;
04676     int new_zone = 0;   /* flag to say if the zone is new or not */
04677     int file_zone_count = 0; /* As a quick check we will compare the number of */
04678     int db_zone_count = 0;   /* zones in the file to the number in the database */
04679     int* zone_ids;      /* List of zone_ids seen from zonelist.xml */
04680     int temp_id;
04681 
04682     char* sql = NULL;
04683     DB_RESULT   result;         /* Result of the query */
04684     DB_RESULT   result2;        /* Result of the query */
04685     DB_RESULT   result3;        /* Result of the query */
04686     DB_ROW      row = NULL;     /* Row data */
04687     KSM_PARAMETER shared;       /* Parameter information */
04688     int seen_zone = 0;
04689     int temp_count = 0;
04690     int i = 0;
04691 
04692     xmlChar *name_expr = (unsigned char*) "name";
04693     xmlChar *policy_expr = (unsigned char*) "//Zone/Policy";
04694     xmlChar *signconf_expr = (unsigned char*) "//Zone/SignerConfiguration";
04695     xmlChar *input_expr = (unsigned char*) "//Zone/Adapters/Input/File";
04696     xmlChar *output_expr = (unsigned char*) "//Zone/Adapters/Output/File";
04697 
04698     /* TODO validate the file ? */
04699     /* Read through the file counting zones TODO better way to do this? */
04700     reader = xmlNewTextReaderFilename(zone_list_filename);
04701     if (reader != NULL) {
04702         ret = xmlTextReaderRead(reader);
04703         while (ret == 1) {
04704             tag_name = (char*) xmlTextReaderLocalName(reader);
04705             /* Found <Zone> */
04706             if (strncmp(tag_name, "Zone", 4) == 0 
04707                     && strncmp(tag_name, "ZoneList", 8) != 0
04708                     && xmlTextReaderNodeType(reader) == 1) {
04709                 file_zone_count++;
04710             }
04711             /* Read the next line */
04712             ret = xmlTextReaderRead(reader);
04713             StrFree(tag_name);
04714         }
04715         xmlFreeTextReader(reader);
04716         if (ret != 0) {
04717             printf("%s : failed to parse\n", zone_list_filename);
04718         }
04719     } else {
04720         printf("Unable to open %s\n", zone_list_filename);
04721     }
04722 
04723     /* Allocate space for the list of zone IDs */
04724     zone_ids = MemMalloc(file_zone_count * sizeof(int));
04725 
04726     /* Start reading the file; we will be looking for "Zone" tags */ 
04727     reader = xmlNewTextReaderFilename(zone_list_filename);
04728     if (reader != NULL) {
04729         ret = xmlTextReaderRead(reader);
04730         while (ret == 1) {
04731             tag_name = (char*) xmlTextReaderLocalName(reader);
04732             /* Found <Zone> */
04733             if (strncmp(tag_name, "Zone", 4) == 0 
04734                     && strncmp(tag_name, "ZoneList", 8) != 0
04735                     && xmlTextReaderNodeType(reader) == 1) {
04736                 /* Get the repository name */
04737                 zone_name = NULL;
04738                 temp_char = (char*) xmlTextReaderGetAttribute(reader, name_expr);
04739                 StrAppend(&zone_name, temp_char);
04740                 StrFree(temp_char);
04741 
04742                                 /* 
04743                                    It is tempting to remove the trailing dot here; however I am 
04744                                    not sure that it is the right thing to do... It trashed my 
04745                                    test setup by deleting the zone sion. and replacing it with 
04746                                    sion (but of course none of the keys were moved). I think 
04747                                    that allowing people to edit zonelist.xml means that we must 
04748                                    allow them to add the td if they want to. 
04749                                  */
04750 
04751                 /* Make sure that we got something */
04752                 if (zone_name == NULL) {
04753                     /* error */
04754                     printf("Error extracting zone name from %s\n", zone_list_filename);
04755                     /* Don't return? try to parse the rest of the file? */
04756                     ret = xmlTextReaderRead(reader);
04757                     continue;
04758                 }
04759 
04760                 printf("Zone %s found\n", zone_name);
04761 
04762                 /* Expand this node and get the rest of the info with XPath */
04763                 xmlTextReaderExpand(reader);
04764                 doc = xmlTextReaderCurrentDoc(reader);
04765                 if (doc == NULL) {
04766                     printf("Error: can not read zone \"%s\"; skipping\n", zone_name);
04767                     /* Don't return? try to parse the rest of the zones? */
04768                     ret = xmlTextReaderRead(reader);
04769                     continue;
04770                 }
04771 
04772                 xpathCtx = xmlXPathNewContext(doc);
04773                 if(xpathCtx == NULL) {
04774                     printf("Error: can not create XPath context for \"%s\"; skipping zone\n", zone_name);
04775                     /* Don't return? try to parse the rest of the zones? */
04776                     ret = xmlTextReaderRead(reader);
04777                     continue;
04778                 }
04779 
04780                 /* Extract the Policy name for this zone */
04781                 /* Evaluate xpath expression for policy */
04782                 xpathObj = xmlXPathEvalExpression(policy_expr, xpathCtx);
04783                 if(xpathObj == NULL) {
04784                     printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", policy_expr);
04785                     /* Don't return? try to parse the rest of the zones? */
04786                     ret = xmlTextReaderRead(reader);
04787                     continue;
04788                 }
04789 
04790                 current_policy = NULL;
04791                 temp_char = (char *)xmlXPathCastToString(xpathObj);
04792                 StrAppend(&current_policy, temp_char);
04793                 StrFree(temp_char);
04794                 printf("Policy set to %s.\n", current_policy);
04795                 xmlXPathFreeObject(xpathObj);
04796 
04797                 /* If we have a different policy to last time get its ID */
04798                 if (policy_name == NULL || strcmp(current_policy, policy_name) != 0) {
04799                     StrFree(policy_name);
04800                     StrAppend(&policy_name, current_policy);
04801 
04802                     status = KsmPolicyIdFromName(policy_name, &policy_id);
04803                     if (status != 0) {
04804                         printf("Error, can't find policy : %s\n", policy_name);
04805                         /* Don't return? try to parse the rest of the zones? */
04806                         ret = xmlTextReaderRead(reader);
04807                         continue;
04808                     }
04809                 }
04810 
04811                 /* Extract the Signconf name for this zone */
04812                 /* Evaluate xpath expression */
04813                 xpathObj = xmlXPathEvalExpression(signconf_expr, xpathCtx);
04814                 if(xpathObj == NULL) {
04815                     printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", signconf_expr);
04816                     /* Don't return? try to parse the rest of the zones? */
04817                     ret = xmlTextReaderRead(reader);
04818                     continue;
04819                 }
04820 
04821                 current_signconf = NULL;
04822                 temp_char = (char *)xmlXPathCastToString(xpathObj);
04823                 StrAppend(&current_signconf, temp_char);
04824                 StrFree(temp_char);
04825                 xmlXPathFreeObject(xpathObj);
04826 
04827                 /* Extract the Input name for this zone */
04828                 /* Evaluate xpath expression */
04829                 xpathObj = xmlXPathEvalExpression(input_expr, xpathCtx);
04830                 if(xpathObj == NULL) {
04831                     printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", input_expr);
04832                     /* Don't return? try to parse the rest of the zones? */
04833                     ret = xmlTextReaderRead(reader);
04834                     continue;
04835                 }
04836 
04837                 current_input = NULL;
04838                 temp_char = (char *)xmlXPathCastToString(xpathObj);
04839                 StrAppend(&current_input, temp_char);
04840                 StrFree(temp_char);
04841                 xmlXPathFreeObject(xpathObj);
04842 
04843                 /* Extract the Output name for this zone */
04844                 /* Evaluate xpath expression */
04845                 xpathObj = xmlXPathEvalExpression(output_expr, xpathCtx);
04846                 xmlXPathFreeContext(xpathCtx);
04847                 if(xpathObj == NULL) {
04848                     printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", output_expr);
04849                     /* Don't return? try to parse the rest of the zones? */
04850                     ret = xmlTextReaderRead(reader);
04851                     continue;
04852                 }
04853 
04854                 current_output = NULL;
04855                 temp_char = (char *)xmlXPathCastToString(xpathObj);
04856                 StrAppend(&current_output, temp_char);
04857                 StrFree(temp_char);
04858                 xmlXPathFreeObject(xpathObj);
04859 
04860                 /*
04861                  * Now we have all the information update/insert this repository
04862                  */
04863                 status = KsmImportZone(zone_name, policy_id, 0, &new_zone, current_signconf, current_input, current_output);
04864                 if (status != 0) {
04865                                         if (status == -3) {
04866                                                 printf("Error Importing zone %s; it already exists both with and without a trailing dot\n", zone_name);
04867                                         } else {
04868                                                 printf("Error Importing Zone %s\n", zone_name);
04869                                         }
04870                     /* Don't return? try to parse the rest of the zones? */
04871                     ret = xmlTextReaderRead(reader);
04872                     continue;
04873                 }
04874 
04875                 /* If need be link existing keys to zone */
04876                 if (new_zone == 1) {
04877                     printf("Added zone %s to database\n", zone_name);
04878                 /* WITH NEW KEYSHARING LEAVE THIS TO THE ENFORCER TODO - CHECK THIS IS RIGHT */
04879                     /*
04880                     status = KsmLinkKeys(zone_name, policy_id);
04881                     if (status != 0) {
04882                         printf("Failed to Link Keys to zone\n");
04883                         ret = xmlTextReaderRead(reader);
04884                         continue;
04885                     }*/
04886                 }
04887 
04888                 /* make a note of the zone_id */
04889                 status = KsmZoneIdFromName(zone_name, &temp_id);
04890                 if (status != 0) {
04891                     printf("Error: unable to find a zone named \"%s\" in database\n", zone_name);
04892                     printf("Error: Possibly two domains differ only by having a trailing dot or not?\n");
04893                     StrFree(zone_ids);
04894                     return(status);
04895                 }
04896                
04897                /* We malloc'd this above */
04898                 zone_ids[i] = temp_id;
04899                 i++;
04900 
04901                 StrFree(zone_name);
04902                 StrFree(current_policy);
04903                 StrFree(current_signconf);
04904                 StrFree(current_input);
04905                 StrFree(current_output);
04906 
04907                 new_zone = 0;
04908 
04909             }
04910             /* Read the next line */
04911             ret = xmlTextReaderRead(reader);
04912             StrFree(tag_name);
04913         }
04914         xmlFreeTextReader(reader);
04915         if (ret != 0) {
04916             printf("%s : failed to parse\n", zone_list_filename);
04917         }
04918     } else {
04919         printf("Unable to open %s\n", zone_list_filename);
04920     }
04921     if (doc) {
04922         xmlFreeDoc(doc);
04923     }
04924     StrFree(policy_name);
04925 
04926     /* Now see how many zones are in the database */
04927     sql = DqsCountInit(DB_ZONE_TABLE);
04928     DqsEnd(&sql);
04929 
04930     /* Execute query and free up the query string */
04931     status = DbIntQuery(DbHandle(), &db_zone_count, sql);
04932     DqsFree(sql);
04933 
04934     /* If the 2 numbers match then our work is done */
04935     if (file_zone_count == db_zone_count) {
04936         StrFree(zone_ids);
04937         return 0;
04938     }
04939     /* If the file count is larger then something went wrong */
04940     else if (file_zone_count > db_zone_count) {
04941         printf("Failed to add all zones from zonelist\n");
04942         StrFree(zone_ids);
04943         return(1);
04944     }
04945 
04946     /* If we get here we need to do some deleting, get each zone in the db 
04947      * and see if it is in the zone_list that we built earlier */
04948     /* In case there are thousands of zones we don't use an "IN" clause*/
04949     sql = DqsSpecifyInit(DB_ZONE_TABLE, "id, name, policy_id");
04950     DqsOrderBy(&sql, "ID");
04951     DqsEnd(&sql);
04952 
04953     status = DbExecuteSql(DbHandle(), sql, &result);
04954 
04955     if (status == 0) {
04956         status = DbFetchRow(result, &row);
04957         while (status == 0) {
04958             DbInt(row, 0, &temp_id);
04959             DbString(row, 1, &zone_name);
04960             DbInt(row, 2, &policy_id);
04961 
04962             seen_zone = 0;
04963             for (i = 0; i < db_zone_count; ++i) {
04964                 if (temp_id == zone_ids[i]) {
04965                     seen_zone = 1;
04966                     break;
04967                 }
04968             }
04969             
04970             if (seen_zone == 0) {
04971                 /* We need to delete this zone */
04972                 /* Get the shared_keys parameter */
04973                 printf("Removing zone %s from database\n", zone_name);
04974 
04975                 status = KsmParameterInit(&result2, "zones_share_keys", "keys", policy_id);
04976                 if (status != 0) {
04977                     DbFreeRow(row);
04978                     DbStringFree(zone_name);
04979                     StrFree(zone_ids);
04980                     return(status);
04981                 }
04982                 status = KsmParameter(result2, &shared);
04983                 if (status != 0) {
04984                     DbFreeRow(row);
04985                     DbStringFree(zone_name);
04986                     StrFree(zone_ids);
04987                     return(status);
04988                 }
04989                 KsmParameterEnd(result2);
04990 
04991                 /* how many zones on this policy (needed to unlink keys) */ 
04992                 status = KsmZoneCountInit(&result3, policy_id); 
04993                 if (status == 0) { 
04994                     status = KsmZoneCount(result3, &temp_count); 
04995                 } 
04996                 DbFreeResult(result3);
04997 
04998                 /* Mark keys as dead if appropriate */
04999                 if ((shared.value == 1 && temp_count == 1) || shared.value == 0) {
05000                     status = KsmMarkKeysAsDead(temp_id);
05001                     if (status != 0) {
05002                         printf("Error: failed to mark keys as dead in database\n");
05003                         StrFree(zone_ids);
05004                         return(status);
05005                     }
05006                 }
05007 
05008                 /* Finally, we can delete the zone (and any dnsseckeys entries) */
05009                 status = KsmDeleteZone(temp_id);
05010             }
05011 
05012             status = DbFetchRow(result, &row);
05013         }
05014         /* Convert EOF status to success */
05015 
05016         if (status == -1) {
05017             status = 0;
05018         }
05019         DbFreeResult(result);
05020     }
05021     
05022     DusFree(sql);
05023     DbFreeRow(row);
05024     DbStringFree(zone_name);
05025     StrFree(zone_ids);
05026 
05027     return 0;
05028 }
05029 
05030 /* 
05031  * This encapsulates all of the steps needed to insert/update a parameter value
05032  * try to update the policy value, if it has changed
05033  * TODO possible bug where parmeters which have a value of 0 are not written (because we 
05034  * only write what looks like it has changed
05035  */
05036 int SetParamOnPolicy(const xmlChar* new_value, const char* name, const char* category, int current_value, int policy_id, int value_type)
05037 {
05038     int status = 0;
05039     int value = 0;
05040     char* temp_char = (char *)new_value;
05041 
05042     /* extract the value into an int */
05043     if (value_type == DURATION_TYPE) {
05044         if (strlen(temp_char) != 0) {
05045             status = DtXMLIntervalSeconds(temp_char, &value);
05046             if (status > 0) {
05047                 printf("Error: unable to convert interval %s to seconds, error: %i\n", temp_char, status);
05048                 StrFree(temp_char);
05049                 return status;
05050             }
05051             else if (status == -1) {
05052                 printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char);
05053             }
05054             StrFree(temp_char);
05055         } else {
05056             value = -1;
05057         }
05058     }
05059     else if (value_type == BOOL_TYPE) {
05060         /* Do we have an empty tag or no tag? */
05061         if (strncmp(temp_char, "Y", 1) == 0) {
05062             value = 1;
05063         } else {
05064             value = 0;
05065         }
05066     }
05067     else if (value_type == REPO_TYPE) {
05068         /* We need to convert the repository name into an id */
05069         status = KsmSmIdFromName(temp_char, &value);
05070         if (status != 0) {
05071             printf("Error: unable to find repository %s\n", temp_char);
05072             StrFree(temp_char);
05073             return status;
05074         }
05075         StrFree(temp_char);
05076     }
05077     else if (value_type == SERIAL_TYPE) {
05078         /* We need to convert the serial name into an id */
05079         status = KsmSerialIdFromName(temp_char, &value);
05080         if (status != 0) {
05081             printf("Error: unable to find serial type %s\n", temp_char);
05082             StrFree(temp_char);
05083             return status;
05084         }
05085         StrFree(temp_char);
05086     }
05087     else if (value_type == ROLLOVER_TYPE) {
05088         /* We need to convert the rollover scheme name into an id */
05089         value = KsmKeywordRollNameToValue(temp_char);
05090         if (value == 0) {
05091             printf("Error: unable to find rollover scheme %s\n", temp_char);
05092             StrFree(temp_char);
05093             return status;
05094         }
05095         StrFree(temp_char);
05096     }
05097     else {
05098         status = StrStrtoi(temp_char, &value);
05099         if (status != 0) {
05100             printf("Error: unable to convert %s to int\n", temp_char);
05101             StrFree(temp_char);
05102             return status;
05103         }
05104         if (value_type != INT_TYPE_NO_FREE) {
05105             StrFree(temp_char);
05106         }
05107     }
05108 
05109     /* Now update the policy with what we found, if it is different */
05110     if (value != current_value || current_value == 0) {
05111         status = KsmParameterSet(name, category, value, policy_id);
05112         if (status != 0) {
05113             printf("Error: unable to insert/update %s for policy\n", name);
05114             printf("Error: Is your database schema up to date?\n");
05115             return status;
05116         }
05117 
05118         /* Special step if salt length changed make sure that the salt is 
05119            regenerated when the enforcer runs next */
05120         if (strncmp(name, "saltlength", 10) == 0) {
05121             status = KsmPolicyNullSaltStamp(policy_id);
05122             if (status != 0) {
05123                 printf("Error: unable to insert/update %s for policy\n", name);
05124                 printf("Error: Is your database schema up to date?\n");
05125                 return status;
05126             }
05127         }
05128     }
05129 
05130     return 0;
05131 }
05132 
05133 void SetPolicyDefaults(KSM_POLICY *policy, char *name)
05134 {
05135     if (policy == NULL) {
05136         printf("Error, no policy provided");
05137         return;
05138     }
05139 
05140         if (name) {
05141         snprintf(policy->name, KSM_NAME_LENGTH, "%s", name);
05142     }
05143 
05144     policy->signer->refresh = 0;
05145     policy->signer->jitter = 0;
05146     policy->signer->propdelay = 0;
05147     policy->signer->soamin = 0;
05148     policy->signer->soattl = 0;
05149     policy->signer->serial = 0;
05150 
05151     policy->signature->clockskew = 0;
05152     policy->signature->resign = 0;
05153     policy->signature->valdefault = 0;
05154     policy->signature->valdenial = 0;
05155 
05156     policy->denial->version = 0;
05157     policy->denial->resalt = 0;
05158     policy->denial->algorithm = 0;
05159     policy->denial->iteration = 0;
05160     policy->denial->optout = 0;
05161     policy->denial->ttl = 0;
05162     policy->denial->saltlength = 0;
05163 
05164     policy->keys->ttl = 0;
05165     policy->keys->retire_safety = 0;
05166     policy->keys->publish_safety = 0;
05167     policy->keys->share_keys = 0;
05168     policy->keys->purge = -1;
05169 
05170     policy->ksk->algorithm = 0;
05171     policy->ksk->bits = 0;
05172     policy->ksk->lifetime = 0;
05173     policy->ksk->sm = 0;
05174     policy->ksk->overlap = 0;
05175     policy->ksk->ttl = 0;
05176     policy->ksk->rfc5011 = 0;
05177     policy->ksk->type = KSM_TYPE_KSK;
05178     policy->ksk->standby_keys = 0;
05179     policy->ksk->manual_rollover = 0;
05180     policy->ksk->rollover_scheme = KSM_ROLL_DEFAULT;
05181 
05182     policy->zsk->algorithm = 0;
05183     policy->zsk->bits = 0;
05184     policy->zsk->lifetime = 0;
05185     policy->zsk->sm = 0;
05186     policy->zsk->overlap = 0;
05187     policy->zsk->ttl = 0;
05188     policy->zsk->rfc5011 = 0;
05189     policy->zsk->type = KSM_TYPE_ZSK;
05190     policy->zsk->standby_keys = 0;
05191     policy->zsk->manual_rollover = 0;
05192     policy->zsk->rollover_scheme = 0;
05193 
05194     policy->enforcer->keycreate = 0;
05195     policy->enforcer->backup_interval = 0;
05196     policy->enforcer->keygeninterval = 0;
05197 
05198     policy->zone->propdelay = 0;
05199     policy->zone->soa_ttl = 0;
05200     policy->zone->soa_min = 0;
05201     policy->zone->serial = 0;
05202 
05203     policy->parent->propdelay = 0;
05204     policy->parent->ds_ttl = 0;
05205     policy->parent->soa_ttl = 0;
05206     policy->parent->soa_min = 0;
05207 
05208 }
05209 
05210 /* make a backup of a file
05211  * Returns 0 on success
05212  *         1 on error
05213  *        -1 if it could read the original but not open the backup
05214  */
05215 int backup_file(const char* orig_file, const char* backup_file)
05216 {
05217     FILE *from, *to;
05218     int ch;
05219 
05220     errno = 0;
05221     /* open source file */
05222     if((from = fopen( orig_file, "rb"))==NULL) {
05223         if (errno == ENOENT) {
05224             printf("File %s does not exist, nothing to backup\n", orig_file);
05225             return(0);
05226         }
05227         else {
05228             printf("Cannot open source file.\n");
05229             return(1); /* No point in trying to connect */
05230         }
05231     }
05232 
05233     /* open destination file */
05234     if((to = fopen(backup_file, "wb"))==NULL) {
05235         printf("Cannot open destination file, will not make backup.\n");
05236         fclose(from);
05237         return(-1);
05238     }
05239     else {
05240         /* copy the file */
05241         while(!feof(from)) {
05242             ch = fgetc(from);
05243             if(ferror(from)) {
05244                 printf("Error reading source file.\n");
05245                 fclose(from);
05246                 fclose(to);
05247                 return(1);
05248             }
05249             if(!feof(from)) fputc(ch, to);
05250             if(ferror(to)) {
05251                 printf("Error writing destination file.\n");
05252                 fclose(from);
05253                 fclose(to);
05254                 return(1);
05255             }
05256         }
05257 
05258         if(fclose(from)==EOF) {
05259             printf("Error closing source file.\n");
05260             fclose(to);
05261             return(1);
05262         }
05263 
05264         if(fclose(to)==EOF) {
05265             printf("Error closing destination file.\n");
05266             return(1);
05267         }
05268     }
05269     return(0);
05270 }
05271 
05272 /* 
05273  * Given a conf.xml location extract the database details contained within it
05274  *
05275  * The caller will need to StrFree the char**s passed in
05276  *
05277  * Returns 0 if a full set of details was found
05278  *         1 if something didn't look right
05279  *        -1 if any of the config files could not be read/parsed
05280  *
05281  */
05282     int
05283 get_db_details(char** dbschema, char** host, char** port, char** user, char** password)
05284 {
05285     /* All of the XML stuff */
05286     xmlDocPtr doc;
05287     xmlDocPtr rngdoc;
05288     xmlXPathContextPtr xpathCtx;
05289     xmlXPathObjectPtr xpathObj;
05290     xmlRelaxNGParserCtxtPtr rngpctx;
05291     xmlRelaxNGValidCtxtPtr rngctx;
05292     xmlRelaxNGPtr schema;
05293     xmlChar *litexpr = (unsigned char*) "//Configuration/Enforcer/Datastore/SQLite";
05294     xmlChar *mysql_host = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host";
05295     xmlChar *mysql_port = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host/@port";
05296     xmlChar *mysql_db = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Database";
05297     xmlChar *mysql_user = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Username";
05298     xmlChar *mysql_pass = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Password";
05299 
05300     int status;
05301     int db_found = 0;
05302     char* temp_char = NULL;
05303 
05304     /* Some files, the xml and rng */
05305     const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
05306 
05307     /* Load XML document */
05308     doc = xmlParseFile(config);
05309     if (doc == NULL) {
05310         printf("Error: unable to parse file \"%s\"\n", config);
05311         return(-1);
05312     }
05313 
05314     /* Load rng document: TODO make the rng stuff optional? */
05315     rngdoc = xmlParseFile(rngfilename);
05316     if (rngdoc == NULL) {
05317         printf("Error: unable to parse file \"%s\"\n", rngfilename);
05318         xmlFreeDoc(doc);
05319         return(-1);
05320     }
05321 
05322     /* Create an XML RelaxNGs parser context for the relax-ng document. */
05323     rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
05324     xmlFreeDoc(rngdoc);
05325     if (rngpctx == NULL) {
05326         printf("Error: unable to create XML RelaxNGs parser context\n");
05327         xmlFreeDoc(doc);
05328         return(-1);
05329     }
05330 
05331     /* parse a schema definition resource and build an internal XML Schema structure which can be used to validate instances. */
05332     schema = xmlRelaxNGParse(rngpctx);
05333     xmlRelaxNGFreeParserCtxt(rngpctx);
05334     if (schema == NULL) {
05335         printf("Error: unable to parse a schema definition resource\n");
05336         xmlFreeDoc(doc);
05337         return(-1);
05338     }
05339 
05340     /* Create an XML RelaxNGs validation context based on the given schema */
05341     rngctx = xmlRelaxNGNewValidCtxt(schema);
05342     if (rngctx == NULL) {
05343         printf("Error: unable to create RelaxNGs validation context based on the schema\n");
05344         xmlRelaxNGFree(schema);
05345         xmlFreeDoc(doc);
05346         return(-1);
05347     }
05348 
05349     /* Validate a document tree in memory. */
05350     status = xmlRelaxNGValidateDoc(rngctx,doc);
05351     xmlRelaxNGFreeValidCtxt(rngctx);
05352     xmlRelaxNGFree(schema);
05353     if (status != 0) {
05354         printf("Error validating file \"%s\"\n", config);
05355         xmlFreeDoc(doc);
05356         return(-1);
05357     }
05358 
05359     /* Now parse a value out of the conf */
05360     /* Create xpath evaluation context */
05361     xpathCtx = xmlXPathNewContext(doc);
05362     if(xpathCtx == NULL) {
05363         printf("Error: unable to create new XPath context\n");
05364         xmlFreeDoc(doc);
05365         return(-1);
05366     }
05367 
05368     /* Evaluate xpath expression for SQLite file location */
05369     xpathObj = xmlXPathEvalExpression(litexpr, xpathCtx);
05370     if(xpathObj == NULL) {
05371         printf("Error: unable to evaluate xpath expression: %s\n", litexpr);
05372         xmlXPathFreeContext(xpathCtx);
05373         xmlFreeDoc(doc);
05374         return(-1);
05375     }
05376     if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
05377         db_found = SQLITE_DB;
05378         temp_char = (char *)xmlXPathCastToString(xpathObj);
05379         StrAppend(dbschema, temp_char);
05380         StrFree(temp_char);
05381         fprintf(stderr, "SQLite database set to: %s\n", *dbschema);
05382     }
05383     xmlXPathFreeObject(xpathObj);
05384 
05385     if (db_found == 0) {
05386         db_found = MYSQL_DB;
05387 
05388         /* Get all of the MySQL stuff read in too */
05389         /* HOST, optional */
05390         xpathObj = xmlXPathEvalExpression(mysql_host, xpathCtx);
05391         if(xpathObj == NULL) {
05392             printf("Error: unable to evaluate xpath expression: %s\n", mysql_host);
05393             xmlXPathFreeContext(xpathCtx);
05394             xmlFreeDoc(doc);
05395             return(-1);
05396         }
05397         if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
05398             temp_char = (char *)xmlXPathCastToString(xpathObj);
05399             StrAppend(host, temp_char);
05400             StrFree(temp_char);
05401             fprintf(stderr, "MySQL database host set to: %s\n", *host);
05402         }
05403         xmlXPathFreeObject(xpathObj);
05404 
05405         /* PORT, optional */
05406         xpathObj = xmlXPathEvalExpression(mysql_port, xpathCtx);
05407         if(xpathObj == NULL) {
05408             printf("Error: unable to evaluate xpath expression: %s\n", mysql_port);
05409             xmlXPathFreeContext(xpathCtx);
05410             xmlFreeDoc(doc);
05411             return(-1);
05412         }
05413         if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
05414             temp_char = (char *)xmlXPathCastToString(xpathObj);
05415             StrAppend(port, temp_char);
05416             StrFree(temp_char);
05417             fprintf(stderr, "MySQL database port set to: %s\n", *port);
05418         }
05419         xmlXPathFreeObject(xpathObj);
05420 
05421         /* SCHEMA */
05422         xpathObj = xmlXPathEvalExpression(mysql_db, xpathCtx);
05423         if(xpathObj == NULL) {
05424             printf("Error: unable to evaluate xpath expression: %s\n", mysql_db);
05425             xmlXPathFreeContext(xpathCtx);
05426             xmlFreeDoc(doc);
05427             return(-1);
05428         }
05429         if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
05430             temp_char = (char *)xmlXPathCastToString(xpathObj);
05431             StrAppend(dbschema, temp_char);
05432             StrFree(temp_char);
05433             fprintf(stderr, "MySQL database schema set to: %s\n", *dbschema);
05434         } else {
05435             db_found = 0;
05436         }
05437         xmlXPathFreeObject(xpathObj);
05438 
05439         /* DB USER */
05440         xpathObj = xmlXPathEvalExpression(mysql_user, xpathCtx);
05441         if(xpathObj == NULL) {
05442             printf("Error: unable to evaluate xpath expression: %s\n", mysql_user);
05443             xmlXPathFreeContext(xpathCtx);
05444             xmlFreeDoc(doc);
05445             return(-1);
05446         }
05447         if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
05448             temp_char = (char *)xmlXPathCastToString(xpathObj);
05449             StrAppend(user, temp_char);
05450             StrFree(temp_char);
05451             fprintf(stderr, "MySQL database user set to: %s\n", *user);
05452         } else {
05453             db_found = 0;
05454         }
05455         xmlXPathFreeObject(xpathObj);
05456 
05457         /* DB PASSWORD */
05458         xpathObj = xmlXPathEvalExpression(mysql_pass, xpathCtx);
05459         if(xpathObj == NULL) {
05460             printf("Error: unable to evaluate xpath expression: %s\n", mysql_pass);
05461             xmlXPathFreeContext(xpathCtx);
05462             xmlFreeDoc(doc);
05463             return(-1);
05464         }
05465         /* password may be blank */
05466         temp_char = (char *)xmlXPathCastToString(xpathObj);
05467         StrAppend(password, temp_char);
05468         StrFree(temp_char);
05469         xmlXPathFreeObject(xpathObj);
05470 
05471         fprintf(stderr, "MySQL database password set\n");
05472 
05473     }
05474 
05475     xmlXPathFreeContext(xpathCtx);
05476     xmlFreeDoc(doc);
05477 
05478     /* Check that we found one or the other database */
05479     if(db_found == 0) {
05480         printf("Error: unable to find complete database connection expression\n");
05481         return(-1);
05482     }
05483 
05484     /* Check that we found the right database type */
05485     if (db_found != DbFlavour()) {
05486         printf("Error: database in config file does not match libksm\n");
05487         return(-1);
05488     }
05489 
05490     return(status);
05491 }
05492 
05493 /* 
05494  *  Read the conf.xml file, we will not validate as that was done as we read the database.
05495  *  Instead we just extract the RepositoryList into the database and also learn the 
05496  *  location of the zonelist.
05497  */
05498 int read_zonelist_filename(char** zone_list_filename)
05499 {
05500     xmlTextReaderPtr reader = NULL;
05501     xmlDocPtr doc = NULL;
05502     xmlXPathContextPtr xpathCtx = NULL;
05503     xmlXPathObjectPtr xpathObj = NULL;
05504     int ret = 0; /* status of the XML parsing */
05505     char* temp_char = NULL;
05506     char* tag_name = NULL;
05507 
05508     xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
05509 
05510     /* Start reading the file; we will be looking for "Common" tags */ 
05511     reader = xmlNewTextReaderFilename(config);
05512     if (reader != NULL) {
05513         ret = xmlTextReaderRead(reader);
05514         while (ret == 1) {
05515             tag_name = (char*) xmlTextReaderLocalName(reader);
05516             /* Found <Common> */
05517             if (strncmp(tag_name, "Common", 6) == 0 
05518                     && xmlTextReaderNodeType(reader) == 1) {
05519 
05520                 /* Expand this node and get the rest of the info with XPath */
05521                 xmlTextReaderExpand(reader);
05522                 doc = xmlTextReaderCurrentDoc(reader);
05523                 if (doc == NULL) {
05524                     printf("Error: can not read Common section\n");
05525                     /* Don't return? try to parse the rest of the file? */
05526                     ret = xmlTextReaderRead(reader);
05527                     continue;
05528                 }
05529 
05530                 xpathCtx = xmlXPathNewContext(doc);
05531                 if(xpathCtx == NULL) {
05532                     printf("Error: can not create XPath context for Common section\n");
05533                     /* Don't return? try to parse the rest of the file? */
05534                     ret = xmlTextReaderRead(reader);
05535                     continue;
05536                 }
05537 
05538                 /* Evaluate xpath expression for ZoneListFile */
05539                 xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
05540                 if(xpathObj == NULL) {
05541                     printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr);
05542                     /* Don't return? try to parse the rest of the file? */
05543                     ret = xmlTextReaderRead(reader);
05544                     continue;
05545                 }
05546                 *zone_list_filename = NULL;
05547                 temp_char = (char *)xmlXPathCastToString(xpathObj);
05548                 xmlXPathFreeObject(xpathObj);
05549                 StrAppend(zone_list_filename, temp_char);
05550                 StrFree(temp_char);
05551                 printf("zonelist filename set to %s.\n", *zone_list_filename);
05552             }
05553             /* Read the next line */
05554             ret = xmlTextReaderRead(reader);
05555             StrFree(tag_name);
05556         }
05557         xmlFreeTextReader(reader);
05558         if (ret != 0) {
05559             printf("%s : failed to parse\n", config);
05560             return(1);
05561         }
05562     } else {
05563         printf("Unable to open %s\n", config);
05564         return(1);
05565     }
05566     if (xpathCtx) {
05567         xmlXPathFreeContext(xpathCtx);
05568     }
05569     if (doc) {
05570         xmlFreeDoc(doc);
05571     }
05572 
05573     return 0;
05574 }
05575 
05576 xmlDocPtr add_zone_node(const char *docname,
05577                         const char *zone_name, 
05578                         const char *policy_name, 
05579                         const char *sig_conf_name, 
05580                         const char *input_name, 
05581                         const char *output_name)
05582 {
05583     xmlDocPtr doc;
05584     xmlNodePtr cur;
05585     xmlNodePtr newzonenode;
05586     xmlNodePtr newadaptnode;
05587     xmlNodePtr newinputnode;
05588     xmlNodePtr newoutputnode;
05589     doc = xmlParseFile(docname);
05590     if (doc == NULL ) {
05591         fprintf(stderr,"Document not parsed successfully. \n");
05592         return (NULL);
05593     }
05594     cur = xmlDocGetRootElement(doc);
05595     if (cur == NULL) {
05596         fprintf(stderr,"empty document\n");
05597         xmlFreeDoc(doc);
05598         return (NULL);
05599     }
05600     if (xmlStrcmp(cur->name, (const xmlChar *) "ZoneList")) {
05601         fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
05602         xmlFreeDoc(doc);
05603         return (NULL);
05604     }
05605     newzonenode = xmlNewTextChild(cur, NULL, (const xmlChar *)"Zone", NULL);
05606     (void) xmlNewProp(newzonenode, (const xmlChar *)"name", (const xmlChar *)zone_name);
05607 
05608     (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"Policy", (const xmlChar *)policy_name);
05609 
05610     (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)sig_conf_name);
05611 
05612     newadaptnode = xmlNewChild (newzonenode, NULL, (const xmlChar *)"Adapters", NULL);
05613 
05614     newinputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Input", NULL);
05615 
05616     (void) xmlNewTextChild (newinputnode, NULL, (const xmlChar *)"File", (const xmlChar *)input_name);
05617 
05618     newoutputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Output", NULL);
05619 
05620     (void) xmlNewTextChild (newoutputnode, NULL, (const xmlChar *)"File", (const xmlChar *)output_name);
05621 
05622     return(doc);
05623 }
05624 
05625 xmlDocPtr del_zone_node(const char *docname,
05626                         const char *zone_name)
05627 {
05628     xmlDocPtr doc;
05629     xmlNodePtr root;
05630     xmlNodePtr cur;
05631 
05632     doc = xmlParseFile(docname);
05633     if (doc == NULL ) {
05634         fprintf(stderr,"Document not parsed successfully. \n");
05635         return (NULL);
05636     }
05637     root = xmlDocGetRootElement(doc);
05638     if (root == NULL) {
05639         fprintf(stderr,"empty document\n");
05640         xmlFreeDoc(doc);
05641         return (NULL);
05642     }
05643     if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
05644         fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
05645         xmlFreeDoc(doc);
05646         return (NULL);
05647     }
05648 
05649     /* If we are removing all zones then just replace the root node with an empty one */
05650     if (all_flag == 1) {
05651         cur = root->children;
05652         while (cur != NULL)
05653         {
05654             xmlUnlinkNode(cur);
05655             xmlFreeNode(cur);
05656 
05657             cur = root->children;
05658         }
05659     }
05660     else {
05661 
05662     /* Zone nodes are children of the root */
05663         for(cur = root->children; cur != NULL; cur = cur->next)
05664         {
05665             /* is this the zone we are looking for? */
05666             if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) zone_name) == 0)
05667             {
05668                 xmlUnlinkNode(cur);
05669 
05670                 cur = root->children; /* May pass through multiple times, but will remove all instances of the zone */
05671             }
05672         }
05673         xmlFreeNode(cur);
05674     }
05675 
05676     return(doc);
05677 }
05678 
05679 void list_zone_node(const char *docname, int *zone_ids)
05680 {
05681     xmlDocPtr doc;
05682     xmlNodePtr root;
05683     xmlNodePtr cur;
05684     xmlNodePtr pol;
05685     xmlChar *polChar = NULL;
05686     xmlChar *propChar = NULL;
05687 
05688     int temp_id;
05689     int i = 0;
05690     int status = 0;
05691 
05692     doc = xmlParseFile(docname);
05693     if (doc == NULL ) {
05694         fprintf(stderr,"Document not parsed successfully. \n");
05695         return;
05696     }
05697     root = xmlDocGetRootElement(doc);
05698     if (root == NULL) {
05699         fprintf(stderr,"empty document\n");
05700         xmlFreeDoc(doc);
05701         return;
05702     }
05703     if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
05704         fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
05705         xmlFreeDoc(doc);
05706         return;
05707     }
05708 
05709     /* Zone nodes are children of the root */
05710     for(cur = root->children; cur != NULL; cur = cur->next)
05711     {
05712         if (xmlStrcmp( cur->name, (const xmlChar *)"Zone") == 0) {
05713             propChar = xmlGetProp(cur, (xmlChar *) "name");
05714             printf("Found Zone: %s", propChar);
05715 
05716             /* make a note of the zone_id */
05717             status = KsmZoneIdFromName((char *) propChar, &temp_id);
05718             xmlFree(propChar);
05719             if (status != 0) {
05720                 printf(" (zone not in database)");
05721                 zone_ids[i] = 0;
05722             } else {
05723                 zone_ids[i] = temp_id;
05724                 i++;
05725             }
05726 
05727             /* Print the policy name for this zone */
05728             for(pol = cur->children; pol != NULL; pol = pol->next)
05729             {
05730                 if (xmlStrcmp( pol->name, (const xmlChar *)"Policy") == 0)
05731                 {
05732                     polChar = xmlNodeGetContent(pol);
05733                     printf("; on policy %s\n", polChar);
05734                     xmlFree(polChar);
05735                 }
05736             }
05737         }
05738     }
05739 
05740     xmlFreeDoc(doc);
05741 
05742     return;
05743 }
05744 
05745 /*
05746  * Given a doc that has the start of the kasp-like xml and a policy structure
05747  * create the policy tag and contents in that doc
05748  */
05749 int append_policy(xmlDocPtr doc, KSM_POLICY *policy)
05750 {
05751     xmlNodePtr root;
05752     xmlNodePtr policy_node;
05753     xmlNodePtr signatures_node;
05754     xmlNodePtr validity_node;
05755     xmlNodePtr denial_node;
05756     xmlNodePtr nsec_node;
05757     xmlNodePtr hash_node;
05758     xmlNodePtr salt_node;
05759     xmlNodePtr keys_node;
05760     xmlNodePtr ksk_node;
05761     xmlNodePtr ksk_alg_node;
05762     xmlNodePtr zsk_node;
05763     xmlNodePtr zsk_alg_node;
05764     xmlNodePtr zone_node;
05765     xmlNodePtr zone_soa_node;
05766     xmlNodePtr parent_node;
05767     xmlNodePtr parent_ds_node;
05768     xmlNodePtr parent_soa_node;
05769 
05770     char temp_time[32];
05771    
05772     root = xmlDocGetRootElement(doc);
05773     if (root == NULL) {
05774         fprintf(stderr,"empty document\n");
05775         return(1);
05776     }
05777     if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) {
05778         fprintf(stderr,"document of the wrong type, root node != %s", "KASP");
05779         return(1);
05780     }
05781 
05782     policy_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Policy", NULL);
05783     (void) xmlNewProp(policy_node, (const xmlChar *)"name", (const xmlChar *)policy->name);
05784     (void) xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Description", (const xmlChar *)policy->description);
05785 
05786     /* SIGNATURES */
05787     signatures_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Signatures", NULL);
05788     snprintf(temp_time, 32, "PT%dS", policy->signature->resign);
05789     (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Resign", (const xmlChar *)temp_time);
05790     snprintf(temp_time, 32, "PT%dS", policy->signer->refresh);
05791     (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Refresh", (const xmlChar *)temp_time);
05792     validity_node = xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Validity", NULL);
05793     snprintf(temp_time, 32, "PT%dS", policy->signature->valdefault);
05794     (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Default", (const xmlChar *)temp_time);
05795     snprintf(temp_time, 32, "PT%dS", policy->signature->valdenial);
05796     (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Denial", (const xmlChar *)temp_time);
05797     snprintf(temp_time, 32, "PT%dS", policy->signer->jitter);
05798     (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Jitter", (const xmlChar *)temp_time);
05799     snprintf(temp_time, 32, "PT%dS", policy->signature->clockskew);
05800     (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"InceptionOffset", (const xmlChar *)temp_time);
05801 
05802     /* DENIAL */
05803     denial_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Denial", NULL);
05804     if (policy->denial->version == 1) /* NSEC */
05805     {
05806         (void) xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC", NULL);
05807     }
05808     else    /* NSEC3 */
05809     {
05810         nsec_node = xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC3", NULL);
05811         if (policy->denial->optout == 1)
05812         {
05813             (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"OptOut", NULL);
05814         }
05815         snprintf(temp_time, 32, "PT%dS", policy->denial->resalt);
05816         (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Resalt", (const xmlChar *)temp_time);
05817         hash_node = xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Hash", NULL);
05818         snprintf(temp_time, 32, "%d", policy->denial->algorithm);
05819         (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
05820         snprintf(temp_time, 32, "%d", policy->denial->iteration);
05821         (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Iteration", (const xmlChar *)temp_time);
05822         snprintf(temp_time, 32, "%d", policy->denial->saltlength);
05823         salt_node = xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Salt", NULL);
05824         (void) xmlNewProp(salt_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
05825     }
05826 
05827     /* KEYS */
05828     keys_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Keys", NULL);
05829     snprintf(temp_time, 32, "PT%dS", policy->keys->ttl);
05830     (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
05831     snprintf(temp_time, 32, "PT%dS", policy->keys->retire_safety);
05832     (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"RetireSafety", (const xmlChar *)temp_time);
05833     snprintf(temp_time, 32, "PT%dS", policy->keys->publish_safety);
05834     (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"PublishSafety", (const xmlChar *)temp_time);
05835     if (policy->keys->share_keys == 1)
05836     {
05837             (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ShareKeys", NULL);
05838     }
05839     if (policy->keys->purge != -1) {
05840         snprintf(temp_time, 32, "PT%dS", policy->keys->purge);
05841     (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"Purge", (const xmlChar *)temp_time);
05842     }
05843     /*(void) xmlNewDocComment(doc, (const xmlChar *)"Parameters that are different for zsks and ksks");*/
05844     /* KSK */
05845     ksk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"KSK", NULL);
05846     snprintf(temp_time, 32, "%d", policy->ksk->algorithm);
05847     ksk_alg_node = xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
05848     snprintf(temp_time, 32, "%d", policy->ksk->bits);
05849     (void) xmlNewProp(ksk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
05850     snprintf(temp_time, 32, "PT%dS", policy->ksk->lifetime);
05851     (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time);
05852     (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->ksk->sm_name);
05853     snprintf(temp_time, 32, "%d", policy->ksk->standby_keys);
05854     (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time);
05855     if (policy->ksk->manual_rollover == 1)
05856     {
05857         (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"ManualRollover", NULL);
05858     }
05859     if (policy->ksk->rfc5011 == 1)
05860     {
05861         (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RFC5011", NULL);
05862     }
05863 /*    if (policy->ksk->rollover_scheme != 0)
05864     {
05865         (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RolloverScheme", (const xmlChar *) KsmKeywordRollValueToName(policy->ksk->rollover_scheme));
05866     }*/
05867 
05868     /* ZSK */
05869     zsk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ZSK", NULL);
05870     snprintf(temp_time, 32, "%d", policy->zsk->algorithm);
05871     zsk_alg_node = xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
05872     snprintf(temp_time, 32, "%d", policy->zsk->bits);
05873     (void) xmlNewProp(zsk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
05874     snprintf(temp_time, 32, "PT%dS", policy->zsk->lifetime);
05875     (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time);
05876     (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->zsk->sm_name);
05877     snprintf(temp_time, 32, "%d", policy->zsk->standby_keys);
05878     (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time);
05879     if (policy->zsk->manual_rollover == 1)
05880     {
05881         (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"ManualRollover", NULL);
05882     }
05883 
05884     /* ZONE */
05885     zone_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Zone", NULL);
05886     snprintf(temp_time, 32, "PT%dS", policy->zone->propdelay);
05887     (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time);
05888     zone_soa_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SOA", NULL);
05889     snprintf(temp_time, 32, "PT%dS", policy->zone->soa_ttl);
05890     (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
05891     snprintf(temp_time, 32, "PT%dS", policy->zone->soa_min);
05892     (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time);
05893     (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Serial", (const xmlChar *) KsmKeywordSerialValueToName(policy->zone->serial));
05894 
05895     /* PARENT */
05896     parent_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Parent", NULL);
05897     snprintf(temp_time, 32, "PT%dS", policy->parent->propdelay);
05898     (void) xmlNewTextChild(parent_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time);
05899     parent_ds_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"DS", NULL);
05900     snprintf(temp_time, 32, "PT%dS", policy->parent->ds_ttl);
05901     (void) xmlNewTextChild(parent_ds_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
05902     parent_soa_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"SOA", NULL);
05903     snprintf(temp_time, 32, "PT%dS", policy->parent->soa_ttl);
05904     (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
05905     snprintf(temp_time, 32, "PT%dS", policy->parent->soa_min);
05906     (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time);
05907 
05908     /* AUDIT (Currently this either exists and is empty or it doesn't) */
05909     if (strncmp(policy->audit, "NULL", 4) != 0) {
05910         (void) xmlNewChild(policy_node, NULL, (const xmlChar *)"Audit", NULL);
05911     }
05912 
05913     return(0);
05914 }
05915 
05916 /*
05917  *  Delete a policy node from kasp.xml
05918  */
05919 xmlDocPtr del_policy_node(const char *docname,
05920                         const char *policy_name)
05921 {
05922     xmlDocPtr doc;
05923     xmlNodePtr root;
05924     xmlNodePtr cur;
05925 
05926     doc = xmlParseFile(docname);
05927     if (doc == NULL ) {
05928         fprintf(stderr,"Document not parsed successfully. \n");
05929         return (NULL);
05930     }
05931     root = xmlDocGetRootElement(doc);
05932     if (root == NULL) {
05933         fprintf(stderr,"empty document\n");
05934         xmlFreeDoc(doc);
05935         return (NULL);
05936     }
05937     if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) {
05938         fprintf(stderr,"document of the wrong type, root node != %s", "KASP");
05939         xmlFreeDoc(doc);
05940         return (NULL);
05941     }
05942 
05943 
05944     /* Policy nodes are children of the root */
05945     for(cur = root->children; cur != NULL; cur = cur->next)
05946     {
05947         /* is this the zone we are looking for? */
05948         if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) policy_name) == 0)
05949         {
05950             xmlUnlinkNode(cur);
05951 
05952             cur = root->children; /* May pass through multiple times, but will remove all instances of the policy */
05953         }
05954     }
05955     xmlFreeNode(cur);
05956 
05957     return(doc);
05958 }
05959 
05960 /*
05961  * CallBack to print key info to stdout
05962  */
05963 int printKey(void* context, KSM_KEYDATA* key_data)
05964 {
05965     if (key_data->state == KSM_STATE_RETIRE && strcasecmp(key_data->retire, (char *)context) == 0) {
05966         if (key_data->keytype == KSM_TYPE_KSK)
05967         {
05968             fprintf(stdout, "KSK:");
05969         }
05970         if (key_data->keytype == KSM_TYPE_ZSK)
05971         {
05972             fprintf(stdout, "ZSK:");
05973         }
05974         fprintf(stdout, " %s Retired\n", key_data->location);
05975     }
05976 
05977     return 0;
05978 }
05979 
05980 /*
05981  * log function suitable for libksm callback
05982  */
05983     void
05984 ksm_log_msg(const char *format)
05985 {
05986     fprintf(stderr, "%s\n", format);
05987 }
05988 
05989 /*+
05990  * ListKeys - Output a list of Keys
05991  *
05992  *
05993  * Arguments:
05994  *
05995  *      int zone_id
05996  *          ID of the zone (-1 for all)
05997  *
05998  * Returns:
05999  *      int
06000  *          Status return.  0 on success.
06001  *                          other on fail
06002  */
06003 
06004 int ListKeys(int zone_id)
06005 {
06006     char*       sql = NULL;     /* SQL query */
06007     int         status = 0;     /* Status return */
06008     char        stringval[KSM_INT_STR_SIZE];  /* For Integer to String conversion */
06009     DB_RESULT   result;         /* Result of the query */
06010     DB_ROW      row = NULL;     /* Row data */
06011     int         done_row = 0;   /* Have we printed a row this loop? */
06012 
06013     char*       temp_zone = NULL;   /* place to store zone name returned */
06014     int         temp_type = 0;      /* place to store key type returned */
06015     int         temp_state = 0;     /* place to store key state returned */
06016     char*       temp_ready = NULL;  /* place to store ready date returned */
06017     char*       temp_active = NULL; /* place to store active date returned */
06018     char*       temp_retire = NULL; /* place to store retire date returned */
06019     char*       temp_dead = NULL;   /* place to store dead date returned */
06020     char*       temp_loc = NULL;    /* place to store location returned */
06021     char*       temp_hsm = NULL;    /* place to store hsm returned */
06022     int         temp_alg = 0;       /* place to store algorithm returned */
06023 
06024     /* Key information */
06025     hsm_key_t *key = NULL;
06026     ldns_rr *dnskey_rr = NULL;
06027     hsm_sign_params_t *sign_params = NULL;
06028 
06029     if (verbose_flag) {
06030         /* connect to the HSM */
06031         status = hsm_open(config, hsm_prompt_pin, NULL);
06032         if (status) {
06033             hsm_print_error(NULL);
06034             return(-1);
06035         }
06036     }
06037 
06038     /* Select rows */
06039     StrAppend(&sql, "select z.name, k.keytype, k.state, k.ready, k.active, k.retire, k.dead, k.location, s.name, k.algorithm from securitymodules s, zones z, KEYDATA_VIEW k where z.id = k.zone_id and s.id = k.securitymodule_id and state != 6 and zone_id is not null ");
06040     if (zone_id != -1) {
06041         StrAppend(&sql, "and zone_id = ");
06042         snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
06043         StrAppend(&sql, stringval);
06044     }
06045     StrAppend(&sql, " order by zone_id");
06046 
06047     DusEnd(&sql);
06048 
06049     status = DbExecuteSql(DbHandle(), sql, &result);
06050 
06051     if (status == 0) {
06052         status = DbFetchRow(result, &row);
06053         if (verbose_flag == 1) {
06054             printf("Zone:                           Keytype:      State:    Date of next transition:  CKA_ID:                           Repository:                       Keytag:\n");
06055         }
06056         else {
06057             printf("Zone:                           Keytype:      State:    Date of next transition:\n");
06058         }
06059         while (status == 0) {
06060             /* Got a row, print it */
06061             DbString(row, 0, &temp_zone);
06062             DbInt(row, 1, &temp_type);
06063             DbInt(row, 2, &temp_state);
06064             DbString(row, 3, &temp_ready);
06065             DbString(row, 4, &temp_active);
06066             DbString(row, 5, &temp_retire);
06067             DbString(row, 6, &temp_dead);
06068             DbString(row, 7, &temp_loc);
06069             DbString(row, 8, &temp_hsm);
06070             DbInt(row, 9, &temp_alg);
06071             done_row = 0;
06072 
06073             if (temp_state == KSM_STATE_PUBLISH) {
06074                 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready);
06075                 done_row = 1;
06076             }
06077             else if (temp_state == KSM_STATE_READY) {
06078                 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_type == KSM_TYPE_KSK) ? "waiting for ds-seen" : "next rollover");
06079                 done_row = 1;
06080             }
06081             else if (temp_state == KSM_STATE_ACTIVE) {
06082                 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_retire == NULL) ? "(not scheduled)" : temp_retire);
06083                 done_row = 1;
06084             }
06085             else if (temp_state == KSM_STATE_RETIRE) {
06086                 printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_dead == NULL) ? "(not scheduled)" : temp_dead);
06087                 done_row = 1;
06088             }
06089             else if (temp_state == KSM_STATE_DSSUB) {
06090                 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "waiting for ds-seen");
06091                 done_row = 1;
06092             }
06093             else if (temp_state == KSM_STATE_DSPUBLISH) {
06094                 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready);
06095                 done_row = 1;
06096             }
06097             else if (temp_state == KSM_STATE_DSREADY) {
06098                 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "When required");
06099                 done_row = 1;
06100             }
06101             else if (temp_state == KSM_STATE_KEYPUBLISH) {
06102                 printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_active == NULL) ? "(not scheduled)" : temp_active);
06103                 done_row = 1;
06104             }
06105 
06106             if (done_row == 1 && verbose_flag == 1) {
06107                 key = hsm_find_key_by_id(NULL, temp_loc);
06108                 if (!key) {
06109                     printf("%-33s %s NOT IN repository\n", temp_loc, temp_hsm);
06110                 } else {
06111                     sign_params = hsm_sign_params_new();
06112                     sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, temp_zone);
06113                     sign_params->algorithm = temp_alg;
06114                     sign_params->flags = LDNS_KEY_ZONE_KEY;
06115                     if (temp_type == KSM_TYPE_KSK) {
06116                         sign_params->flags += LDNS_KEY_SEP_KEY;
06117                     }
06118                     dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
06119                     sign_params->keytag = ldns_calc_keytag(dnskey_rr);
06120 
06121                     printf("%-33s %-33s %d\n", temp_loc, temp_hsm, sign_params->keytag);
06122 
06123                     hsm_sign_params_free(sign_params);
06124                     hsm_key_free(key);
06125                 }
06126             }
06127             else if (done_row == 1) {
06128                 printf("\n");
06129             }
06130             
06131             status = DbFetchRow(result, &row);
06132         }
06133 
06134         /* Convert EOF status to success */
06135 
06136         if (status == -1) {
06137             status = 0;
06138         }
06139 
06140         DbFreeResult(result);
06141     }
06142 
06143     DusFree(sql);
06144     DbFreeRow(row);
06145 
06146     DbStringFree(temp_zone);
06147     DbStringFree(temp_ready);
06148     DbStringFree(temp_active);
06149     DbStringFree(temp_retire);
06150     DbStringFree(temp_dead);
06151     DbStringFree(temp_loc);
06152     DbStringFree(temp_hsm);
06153 
06154     if (dnskey_rr != NULL) {
06155         ldns_rr_free(dnskey_rr);
06156     }
06157 
06158     return status;
06159 }
06160 
06161 /*+
06162  * PurgeKeys - Purge dead Keys
06163  *
06164  *
06165  * Arguments:
06166  *
06167  *      int zone_id
06168  *          ID of the zone 
06169  *
06170  *      int policy_id
06171  *          ID of the policy
06172  *
06173  * N.B. Only one of the arguments should be set, the other should be -1
06174  *
06175  * Returns:
06176  *      int
06177  *          Status return.  0 on success.
06178  *                          other on fail
06179  */
06180 
06181 int PurgeKeys(int zone_id, int policy_id)
06182 {
06183     char*       sql = NULL;     /* SQL query */
06184     char*       sql1 = NULL;     /* SQL query */
06185     char*       sql2 = NULL;    /* SQL query */
06186     char*       sql3 = NULL;    /* SQL query */
06187     int         status = 0;     /* Status return */
06188     char        stringval[KSM_INT_STR_SIZE];  /* For Integer to String conversion */
06189     DB_RESULT   result;         /* Result of the query */
06190     DB_ROW      row = NULL;     /* Row data */
06191 
06192     int         temp_id = -1;       /* place to store the key id returned */
06193     char*       temp_loc = NULL;    /* place to store location returned */
06194     int         count = 0;          /* How many keys don't match the purge */
06195 
06196     int         done_something = 0; /* have we done anything? */
06197 
06198     /* Key information */
06199     hsm_key_t *key = NULL;
06200 
06201     if ((zone_id == -1 && policy_id == -1) || 
06202             (zone_id != -1 && policy_id != -1)){
06203         printf("Please provide either a zone OR a policy to key purge\n");
06204         usage_keypurge();
06205         return(1);
06206     }
06207 
06208     /* connect to the HSM */
06209     status = hsm_open(config, hsm_prompt_pin, NULL);
06210     if (status) {
06211         hsm_print_error(NULL);
06212         return(-1);
06213     }
06214 
06215     /* Select rows */
06216     StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 ");
06217     if (zone_id != -1) {
06218         StrAppend(&sql, "and zone_id = ");
06219         snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
06220         StrAppend(&sql, stringval);
06221     }
06222     if (policy_id != -1) {
06223         StrAppend(&sql, "and policy_id = ");
06224         snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id);
06225         StrAppend(&sql, stringval);
06226     }
06227     DusEnd(&sql);
06228 
06229     status = DbExecuteSql(DbHandle(), sql, &result);
06230 
06231     if (status == 0) {
06232         status = DbFetchRow(result, &row);
06233         while (status == 0) {
06234             /* Got a row, check it */
06235             DbInt(row, 0, &temp_id);
06236             DbString(row, 1, &temp_loc);
06237 
06238             sql1 = DqsCountInit("dnsseckeys");
06239             DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
06240             DdsConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1);
06241             DqsEnd(&sql1);
06242 
06243             status = DbIntQuery(DbHandle(), &count, sql1);
06244             DqsFree(sql1);
06245 
06246             if (status != 0) {
06247                 printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
06248                 DbStringFree(temp_loc);
06249                 DbFreeRow(row);
06250                 return status;
06251             }
06252 
06253             /* If the count is zero then there is no reason not to purge this key */
06254             if (count == 0) {
06255 
06256                 done_something = 1;
06257 
06258                 /* Delete from dnsseckeys */
06259                 sql2 = DdsInit("dnsseckeys");
06260                 DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
06261                 DdsEnd(&sql);
06262 
06263                 status = DbExecuteSqlNoResult(DbHandle(), sql2);
06264                 DdsFree(sql2);
06265                 if (status != 0)
06266                 {
06267                     printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
06268                     DbStringFree(temp_loc);
06269                     DbFreeRow(row);
06270                     return status;
06271                 }
06272 
06273                 /* Delete from keypairs */
06274                 sql3 = DdsInit("keypairs");
06275                 DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0);
06276                 DdsEnd(&sql);
06277 
06278                 status = DbExecuteSqlNoResult(DbHandle(), sql3);
06279                 DdsFree(sql3);
06280                 if (status != 0)
06281                 {
06282                     printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
06283                     DbStringFree(temp_loc);
06284                     DbFreeRow(row);
06285                     return status;
06286                 }
06287 
06288                 /* Delete from the HSM */
06289                 key = hsm_find_key_by_id(NULL, temp_loc);
06290 
06291                 if (!key) {
06292                     printf("Key not found: %s\n", temp_loc);
06293                     DbStringFree(temp_loc);
06294                     DbFreeRow(row);
06295                     return -1;
06296                 }
06297 
06298                 status = hsm_remove_key(NULL, key);
06299 
06300                 hsm_key_free(key);
06301 
06302                 if (!status) {
06303                     printf("Key remove successful.\n");
06304                 } else {
06305                     printf("Key remove failed.\n");
06306                     DbStringFree(temp_loc);
06307                     DbFreeRow(row);
06308                     return -1;
06309                 }
06310             }
06311 
06312             /* NEXT! */ 
06313             status = DbFetchRow(result, &row);
06314         }
06315 
06316         /* Convert EOF status to success */
06317 
06318         if (status == -1) {
06319             status = 0;
06320         }
06321 
06322         DbFreeResult(result);
06323     }
06324 
06325     if (done_something == 0) {
06326         printf("No keys to purge.\n");
06327     }
06328 
06329     DusFree(sql);
06330     DbFreeRow(row);
06331 
06332     DbStringFree(temp_loc);
06333 
06334     return status;
06335 }
06336 
06337 int cmd_genkeys()
06338 {
06339     int status = 0;
06340 
06341     int interval = -1;
06342 
06343     KSM_POLICY* policy;
06344     hsm_ctx_t *ctx = NULL;
06345 
06346     char *rightnow;
06347     int i = 0;
06348     char *id;
06349     hsm_key_t *key = NULL;
06350     char *hsm_error_message = NULL;
06351     DB_ID ignore = 0;
06352     int ksks_needed = 0;    /* Total No of ksks needed before next generation run */
06353     int zsks_needed = 0;    /* Total No of zsks needed before next generation run */
06354     int keys_in_queue = 0;  /* number of unused keys */
06355     int new_keys = 0;       /* number of keys required */
06356     unsigned int current_count = 0;  /* number of keys already in HSM */
06357 
06358     DB_RESULT result; 
06359     int zone_count = 0;     /* Number of zones on policy */
06360 
06361     int same_keys = 0;      /* Do ksks and zsks look the same ? */
06362     int ksks_created = 0;   /* Were any KSKs created? */
06363 
06364         /* Database connection details */
06365     DB_HANDLE   dbhandle;
06366     FILE* lock_fd = NULL;   /* This is the lock file descriptor for a SQLite DB */
06367 
06368     /* try to connect to the database */
06369     status = db_connect(&dbhandle, &lock_fd, 1);
06370     if (status != 0) {
06371         printf("Failed to connect to database\n");
06372         db_disconnect(lock_fd);
06373         return(1);
06374     }
06375 
06376     policy = KsmPolicyAlloc();
06377     if (policy == NULL) {
06378         printf("Malloc for policy struct failed\n");
06379         db_disconnect(lock_fd);
06380         exit(1);
06381     }
06382 
06383     if (o_policy == NULL) {
06384         printf("Please provide a policy name with the --policy option\n");
06385         db_disconnect(lock_fd);
06386         KsmPolicyFree(policy);
06387         return(1);
06388     }
06389     if (o_interval == NULL) {
06390         printf("Please provide an interval with the --interval option\n");
06391         db_disconnect(lock_fd);
06392         KsmPolicyFree(policy);
06393         return(1);
06394     }
06395 
06396     SetPolicyDefaults(policy, o_policy);
06397   
06398     status = KsmPolicyExists(o_policy);
06399     if (status == 0) {
06400         /* Policy exists */
06401         status = KsmPolicyRead(policy);
06402         if(status != 0) {
06403             printf("Error: unable to read policy %s from database\n", o_policy);
06404             db_disconnect(lock_fd);
06405             KsmPolicyFree(policy);
06406             return status;
06407         }
06408     } else {
06409         printf("Error: policy %s doesn't exist in database\n", o_policy);
06410         db_disconnect(lock_fd);
06411         KsmPolicyFree(policy);
06412         return status;
06413     }
06414 
06415     if  (policy->shared_keys == 1 ) {
06416         printf("Key sharing is On\n");
06417     } else {
06418         printf("Key sharing is Off\n");
06419     }
06420 
06421     status = DtXMLIntervalSeconds(o_interval, &interval);
06422     if (status > 0) {
06423         printf("Error: unable to convert Interval %s to seconds, error: ", o_interval);
06424         switch (status) {
06425             case 1: /* This has gone away, will now return 2 */
06426                 printf("invalid interval-type.\n");
06427                 break;
06428             case 2:
06429                 printf("unable to translate string.\n");
06430                 break;
06431             case 3:
06432                 printf("interval too long to be an int. E.g. Maximum is ~68 years on a system with 32-bit integers.\n");
06433                 break;
06434             case 4:
06435                 printf("invalid pointers or text string NULL.\n");
06436                 break;
06437             default:
06438                 printf("unknown\n");
06439         }
06440         db_disconnect(lock_fd);
06441         KsmPolicyFree(policy);
06442         return status;
06443     }
06444     else if (status == -1) {
06445         printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", o_interval);
06446     }
06447 
06448     /* Connect to the hsm */
06449     status = hsm_open(config, hsm_prompt_pin, NULL);
06450     if (status) {
06451         hsm_error_message = hsm_get_error(ctx);
06452         if (hsm_error_message) {
06453             printf("%s\n", hsm_error_message);
06454             free(hsm_error_message);
06455         } else {
06456             /* decode the error code ourselves 
06457                TODO find if there is a better way to do this (and can all of these be returned? are there others?) */
06458             switch (status) {
06459                 case HSM_ERROR:
06460                     printf("hsm_open() result: HSM error\n");
06461                     break;
06462                 case HSM_PIN_INCORRECT:
06463                     printf("hsm_open() result: incorrect PIN\n");
06464                     break;
06465                 case HSM_CONFIG_FILE_ERROR:
06466                     printf("hsm_open() result: config file error\n");
06467                     break;
06468                 case HSM_REPOSITORY_NOT_FOUND:
06469                     printf("hsm_open() result: repository not found\n");
06470                     break;
06471                 case HSM_NO_REPOSITORIES:
06472                     printf("hsm_open() result: no repositories\n");
06473                     break;
06474                 default:
06475                     printf("hsm_open() result: %d", status);
06476             }
06477         }
06478         db_disconnect(lock_fd);
06479         KsmPolicyFree(policy);
06480         exit(1);
06481     }
06482     printf("HSM opened successfully.\n");
06483     ctx = hsm_create_context();
06484 
06485     rightnow = DtParseDateTimeString("now");
06486 
06487     /* Check datetime in case it came back NULL */
06488     if (rightnow == NULL) {
06489         printf("Couldn't turn \"now\" into a date, quitting...\n");
06490         db_disconnect(lock_fd);
06491         KsmPolicyFree(policy);
06492         exit(1);
06493     }
06494 
06495     if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) {
06496         same_keys = 1;
06497     } else {
06498         same_keys = 0;
06499     }
06500 
06501     /* How many zones on this policy */ 
06502     status = KsmZoneCountInit(&result, policy->id); 
06503     if (status == 0) { 
06504         status = KsmZoneCount(result, &zone_count); 
06505     } 
06506     DbFreeResult(result); 
06507 
06508     if (status == 0) { 
06509         /* make sure that we have at least one zone */ 
06510         if (zone_count == 0) { 
06511             printf("No zones on policy %s, skipping...", policy->name);
06512             db_disconnect(lock_fd);
06513             if (ctx) {
06514                     hsm_destroy_context(ctx);
06515             }
06516             hsm_close();
06517             KsmPolicyFree(policy);
06518             return status; 
06519         } 
06520     } else {
06521         printf("Could not count zones on policy %s", policy->name);
06522         db_disconnect(lock_fd);
06523         if (ctx) {
06524                 hsm_destroy_context(ctx);
06525         }
06526         hsm_close();
06527         KsmPolicyFree(policy);
06528         return status; 
06529     }
06530 
06531     /* Find out how many ksk keys are needed for the POLICY */
06532     status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count);
06533     if (status != 0) {
06534         printf("Could not predict ksk requirement for next interval for %s\n", policy->name);
06535         /* TODO exit? continue with next policy? */
06536     }
06537     /* Find out how many suitable keys we have */
06538     status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_KSK);
06539     if (status != 0) {
06540         printf("Could not count current ksk numbers for policy %s\n", policy->name);
06541         /* TODO exit? continue with next policy? */
06542     }
06543     /* Correct for shared keys */
06544     if (policy->shared_keys == KSM_KEYS_SHARED) {
06545         keys_in_queue /= zone_count;
06546     }
06547 
06548     new_keys = ksks_needed - keys_in_queue;
06549     /* fprintf(stderr, "keygen(ksk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, ksks_needed, keys_in_queue); */
06550 
06551     /* Check capacity of HSM will not be exceeded */
06552     if (policy->ksk->sm_capacity != 0 && new_keys > 0) {
06553         current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name);
06554         if (current_count >= policy->ksk->sm_capacity) {
06555             printf("Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name);
06556             new_keys = 0;
06557         }
06558         else if (current_count + new_keys >  policy->ksk->sm_capacity) {
06559             printf("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);
06560             new_keys = policy->ksk->sm_capacity - current_count;
06561         }
06562     }
06563 
06564     /* Create the required keys */
06565     for (i=new_keys ; i > 0 ; i--){
06566         if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) {
06567             /* NOTE: for now we know that libhsm only supports RSA keys */
06568             key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits);
06569             if (key) {
06570                 if (verbose_flag) {
06571                     printf("Created key in repository %s\n", policy->ksk->sm_name);
06572                 }
06573             } else {
06574                 printf("Error creating key in repository %s\n", policy->ksk->sm_name);
06575                 hsm_error_message = hsm_get_error(ctx);
06576                 if (hsm_error_message) {
06577                     printf("%s\n", hsm_error_message);
06578                     free(hsm_error_message);
06579                 }
06580                 db_disconnect(lock_fd);
06581                 KsmPolicyFree(policy);
06582                 exit(1);
06583             }
06584             id = hsm_get_key_id(ctx, key);
06585             hsm_key_free(key);
06586             status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore);
06587             if (status != 0) {
06588                 printf("Error creating key in Database\n");
06589                 hsm_error_message = hsm_get_error(ctx);
06590                 if (hsm_error_message) {
06591                     printf("%s\n", hsm_error_message);
06592                     free(hsm_error_message);
06593                 }
06594                 db_disconnect(lock_fd);
06595                 KsmPolicyFree(policy);
06596                 exit(1);
06597             }
06598             printf("Created KSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->ksk->bits,
06599                     policy->ksk->algorithm, id, policy->ksk->sm_name);
06600             free(id);
06601         } else {
06602             printf("Key algorithm %d unsupported by libhsm.\n", policy->ksk->algorithm);
06603             db_disconnect(lock_fd);
06604             KsmPolicyFree(policy);
06605             exit(1);
06606         }
06607     }
06608     ksks_created = new_keys;
06609 
06610     /* Find out how many zsk keys are needed */
06611     keys_in_queue = 0;
06612     new_keys = 0;
06613     current_count = 0;
06614 
06615     /* Find out how many zsk keys are needed for the POLICY */
06616     status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, interval, &zsks_needed, 0, zone_count);
06617     if (status != 0) {
06618         printf("Could not predict zsk requirement for next interval for %s\n", policy->name);
06619         /* TODO exit? continue with next policy? */
06620     }
06621     /* Find out how many suitable keys we have */
06622     status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK);
06623     if (status != 0) {
06624         printf("Could not count current zsk numbers for policy %s\n", policy->name);
06625         /* TODO exit? continue with next policy? */
06626     }
06627     /* Correct for shared keys */
06628     if (policy->shared_keys == KSM_KEYS_SHARED) {
06629         keys_in_queue /= zone_count;
06630     }
06631     /* Might have to account for ksks */
06632     if (same_keys) {
06633         keys_in_queue -= ksks_needed;
06634     }
06635 
06636     new_keys = zsks_needed - keys_in_queue;
06637     /* fprintf(stderr, "keygen(zsk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, zsks_needed, keys_in_queue); */
06638 
06639     /* Check capacity of HSM will not be exceeded */
06640     if (policy->zsk->sm_capacity != 0 && new_keys > 0) {
06641         current_count = hsm_count_keys_repository(ctx, policy->zsk->sm_name);
06642         if (current_count >= policy->zsk->sm_capacity) {
06643             printf("Repository %s is full, cannot create more ZSKs for policy %s\n", policy->zsk->sm_name, policy->name);
06644             new_keys = 0;
06645         }
06646         else if (current_count + new_keys >  policy->zsk->sm_capacity) {
06647             printf("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);
06648             new_keys = policy->zsk->sm_capacity - current_count;
06649         }
06650     }
06651 
06652     /* Create the required keys */
06653     for (i = new_keys ; i > 0 ; i--) {
06654         if (hsm_supported_algorithm(policy->zsk->algorithm) == 0) {
06655             /* NOTE: for now we know that libhsm only supports RSA keys */
06656             key = hsm_generate_rsa_key(ctx, policy->zsk->sm_name, policy->zsk->bits);
06657             if (key) {
06658                 if (verbose_flag) {
06659                     printf("Created key in repository %s\n", policy->zsk->sm_name);
06660                 }
06661             } else {
06662                 printf("Error creating key in repository %s\n", policy->zsk->sm_name);
06663                 hsm_error_message = hsm_get_error(ctx);
06664                 if (hsm_error_message) {
06665                     printf("%s\n", hsm_error_message);
06666                     free(hsm_error_message);
06667                 }
06668                 db_disconnect(lock_fd);
06669                 KsmPolicyFree(policy);
06670                 exit(1);
06671             }
06672             id = hsm_get_key_id(ctx, key);
06673             hsm_key_free(key);
06674             status = KsmKeyPairCreate(policy->id, id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, rightnow, &ignore);
06675             if (status != 0) {
06676                 printf("Error creating key in Database\n");
06677                 hsm_error_message = hsm_get_error(ctx);
06678                 if (hsm_error_message) {
06679                     printf("%s\n", hsm_error_message);
06680                     free(hsm_error_message);
06681                 }
06682                 db_disconnect(lock_fd);
06683                 KsmPolicyFree(policy);
06684                 exit(1);
06685             }
06686             printf("Created ZSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->zsk->bits,
06687                     policy->zsk->algorithm, id, policy->zsk->sm_name);
06688             free(id);
06689         } else {
06690             printf("Key algorithm %d unsupported by libhsm.\n", policy->zsk->algorithm);
06691             db_disconnect(lock_fd);
06692             KsmPolicyFree(policy);
06693             exit(1);
06694         }
06695     }
06696     StrFree(rightnow);
06697 
06698     /* Log if a backup needs to be run for these keys */
06699     if (ksks_created && policy->ksk->require_backup) {
06700         printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->ksk->sm_name);
06701     }
06702     if (new_keys && policy->zsk->require_backup && (policy->zsk->sm != policy->ksk->sm)) {
06703         printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->zsk->sm_name);
06704     }
06705 
06706     /*
06707      * Destroy HSM context
06708      */
06709     if (ctx) {
06710         hsm_destroy_context(ctx);
06711     }
06712     status = hsm_close();
06713     printf("all done! hsm_close result: %d\n", status);
06714 
06715     KsmPolicyFree(policy);
06716     
06717     /* Release sqlite lock file (if we have it) */
06718     db_disconnect(lock_fd);
06719 
06720     return status;
06721 }
06722 
06723 /* Make sure (if we can) that the permissions on a file are correct for the user/group in conf.xml */
06724 
06725 int fix_file_perms(const char *dbschema)
06726 {
06727     struct stat stat_ret;
06728     
06729     int status = 0;
06730 
06731     xmlDocPtr doc = NULL;
06732     xmlDocPtr rngdoc = NULL;
06733     xmlXPathContextPtr xpathCtx = NULL;
06734     xmlXPathObjectPtr xpathObj = NULL;
06735     xmlRelaxNGParserCtxtPtr rngpctx = NULL;
06736     xmlRelaxNGValidCtxtPtr rngctx = NULL;
06737     xmlRelaxNGPtr schema = NULL;
06738     xmlChar *user_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/User";
06739     xmlChar *group_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/Group";
06740 
06741     char* filename = OPENDNSSEC_CONFIG_FILE;
06742     char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
06743     char* temp_char = NULL;
06744 
06745     struct passwd *pwd;
06746     struct group  *grp;
06747 
06748     int uid = -1;
06749     int gid = -1;
06750     char *username = NULL;
06751     char *groupname = NULL;
06752 
06753     printf("fixing permissions on file %s\n", dbschema);
06754     /* First see if we are running as root, if not then return */
06755     if (geteuid() != 0) {
06756         return 0;
06757     }
06758 
06759     /* Now see if the file exists, if it does not then return */
06760     if (stat(dbschema, &stat_ret) != 0) {
06761         printf("cannot stat file %s: %s", dbschema, strerror(errno));
06762         return -1;
06763     }
06764 
06765     /* OKAY... read conf.xml for the user and group */
06766     /* Load XML document */
06767     doc = xmlParseFile(filename);
06768     if (doc == NULL) {
06769         printf("Error: unable to parse file \"%s\"", filename);
06770         return(-1);
06771     }
06772 
06773     /* Load rng document */
06774     rngdoc = xmlParseFile(rngfilename);
06775     if (rngdoc == NULL) {
06776         printf("Error: unable to parse file \"%s\"", rngfilename);
06777         return(-1);
06778     }
06779 
06780     /* Create an XML RelaxNGs parser context for the relax-ng document. */
06781     rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
06782     if (rngpctx == NULL) {
06783         printf("Error: unable to create XML RelaxNGs parser context");
06784         return(-1);
06785     }
06786 
06787     /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
06788     schema = xmlRelaxNGParse(rngpctx);
06789     if (schema == NULL) {
06790         printf("Error: unable to parse a schema definition resource");
06791         return(-1);
06792     }
06793 
06794     /* Create an XML RelaxNGs validation context based on the given schema */
06795     rngctx = xmlRelaxNGNewValidCtxt(schema);
06796     if (rngctx == NULL) {
06797         printf("Error: unable to create RelaxNGs validation context based on the schema");
06798         return(-1);
06799     }
06800 
06801     /* Validate a document tree in memory. */
06802     status = xmlRelaxNGValidateDoc(rngctx,doc);
06803     if (status != 0) {
06804         printf("Error validating file \"%s\"", filename);
06805         return(-1);
06806     }
06807 
06808     /* Now parse a value out of the conf */
06809     /* Create xpath evaluation context */
06810     xpathCtx = xmlXPathNewContext(doc);
06811     if(xpathCtx == NULL) {
06812         printf("Error: unable to create new XPath context");
06813         xmlFreeDoc(doc);
06814         return(-1);
06815     }
06816 
06817     /* Set the group if specified */
06818     xpathObj = xmlXPathEvalExpression(group_expr, xpathCtx);
06819     if(xpathObj == NULL) {
06820         printf("Error: unable to evaluate xpath expression: %s", group_expr);
06821         xmlXPathFreeContext(xpathCtx);
06822         xmlFreeDoc(doc);
06823         return(-1);
06824     }
06825     if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
06826         temp_char = (char*) xmlXPathCastToString(xpathObj);
06827         StrAppend(&groupname, temp_char);
06828         StrFree(temp_char);
06829         xmlXPathFreeObject(xpathObj);
06830     } else {
06831         groupname = NULL;
06832     }
06833 
06834     /* Set the user to drop to if specified */
06835     xpathObj = xmlXPathEvalExpression(user_expr, xpathCtx);
06836     if(xpathObj == NULL) {
06837         printf("Error: unable to evaluate xpath expression: %s", user_expr);
06838         xmlXPathFreeContext(xpathCtx);
06839         xmlFreeDoc(doc);
06840         return(-1);
06841     }
06842     if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
06843         temp_char = (char*) xmlXPathCastToString(xpathObj);
06844         StrAppend(&username, temp_char);
06845         StrFree(temp_char);
06846         xmlXPathFreeObject(xpathObj);
06847     } else {
06848         username = NULL;
06849     }
06850 
06851     /* Free up the xml stuff, we are done with it */
06852     xmlXPathFreeContext(xpathCtx);
06853     xmlRelaxNGFree(schema);
06854     xmlRelaxNGFreeValidCtxt(rngctx);
06855     xmlRelaxNGFreeParserCtxt(rngpctx);
06856     xmlFreeDoc(doc);
06857     xmlFreeDoc(rngdoc);
06858 
06859     /* Set uid and gid if required */
06860     if (username != NULL) {
06861         /* Lookup the user id in /etc/passwd */
06862         if ((pwd = getpwnam(username)) == NULL) {
06863             printf("user '%s' does not exist. cannot chown %s...\n", username, dbschema);
06864             return(1);
06865         } else {
06866             uid = pwd->pw_uid;
06867         }
06868         endpwent();
06869     }
06870     if (groupname) {
06871         /* Lookup the group id in /etc/groups */
06872         if ((grp = getgrnam(groupname)) == NULL) {
06873             printf("group '%s' does not exist. cannot chown %s...\n", groupname, dbschema);
06874             exit(1);
06875         } else {
06876             gid = grp->gr_gid;
06877         }
06878         endgrent();
06879     }
06880 
06881     /* Change ownership of the db file */
06882     if (chown(dbschema, uid, gid) == -1) {
06883         printf("cannot chown(%u,%u) %s: %s",
06884                 (unsigned) uid, (unsigned) gid, dbschema, strerror(errno));
06885         return -1;
06886     }
06887 
06888     /* and change ownership of the lock file */
06889     temp_char = NULL;
06890     StrAppend(&temp_char, dbschema);
06891     StrAppend(&temp_char, ".our_lock");
06892 
06893     if (chown(temp_char, uid, gid) == -1) {
06894         printf("cannot chown(%u,%u) %s: %s",
06895                 (unsigned) uid, (unsigned) gid, temp_char, strerror(errno));
06896         StrFree(temp_char);
06897         return -1;
06898     }
06899 
06900     StrFree(temp_char);
06901 
06902     return 0;
06903 }
06904 
06905 /*+
06906  * CountKeys - Find how many Keys match our criteria
06907  *
06908  *
06909  * Arguments:
06910  *
06911  *      int zone_id
06912  *          ID of the zone (-1 for all)
06913  *
06914  *      int keytag
06915  *          keytag provided (-1 if not specified)
06916  *
06917  *      const char * cka_id
06918  *          cka_id provided (NULL if not)
06919  *
06920  *      int * key_count (returned)
06921  *          count of keys matching the information specified
06922  *
06923  *      char ** temp_cka_id (returned)
06924  *          cka_id of key found
06925  *
06926  *      int * temp_key_state (returned)
06927  *          What state is the key in (only used if _one_ key returned)
06928  *
06929  *      int * temp_keypair_id (returned)
06930  *          ID of the key found (only used if _one_ key returned)
06931  * Returns:
06932  *      int
06933  *          Status return.  0 on success.
06934  *                          other on fail
06935  */
06936 
06937 int CountKeys(int *zone_id, int keytag, const char *cka_id, int *key_count, char **temp_cka_id, int *temp_key_state, int *temp_keypair_id)
06938 {
06939     char*       sql = NULL;     /* SQL query */
06940     int         status = 0;     /* Status return */
06941     char        stringval[KSM_INT_STR_SIZE];  /* For Integer to String conversion */
06942     DB_RESULT   result;         /* Result of the query */
06943     DB_ROW      row = NULL;     /* Row data */
06944 
06945     char    buffer[256];    /* For constructing part of the command */
06946     size_t  nchar;          /* Number of characters written */
06947 
06948     int         done_row = 0;   /* Have we found a key this loop? */
06949 
06950     int         temp_zone_id = 0;   /* place to store zone_id returned */
06951     char*       temp_loc = NULL;    /* place to store location returned */
06952     int         temp_alg = 0;       /* place to store algorithm returned */
06953     int         temp_state = 0;     /* place to store state returned */
06954     int         temp_keypair = 0;   /* place to store id returned */
06955 
06956     int         temp_count = 0;     /* Count of keys found */
06957 
06958     /* Key information */
06959     hsm_key_t *key = NULL;
06960     ldns_rr *dnskey_rr = NULL;
06961     hsm_sign_params_t *sign_params = NULL;
06962 
06963     /* connect to the HSM */
06964     status = hsm_open(config, hsm_prompt_pin, NULL);
06965     if (status) {
06966         hsm_print_error(NULL);
06967         return(-1);
06968     }
06969 
06970     /* Select rows */
06971     nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d)",
06972         KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB);
06973     if (nchar >= sizeof(buffer)) {
06974         printf("Error: Overran buffer in CountKeys\n");
06975         return(-1);
06976     }
06977 
06978     /* TODO do I need to use the view */
06979     StrAppend(&sql, "select k.zone_id, k.location, k.algorithm, k.state, k.id from KEYDATA_VIEW k where state in ");
06980     StrAppend(&sql, buffer);
06981     StrAppend(&sql, " and zone_id is not null and k.keytype = 257");
06982 
06983     if (*zone_id != -1) {
06984         StrAppend(&sql, " and zone_id = ");
06985         snprintf(stringval, KSM_INT_STR_SIZE, "%d", *zone_id);
06986         StrAppend(&sql, stringval);
06987     }
06988     if (cka_id != NULL) {
06989         StrAppend(&sql, " and k.location = '");
06990         StrAppend(&sql, cka_id);
06991         StrAppend(&sql, "'");
06992     }
06993     /* where location is unique? */
06994     StrAppend(&sql, " group by location");
06995 
06996     DusEnd(&sql);
06997 
06998     status = DbExecuteSql(DbHandle(), sql, &result);
06999 
07000     /* loop round printing out the cka_id of any key that matches
07001      * if only one does then we are good, if not then we will write a 
07002      * message asking for further clarification */
07003     /* Note that we only need to do each key, not each instance of a key */
07004     if (status == 0) {
07005         status = DbFetchRow(result, &row);
07006         while (status == 0) {
07007             /* Got a row, process it */
07008             DbInt(row, 0, &temp_zone_id);
07009             DbString(row, 1, &temp_loc);
07010             DbInt(row, 2, &temp_alg);
07011             DbInt(row, 3, &temp_state);
07012             DbInt(row, 4, &temp_keypair);
07013 
07014             done_row = 0;
07015 
07016             if (keytag == -1 && cka_id == NULL)
07017             {
07018                 *temp_key_state = temp_state;
07019             }
07020 
07021             key = hsm_find_key_by_id(NULL, temp_loc);
07022             if (!key) {
07023                 printf("cka_id %-33s in DB but NOT IN repository\n", temp_loc);
07024             } else if (keytag != -1) {
07025                 sign_params = hsm_sign_params_new();
07026                 sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "temp_zone");
07027                 sign_params->algorithm = temp_alg;
07028                 sign_params->flags = LDNS_KEY_ZONE_KEY;
07029                 sign_params->flags += LDNS_KEY_SEP_KEY;
07030 
07031                 dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
07032                 sign_params->keytag = ldns_calc_keytag(dnskey_rr);
07033 
07034                 /* Have we matched our keytag? */
07035                 if (keytag == sign_params->keytag) {
07036                     temp_count++;
07037                     done_row = 1;
07038                     *temp_cka_id = NULL;
07039                     StrAppend(temp_cka_id, temp_loc);
07040                     *zone_id = temp_zone_id;
07041                     *temp_key_state = temp_state;
07042                     *temp_keypair_id = temp_keypair;
07043                     printf("Found key with CKA_ID %s\n", temp_loc);
07044                 }
07045 
07046                 hsm_sign_params_free(sign_params);
07047             }
07048             if (key && cka_id != NULL && strncmp(cka_id, temp_loc, strlen(temp_loc)) == 0) {
07049                 /* Or have we matched a provided cka_id */
07050                 if (done_row == 0) {
07051                     temp_count++;
07052                     *temp_cka_id = NULL;
07053                     StrAppend(temp_cka_id, temp_loc);
07054                     *zone_id = temp_zone_id;
07055                     *temp_key_state = temp_state;
07056                     *temp_keypair_id = temp_keypair;
07057                     printf("Found key with CKA_ID %s\n", temp_loc);
07058                 }
07059             }
07060 
07061             if (key) {
07062                 hsm_key_free(key);
07063             }
07064             
07065             status = DbFetchRow(result, &row);
07066         }
07067 
07068         /* Convert EOF status to success */
07069 
07070         if (status == -1) {
07071             status = 0;
07072         }
07073 
07074         DbFreeResult(result);
07075     }
07076 
07077     *key_count = temp_count;
07078 
07079     DusFree(sql);
07080     DbFreeRow(row);
07081 
07082     DbStringFree(temp_loc);
07083 
07084     if (dnskey_rr != NULL) {
07085         ldns_rr_free(dnskey_rr);
07086     }
07087 
07088     return status;
07089 }
07090 
07091 /*+
07092  * MarkDSSeen - Indicate that the DS record has been observed:
07093  *              Change the state of the key to ACTIVE
07094  *
07095  * Arguments:
07096  *
07097  *      const char * cka_id
07098  *          cka_id of key to make active
07099  *
07100  *      int zone_id
07101  *          ID of the zone
07102  *
07103  *      int policy_id
07104  *          ID of the policy
07105  *
07106  *      const char * datetime
07107  *          when this is happening
07108  *
07109  *      int key_state
07110  *          state that the key is in
07111  *
07112  * Returns:
07113  *      int
07114  *          Status return.  0 on success.
07115  *                          other on fail
07116  */
07117 
07118 int MarkDSSeen(int keypair_id, int zone_id, int policy_id, const char *datetime, int key_state)
07119 {
07120     char*       sql1 = NULL;    /* SQL query */
07121     int         status = 0;     /* Status return */
07122 
07123     char            buffer[KSM_SQL_SIZE];    /* Long enough for any statement */
07124     unsigned int    nchar;          /* Number of characters converted */
07125     
07126     KSM_PARCOLL         collection;     /* Collection of parameters for zone */
07127     int deltat;     /* Time interval */
07128 
07129     (void)      zone_id;
07130 
07131     /* Set collection defaults */
07132     KsmCollectionInit(&collection);
07133 
07134     /* Get the values of the parameters */
07135     status = KsmParameterCollection(&collection, policy_id);
07136     if (status != 0) {
07137         printf("Error: failed to read policy\n");
07138         return status;
07139     }
07140 
07141 /* 0) Start a transaction */
07142     status = DbBeginTransaction();
07143     if (status != 0) {
07144         /* Something went wrong */
07145 
07146         MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07147         return status;
07148     }
07149 
07150     /* 1) Change the state of the selected Key */
07151     if (key_state == KSM_STATE_READY) {
07152         /* We are making a key active */
07153 
07154         /* Set the interval until Retire */
07155         deltat = collection.ksklife;
07156 
07157 #ifdef USE_MYSQL
07158         nchar = snprintf(buffer, sizeof(buffer),
07159                 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07160 #else
07161         nchar = snprintf(buffer, sizeof(buffer),
07162                 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07163 #endif /* USE_MYSQL */
07164 
07165         sql1 = DusInit("dnsseckeys");
07166         DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0);
07167         DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_ACTIVE), datetime, 1);
07168         StrAppend(&sql1, ", RETIRE = ");
07169         StrAppend(&sql1, buffer);
07170 
07171         DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
07172         DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07173         DusEnd(&sql1);
07174     }
07175     else {
07176         /* We are making a standby key DSpublish */
07177 
07178         /* Set the interval until DSReady */
07179         deltat = collection.kskttl + collection.kskpropdelay + 
07180             collection.pub_safety;
07181 
07182 #ifdef USE_MYSQL
07183         nchar = snprintf(buffer, sizeof(buffer),
07184                 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07185 #else
07186         nchar = snprintf(buffer, sizeof(buffer),
07187                 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07188 #endif /* USE_MYSQL */
07189 
07190         sql1 = DusInit("dnsseckeys");
07191         DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0);
07192         DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_PUBLISH), datetime, 1);
07193         StrAppend(&sql1, ", READY = ");
07194         StrAppend(&sql1, buffer);
07195 
07196         DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
07197         DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07198         DusEnd(&sql1);
07199     }
07200 
07201     status = DbExecuteSqlNoResult(DbHandle(), sql1);
07202     DusFree(sql1);
07203 
07204     /* Report any errors */
07205     if (status != 0) {
07206         status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07207         DbRollback();
07208         return status;
07209     }
07210 
07211     /* 3) Commit or Rollback */
07212     if (status == 0) { /* It actually can't be anything else */
07213         /* Everything worked by the looks of it */
07214         DbCommit();
07215     } else {
07216         /* Whatever happened, it was not good */
07217         DbRollback();
07218     }
07219 
07220     return status;
07221 }
07222 
07223 /*+
07224  * RetireOldKey - Retire the old KSK
07225  *
07226  *
07227  * Arguments:
07228  *
07229  *      int zone_id
07230  *          ID of the zone
07231  *
07232  *      int policy_id
07233  *          ID of the policy
07234  *
07235  *      const char * datetime
07236  *          when this is happening
07237  *
07238  * Returns:
07239  *      int
07240  *          Status return.  0 on success.
07241  *                          other on fail
07242  */
07243 
07244 int RetireOldKey(int zone_id, int policy_id, const char *datetime)
07245 {
07246     char*       sql2 = NULL;    /* SQL query */
07247     int         status = 0;     /* Status return */
07248     char*       where_clause = NULL;
07249     int         id = -1;        /* ID of key to retire */
07250 
07251     char        stringval[KSM_INT_STR_SIZE];  /* For Integer to String conversion */
07252     char            buffer[KSM_SQL_SIZE];    /* Long enough for any statement */
07253     unsigned int    nchar;          /* Number of characters converted */
07254     
07255     KSM_PARCOLL         collection;     /* Collection of parameters for zone */
07256     int deltat;     /* Time interval */
07257 
07258     /* Set collection defaults */
07259     KsmCollectionInit(&collection);
07260 
07261     /* Get the values of the parameters */
07262     status = KsmParameterCollection(&collection, policy_id);
07263     if (status != 0) {
07264         printf("Error: failed to read policy\n");
07265         return status;
07266     }
07267 
07268 /* 0) Start a transaction */
07269     status = DbBeginTransaction();
07270     if (status != 0) {
07271         /* Something went wrong */
07272 
07273         MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07274         return status;
07275     }
07276 
07277     /* 1) Retire the oldest active key, and set its deadtime */
07278     /* work out which key */
07279     snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
07280     StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
07281     StrAppend(&where_clause, stringval);
07282     StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
07283     StrAppend(&where_clause, stringval);
07284     StrAppend(&where_clause, ")");
07285 
07286     /* Execute query and free up the query string */
07287     status = DbIntQuery(DbHandle(), &id, where_clause);
07288     StrFree(where_clause);
07289     if (status != 0)
07290     {
07291         printf("Error: failed to find ID of key to retire\n");
07292         DbRollback();
07293         return status;
07294         }
07295 
07296     /* work out what its deadtime should become */
07297     deltat = collection.dsttl + collection.kskpropdelay + collection.ret_safety;
07298 
07299 #ifdef USE_MYSQL
07300     nchar = snprintf(buffer, sizeof(buffer),
07301         "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07302 #else
07303     nchar = snprintf(buffer, sizeof(buffer),
07304         "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07305 #endif /* USE_MYSQL */
07306 
07307     sql2 = DusInit("dnsseckeys");
07308     DusSetInt(&sql2, "STATE", KSM_STATE_RETIRE, 0);
07309     DusSetString(&sql2, KsmKeywordStateValueToName(KSM_STATE_RETIRE), datetime, 1);
07310     StrAppend(&sql2, ", DEAD = ");
07311     StrAppend(&sql2, buffer);
07312     DusConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, id, 0);
07313     DusConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07314 
07315     status = DbExecuteSqlNoResult(DbHandle(), sql2);
07316     DusFree(sql2);
07317 
07318     /* Report any errors */
07319     if (status != 0) {
07320         status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07321         DbRollback();
07322         return status;
07323     }
07324 
07325     /* 2) Commit or Rollback */
07326     if (status == 0) { /* It actually can't be anything else */
07327         /* Everything worked by the looks of it */
07328         DbCommit();
07329     } else {
07330         /* Whatever happened, it was not good */
07331         DbRollback();
07332     }
07333 
07334     return status;
07335 }
07336 
07337 /*
07338  * CountKeysInState - Count Keys in given state
07339  *
07340  * Description:
07341  *      Counts the number of keys in the given state.
07342  *
07343  * Arguments:
07344  *      int keytype
07345  *          Either KSK or ZSK, depending on the key type
07346  *
07347  *      int keystate
07348  *          State of keys to count
07349  *
07350  *      int* count
07351  *          Number of keys meeting the condition.
07352  *
07353  *      int zone_id
07354  *          ID of zone that we are looking at (-1 == all zones)
07355  *
07356  * Returns:
07357  *      int
07358  *          Status return. 0 => success, Other => error, in which case a message
07359  *          will have been output.
07360 -*/
07361 
07362 int CountKeysInState(int keytype, int keystate, int* count, int zone_id)
07363 {
07364     int     clause = 0;     /* Clause counter */
07365     char*   sql = NULL;     /* SQL command */
07366     int     status;         /* Status return */
07367 
07368     sql = DqsCountInit("KEYDATA_VIEW");
07369     DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
07370     DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, keystate, clause++);
07371     if (zone_id != -1) {
07372         DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
07373     }
07374     DqsEnd(&sql);
07375 
07376     status = DbIntQuery(DbHandle(), count, sql);
07377     DqsFree(sql);
07378 
07379     if (status != 0) {
07380         printf("Error in CountKeysInState\n");
07381     }
07382 
07383     return status;
07384 }
07385 
07386 /*+
07387  * ChangeKeyState - Change the state of the specified key
07388  *
07389  * Arguments:
07390  *
07391  *      int keytype
07392  *          type of key we are dealing with
07393  *
07394  *      const char * cka_id
07395  *          cka_id of key to change
07396  *
07397  *      int zone_id
07398  *          ID of the zone
07399  *
07400  *      int policy_id
07401  *          ID of the policy
07402  *
07403  *      const char * datetime
07404  *          when this is happening
07405  *
07406  *      int keystate
07407  *          state that the key should be moved to
07408  *
07409  * Returns:
07410  *      int
07411  *          Status return.  0 on success.
07412  *                          other on fail
07413  *
07414  *  TODO take keytimings out of here
07415  */
07416 
07417 int ChangeKeyState(int keytype, const char *cka_id, int zone_id, int policy_id, const char *datetime, int keystate)
07418 {
07419     char*       sql1 = NULL;    /* SQL query */
07420     int         status = 0;     /* Status return */
07421 
07422     int     count = 0;      /* Count of keys whose date will be set */
07423     char*   sql = NULL;     /* For creating the SQL command */
07424     int     where = 0;      /* For the SQL selection */
07425     int     i = 0;          /* A counter */
07426     int     j = 0;          /* Another counter */
07427     char*   insql = NULL;   /* SQL "IN" clause */
07428     int*    keyids;         /* List of IDs of keys to promote */
07429     DB_RESULT    result;    /* List result set */
07430     KSM_KEYDATA  data;      /* Data for this key */
07431 
07432     char            buffer[KSM_SQL_SIZE];    /* Long enough for any statement */
07433     unsigned int    nchar;          /* Number of characters converted */
07434     
07435     KSM_PARCOLL         collection;     /* Collection of parameters for zone */
07436     int deltat = 0;     /* Time interval */
07437 
07438     (void)      zone_id;
07439 
07440     /* Set collection defaults */
07441     KsmCollectionInit(&collection);
07442 
07443     /* Get the values of the parameters */
07444     status = KsmParameterCollection(&collection, policy_id);
07445     if (status != 0) {
07446         printf("Error: failed to read policy\n");
07447         return status;
07448     }
07449 
07450     /* Count how many keys will have their state changed */
07451 
07452     sql = DqsCountInit("KEYDATA_VIEW");
07453     DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++);
07454     if (zone_id != -1) {
07455         DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
07456     }
07457     DqsEnd(&sql);
07458 
07459     status = DbIntQuery(DbHandle(), &count, sql);
07460     DqsFree(sql);
07461 
07462     if (status != 0) {
07463         status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07464         return status;
07465     }
07466 
07467     if (count == 0) {
07468         /* Nothing to do, error? */
07469         return status;
07470     }
07471 
07472     /* Allocate space for the list of key IDs */
07473     keyids = MemMalloc(count * sizeof(int));
07474 
07475     /* Get the list of IDs */
07476 
07477     where = 0;
07478     sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
07479     DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++);
07480     if (zone_id != -1) {
07481         DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
07482     }
07483     DqsEnd(&sql);
07484 
07485     status = KsmKeyInitSql(&result, sql);
07486     DqsFree(sql);
07487 
07488     if (status == 0) {
07489         while (status == 0) {
07490             status = KsmKey(result, &data);
07491             if (status == 0) {
07492                 keyids[i] = data.keypair_id;
07493                 i++;
07494             }
07495         }
07496 
07497         /* Convert EOF status to success */
07498 
07499         if (status == -1) {
07500             status = 0;
07501         } else {
07502             status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07503             StrFree(keyids);
07504             return status;
07505         }
07506 
07507         KsmKeyEnd(result);
07508 
07509     } else {
07510         status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07511         StrFree(keyids);
07512                 return status;
07513         }
07514     
07515     /*
07516      * Now construct the "IN" statement listing the IDs of the keys we
07517      * are planning to change the state of.
07518      */
07519 
07520     StrAppend(&insql, "(");
07521     for (j = 0; j < i; ++j) {
07522         if (j != 0) {
07523             StrAppend(&insql, ",");
07524         }
07525         snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
07526         StrAppend(&insql, buffer);
07527     }
07528     StrAppend(&insql, ")");
07529 
07530 /* 0) Start a transaction */
07531     status = DbBeginTransaction();
07532     if (status != 0) {
07533         /* Something went wrong */
07534 
07535         MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07536         StrFree(keyids);
07537         return status;
07538     }
07539 
07540     /* 1) Change the state of the selected Key */
07541     if (keystate == KSM_STATE_ACTIVE) {
07542         /* We are making a key active */
07543 
07544         /* Set the interval until Retire */
07545         deltat = collection.ksklife;
07546 
07547 #ifdef USE_MYSQL
07548         nchar = snprintf(buffer, sizeof(buffer),
07549                 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07550 #else
07551         nchar = snprintf(buffer, sizeof(buffer),
07552                 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07553 #endif /* USE_MYSQL */
07554 
07555         sql1 = DusInit("dnsseckeys");
07556         DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0);
07557         DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_ACTIVE), datetime, 1);
07558         StrAppend(&sql1, ", RETIRE = ");
07559         StrAppend(&sql1, buffer);
07560 
07561         DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
07562         if (zone_id != -1) {
07563             DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07564         }
07565         DusEnd(&sql1);
07566     }
07567     else if (keystate == KSM_STATE_RETIRE) {
07568         /* We are making a key retired */
07569 
07570         /* Set the interval until Dead */
07571         if (keytype == KSM_TYPE_ZSK) {
07572             deltat = collection.zsksiglife + collection.propdelay + collection.ret_safety;
07573         }
07574         else if (keytype == KSM_TYPE_KSK) {
07575             deltat = collection.kskttl + collection.kskpropdelay + 
07576                 collection.ret_safety; /* Ipp */
07577         }
07578 
07579 #ifdef USE_MYSQL
07580         nchar = snprintf(buffer, sizeof(buffer),
07581                 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07582 #else
07583         nchar = snprintf(buffer, sizeof(buffer),
07584                 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07585 #endif /* USE_MYSQL */
07586 
07587         sql1 = DusInit("dnsseckeys");
07588         DusSetInt(&sql1, "STATE", KSM_STATE_RETIRE, 0);
07589         DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_RETIRE), datetime, 1);
07590         StrAppend(&sql1, ", DEAD = ");
07591         StrAppend(&sql1, buffer);
07592 
07593         DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
07594         if (zone_id != -1) {
07595             DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07596         }
07597         DusEnd(&sql1);
07598     }
07599     else if (keystate == KSM_STATE_DSPUBLISH) {
07600         /* Set the interval until DSReady */
07601         deltat = collection.kskttl + collection.kskpropdelay + 
07602             collection.pub_safety;
07603 
07604 #ifdef USE_MYSQL
07605         nchar = snprintf(buffer, sizeof(buffer),
07606                 "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
07607 #else
07608         nchar = snprintf(buffer, sizeof(buffer),
07609                 "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
07610 #endif /* USE_MYSQL */
07611 
07612         sql1 = DusInit("dnsseckeys");
07613         DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0);
07614         DusSetString(&sql1, KsmKeywordStateValueToName(KSM_STATE_PUBLISH), datetime, 1);
07615         StrAppend(&sql1, ", READY = ");
07616         StrAppend(&sql1, buffer);
07617 
07618         DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
07619         if (zone_id != -1) {
07620             DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
07621         }
07622         DusEnd(&sql1);
07623     }
07624     else {
07625         printf("Moving to keystate %s not implemented yet\n", KsmKeywordStateValueToName(keystate));
07626         StrFree(keyids);
07627         return -1;
07628     }
07629 
07630     status = DbExecuteSqlNoResult(DbHandle(), sql1);
07631     DusFree(sql1);
07632 
07633     StrFree(keyids);
07634     
07635     /* Report any errors */
07636     if (status != 0) {
07637         status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
07638         DbRollback();
07639         return status;
07640     }
07641 
07642     /* 3) Commit or Rollback */
07643     if (status == 0) { /* It actually can't be anything else */
07644         /* Everything worked by the looks of it */
07645         DbCommit();
07646     } else {
07647         /* Whatever happened, it was not good */
07648         DbRollback();
07649     }
07650 
07651     return status;
07652 }
07653 
07654 static int restart_enforcerd()
07655 {
07656         /* ToDo: This should really be rewritten so that it will read
07657            OPENDNSSEC_ENFORCER_PIDFILE and send a SIGHUP itself */
07658         return system(RESTART_ENFORCERD_CMD);
07659 }
07660 
07661 /* 
07662  *  Read the conf.xml file, we will not validate as that was done as we read the database.
07663  *  Instead we just extract the RepositoryList into the database and also learn the 
07664  *  location of the zonelist.
07665  */
07666 int get_conf_key_info(int* interval, int* man_key_gen)
07667 {
07668     int status = 0;
07669     int mysec = 0;
07670     xmlDocPtr doc = NULL;
07671     xmlXPathContextPtr xpathCtx = NULL;
07672     xmlXPathObjectPtr xpathObj = NULL;
07673     char* temp_char = NULL;
07674 
07675     xmlChar *iv_expr = (unsigned char*) "//Configuration/Enforcer/Interval";
07676     xmlChar *mk_expr = (unsigned char*) "//Configuration/Enforcer/ManualKeyGeneration";
07677 
07678     /* Load XML document */
07679     doc = xmlParseFile(config);
07680     if (doc == NULL) {
07681         printf("Error: unable to parse file \"%s\"\n", config);
07682         return(-1);
07683     }
07684 
07685     /* Create xpath evaluation context */
07686     xpathCtx = xmlXPathNewContext(doc);
07687     if(xpathCtx == NULL) {
07688         printf("Error: unable to create new XPath context\n");
07689         xmlFreeDoc(doc);
07690         return(-1);
07691     }
07692     
07693     /* Evaluate xpath expression for interval */
07694     xpathObj = xmlXPathEvalExpression(iv_expr, xpathCtx);
07695     if(xpathObj == NULL) {
07696         printf("Error: unable to evaluate xpath expression: %s", iv_expr);
07697         xmlXPathFreeContext(xpathCtx);
07698         xmlFreeDoc(doc);
07699         return(-1);
07700     }
07701 
07702     temp_char = (char *)xmlXPathCastToString(xpathObj);
07703     status = DtXMLIntervalSeconds(temp_char, &mysec);
07704     if (status > 0) {
07705         printf("Error: unable to convert Interval %s to seconds, error: %i\n", temp_char, status);
07706         StrFree(temp_char);
07707         return status;
07708     }
07709     else if (status == -1) {
07710         printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char);
07711     }
07712     *interval = mysec;
07713     StrFree(temp_char);
07714     xmlXPathFreeObject(xpathObj);
07715 
07716     /* Evaluate xpath expression for Manual key generation */
07717     xpathObj = xmlXPathEvalExpression(mk_expr, xpathCtx);
07718     if(xpathObj == NULL) {
07719         printf("Error: unable to evaluate xpath expression: %s\n", mk_expr);
07720         xmlXPathFreeContext(xpathCtx);
07721         xmlFreeDoc(doc);
07722         return(-1);
07723     }
07724 
07725     if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
07726         /* Manual key generation tag is present */
07727         *man_key_gen = 1;
07728     }
07729     else {
07730         /* Tag absent */
07731         *man_key_gen = 0;
07732     }
07733     xmlXPathFreeObject(xpathObj);
07734 
07735     if (xpathCtx) {
07736         xmlXPathFreeContext(xpathCtx);
07737     }
07738     if (doc) {
07739         xmlFreeDoc(doc);
07740     }
07741 
07742     return 0;
07743 }
07744 
07745 /* TODO put this fn and the one below somewhere that we can call it from here and the enforcer */
07746  /*+
07747  * LinkKeys - Create required entries in Dnsseckeys table for zones added to policies
07748  *                      (i.e. when keysharing is turned on)
07749  *
07750  * Description:
07751  *      Allocates a key in the database.
07752  *
07753  * Arguments:
07754  *      const char* zone_name
07755  *          name of zone
07756  *
07757  *      int policy_id
07758  *          ID of policy which the zone is on
07759  *
07760  *      int interval
07761  *          Enforcer run interval
07762  *
07763  *      int man_key_gen
07764  *          Manual Key Generation flag
07765  *
07766  * Returns:
07767  *      int
07768  *          Status return.  0=> Success, non-zero => error.
07769 -*/
07770 
07771 int LinkKeys(const char* zone_name, int policy_id)
07772 {
07773     int status = 0;
07774 
07775     int interval = -1;          /* Enforcer interval */
07776     int man_key_gen = -1;       /* Manual key generation flag */
07777 
07778     int             zone_id = 0;    /* id of zone supplied */ 
07779     KSM_POLICY* policy;
07780 
07781     /* Unused parameter */
07782     (void)policy_id;
07783 
07784     /* Get some info from conf.xml */
07785     status = get_conf_key_info(&interval, &man_key_gen);
07786     if (status != 0) {
07787         printf("Failed to Link Keys to zone\n");
07788         return(1);
07789     }
07790 
07791     status = KsmZoneIdFromName(zone_name, &zone_id);
07792     if (status != 0) {
07793         return(status);
07794     }
07795 
07796     policy = KsmPolicyAlloc();
07797     if (policy == NULL) {
07798         printf("Malloc for policy struct failed\n");
07799         exit(1);
07800     }
07801     SetPolicyDefaults(policy, o_policy);
07802 
07803     status = KsmPolicyExists(o_policy);
07804     if (status == 0) {
07805         /* Policy exists */
07806         status = KsmPolicyRead(policy);
07807         if(status != 0) {
07808             printf("Error: unable to read policy %s from database\n", o_policy);
07809             KsmPolicyFree(policy);
07810             return status;
07811         }
07812     } else {
07813         printf("Error: policy %s doesn't exist in database\n", o_policy);
07814         KsmPolicyFree(policy);
07815         return status;
07816     }
07817 
07818     /* Make sure that enough keys are allocated to this zone */
07819     status = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, interval, zone_name, man_key_gen, 0);
07820     if (status != 0) {
07821         printf("Error allocating zsks to zone %s", zone_name);
07822         KsmPolicyFree(policy);
07823         return(status);
07824     }
07825     status = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, interval, zone_name, man_key_gen, policy->ksk->rollover_scheme);
07826     if (status != 0) {
07827         printf("Error allocating ksks to zone %s", zone_name);
07828         KsmPolicyFree(policy);
07829         return(status);
07830     }
07831 
07832     KsmPolicyFree(policy);
07833     return 0;
07834 }
07835 
07836 /* allocateKeysToZone
07837  *
07838  * Description:
07839  *      Allocates existing keys to zones
07840  *
07841  * Arguments:
07842  *      policy
07843  *          policy that the keys were created for
07844  *      key_type
07845  *          KSK or ZSK
07846  *      zone_id
07847  *          ID of zone in question
07848  *      interval
07849  *          time before next run
07850  *      zone_name
07851  *          just in case we need to log something
07852  *      man_key_gen
07853  *          lack of keys may be an issue for the user to fix
07854  *      int rollover_scheme
07855  *          KSK rollover scheme in use
07856  *
07857  * Returns:
07858  *      int
07859  *          Status return.  0=> Success, non-zero => error.
07860  *          1 == error with input
07861  *          2 == not enough keys to satisfy policy
07862  *          3 == database error
07863  -*/
07864 
07865 
07866 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)
07867 {
07868     int status = 0;
07869     int keys_needed = 0;
07870     int keys_in_queue = 0;
07871     int keys_pending_retirement = 0;
07872     int new_keys = 0;
07873     int key_pair_id = 0;
07874     int i = 0;
07875     DB_ID ignore = 0;
07876     KSM_PARCOLL collection; /* Parameters collection */
07877     char*   datetime = DtParseDateTimeString("now");
07878 
07879     /* Check datetime in case it came back NULL */
07880     if (datetime == NULL) {
07881         printf("Couldn't turn \"now\" into a date, quitting...");
07882         exit(1);
07883     }
07884 
07885     if (policy == NULL) {
07886         printf("NULL policy sent to allocateKeysToZone");
07887         StrFree(datetime);
07888         return 1;
07889     }
07890 
07891     if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) {
07892         printf("Unknown keytype: %i in allocateKeysToZone", key_type);
07893         StrFree(datetime);
07894         return 1;
07895     }
07896 
07897     /* Get list of parameters */
07898     status = KsmParameterCollection(&collection, policy->id);
07899     if (status != 0) {
07900         StrFree(datetime);
07901         return status;
07902     }
07903 
07904     /* Make sure that enough keys are allocated to this zone */
07905     /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */
07906     status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1);
07907     if (status != 0) {
07908         printf("Could not predict key requirement for next interval for %s", zone_name);
07909         StrFree(datetime);
07910         return 3;
07911     }
07912 
07913     /* How many do we have ? TODO should this include the currently active key?*/
07914     status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id);
07915     if (status != 0) {
07916         printf("Could not count current key numbers for zone %s", zone_name);
07917         StrFree(datetime);
07918         return 3;
07919     }
07920 
07921     /* or about to retire */
07922     status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval);
07923     if (status != 0) {
07924         printf("Could not count keys which may retire before the next run (for zone %s)", zone_name);
07925         StrFree(datetime);
07926         return 3;
07927     }
07928 
07929     StrFree(datetime);
07930     new_keys = keys_needed - (keys_in_queue - keys_pending_retirement);
07931 
07932     /* 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); */
07933 
07934     /* Allocate keys */
07935     for (i=0 ; i < new_keys ; i++){
07936         key_pair_id = 0;
07937         if (key_type == KSM_TYPE_KSK) {
07938             status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
07939             if (status == -1 || key_pair_id == 0) {
07940                 if (man_key_gen == 0) {
07941                     printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name);
07942                     printf("ods-enforcerd will create some more keys on its next run");
07943                 }
07944                 else {
07945                     printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name);
07946                     printf("please use \"ods-ksmutil key generate\" to create some more keys.");
07947                 }
07948                 return 2;
07949             }
07950             else if (status != 0) {
07951                 printf("Could not get an unallocated ksk for zone: %s", zone_name);
07952                 return 3;
07953             }
07954         } else {
07955             status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
07956             if (status == -1 || key_pair_id == 0) {
07957                 if (man_key_gen == 0) {
07958                     printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name);
07959                     printf("ods-enforcerd will create some more keys on its next run");
07960                 }
07961                 else {
07962                     printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name);
07963                     printf("please use \"ods-ksmutil key generate\" to create some more keys.");
07964                 }
07965                 return 2;
07966             }
07967             else if (status != 0) {
07968                 printf("Could not get an unallocated zsk for zone: %s", zone_name);
07969                 return 3;
07970             }
07971         }
07972         if(key_pair_id > 0) {
07973             status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, NULL, &ignore);
07974             /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */
07975         } else {
07976             /* This shouldn't happen */
07977             printf("KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name);
07978             exit(1);
07979         }
07980 
07981     }
07982 
07983     return status;
07984 }
07985 
07986 
07987 /* keyRoll
07988  *
07989  * Description:
07990  *      Rolls keys far enough for the enforcer to take over
07991  *
07992  * Arguments:
07993  *      zone_id
07994  *          ID of zone in question (-1 == all)
07995  *      policy_id
07996  *          policy that should be rolled (-1 == all)
07997  *      key_type
07998  *          KSK or ZSK (-1 == all)
07999  *
08000  * Returns:
08001  *      int
08002  *          Status return.  0=> Success, non-zero => error.
08003  -*/
08004 
08005 int keyRoll(int zone_id, int policy_id, int key_type)
08006 {
08007 
08008     int status = 0;
08009     int size = -1;
08010 
08011     char*       sql = NULL;     /* SQL query */
08012     char*       sql1 = NULL;    /* SQL query */
08013     char        sql2[KSM_SQL_SIZE];
08014     DB_RESULT   result1;        /* Result of the query */
08015     DB_ROW      row = NULL;     /* Row data */
08016     int         temp_id = -1;   /* place to store the key id returned */
08017     int         temp_type = -1; /* place to store the key type returned */
08018     int         temp_zone_id = -1;   /* place to store the zone id returned */
08019     int         where = 0;
08020     int         j = 0;
08021     DB_RESULT   result2;        /* Result of the query */
08022     DB_RESULT   result3;        /* Result of the query */
08023     DB_ROW      row2 = NULL;    /* Row data */
08024     char*       insql1 = NULL;  /* SQL query */
08025     char*       insql2 = NULL;  /* SQL query */
08026     char        buffer[32];     /* For integer conversion */
08027     
08028     char*   datetime = DtParseDateTimeString("now");
08029 
08030     /* Check datetime in case it came back NULL */
08031     if (datetime == NULL) {
08032         printf("Couldn't turn \"now\" into a date, quitting...\n");
08033         StrFree(datetime);
08034         exit(1);
08035     }
08036 
08037     /* retire the active key(s) */
08038     /* Find the key ID */
08039     sql = DqsSpecifyInit("KEYDATA_VIEW","id, keytype");
08040     if (zone_id != -1) {
08041         DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, where++);
08042     }
08043     if (policy_id != -1) {
08044         DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
08045     }
08046     DqsConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
08047     if (key_type != -1) {
08048         DqsConditionInt(&sql, "keytype", DQS_COMPARE_EQ, key_type, where++);
08049     }
08050     DqsEnd(&sql);
08051 
08052     status = DbExecuteSql(DbHandle(), sql, &result1);
08053 
08054     if (status == 0) {
08055         status = DbFetchRow(result1, &row);
08056         while (status == 0) {
08057             /* Got a row, deal with it */
08058             DbInt(row, 0, &temp_id);
08059             DbInt(row, 1, &temp_type);
08060 
08061             sql1 = DusInit("keypairs");
08062             DusSetInt(&sql1, "fixedDate", 1, 0);
08063             DusSetInt(&sql1, "compromisedflag", 1, 1);
08064 
08065             DusConditionInt(&sql1, "id", DQS_COMPARE_EQ, temp_id, 0);
08066             DusEnd(&sql1);
08067             status = DbExecuteSqlNoResult(DbHandle(), sql1);
08068             DusFree(sql1);
08069 
08070             /* Report any errors */
08071             if (status != 0) {
08072                 printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08073                 DbFreeRow(row);
08074                 return status;
08075             }
08076 
08077             /* Loop over instances of this key: */
08078             /* active-> set retire time */
08079             sql1 = DusInit("dnsseckeys");
08080             DusSetString(&sql1, "RETIRE", datetime, 0);
08081 
08082             DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
08083             DusConditionInt(&sql1, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, 1);
08084             DusEnd(&sql1);
08085             status = DbExecuteSqlNoResult(DbHandle(), sql1);
08086             DusFree(sql1);
08087 
08088             /* Report any errors */
08089             if (status != 0) {
08090                 printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08091                 DbFreeRow(row);
08092                 return status;
08093             }
08094 
08095             /* other-> move to dead */
08096             sql1 = DusInit("dnsseckeys");
08097             DusSetString(&sql1, "DEAD", datetime, 0);
08098             DusSetInt(&sql1, "state", KSM_STATE_DEAD, 1);
08099 
08100             DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
08101             DusConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_ACTIVE, 1);
08102             DusEnd(&sql1);
08103             status = DbExecuteSqlNoResult(DbHandle(), sql1);
08104             DusFree(sql1);
08105 
08106             /* Report any errors */
08107             if (status != 0) {
08108                 printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08109                 DbFreeRow(row);
08110                 return status;
08111             }
08112            
08113             /* Promote any standby keys if we need to, i.e. we retired a KSK 
08114                and there is nothing able to take over from it */
08115             if (temp_type == KSM_TYPE_KSK) {
08116                 /* find each zone in turn */
08117                 /* Depressingly MySQL can't run the following sql; so we need 
08118                    to build it by parts... There has to be a better way to do 
08119                    this.
08120                 size = snprintf(sql2, KSM_SQL_SIZE, "update dnsseckeys set state = %d where state = %d and zone_id in (select zone_id from dnsseckeys where retire = \"%s\" and keypair_id = %d) and zone_id not in (select zone_id from KEYDATA_VIEW where policy_id = %d and keytype = %d and state in (%d,%d))", KSM_STATE_KEYPUBLISH, KSM_STATE_DSREADY, datetime, temp_id, policy_id, KSM_TYPE_KSK, KSM_STATE_PUBLISH, KSM_STATE_READY); */
08121 
08122                 /* First INSQL: select zone_id from dnsseckeys where retire = "DATETIME" and keypair_id = temp_id*/
08123 
08124                 size = snprintf(sql2, KSM_SQL_SIZE, "select zone_id from dnsseckeys where retire = \"%s\" and keypair_id = %d", datetime, temp_id);
08125                 status = DbExecuteSql(DbHandle(), sql2, &result2);
08126                 if (status == 0) {
08127                     status = DbFetchRow(result2, &row2);
08128                     while (status == 0) {
08129                         /* Got a row, print it */
08130                         DbInt(row2, 0, &temp_zone_id);
08131 
08132                         if (j != 0) {
08133                             StrAppend(&insql1, ",");
08134                         }
08135                         snprintf(buffer, sizeof(buffer), "%d", temp_zone_id);
08136                         StrAppend(&insql1, buffer);
08137                         j++;
08138 
08139                         status = DbFetchRow(result2, &row2);
08140                     }
08141 
08142                     /* Convert EOF status to success */
08143 
08144                     if (status == -1) {
08145                         status = 0;
08146                     }
08147 
08148                     DbFreeResult(result2);
08149                 }
08150 
08151                 /* Second INSQL: select zone_id from KEYDATA_VIEW where policy_id = policy_id and keytype = KSK and state in (publish,ready) */
08152 
08153                 size = snprintf(sql2, KSM_SQL_SIZE, "select zone_id from KEYDATA_VIEW where policy_id = %d and keytype = %d and state in (%d,%d)", policy_id, KSM_TYPE_KSK, KSM_STATE_PUBLISH, KSM_STATE_READY);
08154                 j=0;
08155                 status = DbExecuteSql(DbHandle(), sql2, &result3);
08156                 if (status == 0) {
08157                     status = DbFetchRow(result3, &row2);
08158                     while (status == 0) {
08159                         /* Got a row, print it */
08160                         DbInt(row2, 0, &temp_zone_id);
08161 
08162                         if (j != 0) {
08163                             StrAppend(&insql2, ",");
08164                         }
08165                         snprintf(buffer, sizeof(buffer), "%d", temp_zone_id);
08166                         StrAppend(&insql2, buffer);
08167                         j++;
08168 
08169                         status = DbFetchRow(result3, &row2);
08170                     }
08171 
08172                     /* Convert EOF status to success */
08173 
08174                     if (status == -1) {
08175                         status = 0;
08176                     }
08177 
08178                     DbFreeResult(result3);
08179                 }
08180                 DbFreeRow(row2);
08181 
08182                 /* Finally we can do the update */
08183                 size = snprintf(sql2, KSM_SQL_SIZE, "update dnsseckeys set state = %d where state = %d and zone_id in (%s) and zone_id not in (%s)", KSM_STATE_KEYPUBLISH, KSM_STATE_DSREADY, insql1, insql2);
08184 
08185                 /* Quick check that we didn't run out of space */
08186                 if (size < 0 || size >= KSM_SQL_SIZE) {
08187                     printf("Couldn't construct SQL to promote standby key\n");
08188                     DbFreeRow(row);
08189                     return -1;
08190                 }
08191 
08192                 status = DbExecuteSqlNoResult(DbHandle(), sql2);
08193 
08194                 /* Report any errors */
08195                 if (status != 0) {
08196                     printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08197                     DbFreeRow(row);
08198                     return status;
08199                 }
08200             }
08201 
08202             /* NEXT KEY */ 
08203             status = DbFetchRow(result1, &row);
08204         }
08205 
08206         /* Convert EOF status to success */
08207         if (status == -1) {
08208             status = 0;
08209         }
08210         DbFreeResult(result1);
08211     }
08212     DqsFree(sql);
08213     DbFreeRow(row);
08214 
08215     StrFree(datetime);
08216     
08217     return status;
08218 }
08219 
08220 int get_policy_name_from_id(KSM_ZONE *zone)
08221 {
08222     int     where = 0;          /* WHERE clause value */
08223     char*   sql = NULL;         /* SQL query */
08224     DB_RESULT       result;     /* Handle converted to a result object */
08225     DB_ROW      row = NULL;            /* Row data */
08226     int     status = 0;         /* Status return */
08227 
08228     /* Construct the query */
08229 
08230     sql = DqsSpecifyInit("policies","id, name");
08231     DqsConditionInt(&sql, "ID", DQS_COMPARE_EQ, zone->policy_id, where++);
08232     DqsOrderBy(&sql, "id");
08233 
08234     /* Execute query and free up the query string */
08235     status = DbExecuteSql(DbHandle(), sql, &result);
08236     DqsFree(sql);
08237     
08238     if (status != 0)
08239     {
08240         printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08241         DbFreeResult(result);
08242         return status;
08243         }
08244 
08245     /* Get the next row from the data */
08246     status = DbFetchRow(result, &row);
08247     if (status == 0) {
08248         DbStringBuffer(row, DB_POLICY_NAME, zone->policy_name, KSM_NAME_LENGTH*sizeof(char));
08249     }
08250     else if (status == -1) {}
08251         /* No rows to return (but no error) */
08252         else {
08253         printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
08254         return status;
08255         }
08256 
08257     DbFreeRow(row);
08258     DbFreeResult(result);
08259     return status;
08260 }
08261 
08262 int append_zone(xmlDocPtr doc, KSM_ZONE *zone)
08263 {
08264     xmlNodePtr root;
08265     xmlNodePtr zone_node;
08266     xmlNodePtr adapters_node;
08267     xmlNodePtr input_node;
08268     xmlNodePtr output_node;
08269 
08270     root = xmlDocGetRootElement(doc);
08271     if (root == NULL) {
08272         fprintf(stderr,"empty document\n");
08273         return(1);
08274     }
08275     if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
08276         fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
08277         return(1);
08278     }
08279 
08280     zone_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Zone", NULL);
08281     (void) xmlNewProp(zone_node, (const xmlChar *)"name", (const xmlChar *)zone->name);
08282 
08283     /* Policy */
08284     (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Policy", (const xmlChar *)zone->policy_name);
08285 
08286     /* SignConf */
08287     (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)zone->signconf);
08288 
08289     /* Adapters */
08290     adapters_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Adapters", NULL);
08291     /* Input */
08292     input_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Input", NULL);
08293     (void) xmlNewTextChild(input_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->input);
08294     /* Output */
08295     output_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Output", NULL);
08296     (void) xmlNewTextChild(output_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->output);
08297 
08298 
08299     return(0);
08300 }
08301 
08302 int ShellQuoteString(const char* string, char* buffer, size_t buflen)
08303 {
08304         size_t i;           /* Loop counter */
08305         size_t j = 0;       /* Counter for new string */
08306 
08307         size_t len = strlen(string);
08308 
08309         if (string) {
08310                 for (i = 0; i < len; ++i) {
08311                         if (string[i] == '\'') {
08312                                 buffer[j++] = '\'';
08313                                 buffer[j++] = '\\';
08314                                 buffer[j++] = '\'';
08315                         }
08316                         buffer[j++] = string[i];
08317                 }
08318         }
08319         buffer[j] = '\0';
08320         return ( (j <= buflen) ? 0 : 1);
08321 }
08322