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