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