• Main Page
  • Data Structures
  • Files
  • File List
  • Globals

/srv/bpo/opendnssec/opendnssec-1.3.2/enforcer/utils/ksmutil.c

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

Generated on Mon Oct 31 2011 14:38:31 for OpenDNSSEC-enforcer by  doxygen 1.7.1