OpenDNSSEC-enforcer  1.3.15
ksmutil.c
Go to the documentation of this file.
1 /*
2  * $Id: ksmutil.c 7268 2013-09-06 13:27:28Z sara $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #define _GNU_SOURCE
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <limits.h>
36 
37 #include "config.h"
38 
39 #include <getopt.h>
40 #include <string.h>
41 #include <syslog.h>
42 #include <sys/stat.h>
43 #include <pwd.h>
44 #include <grp.h>
45 
46 #include <ksm/ksmutil.h>
47 #include <ksm/ksm.h>
48 #include <ksm/database.h>
49 #include "ksm/database_statement.h"
50 #include "ksm/db_fields.h"
51 #include <ksm/datetime.h>
52 #include <ksm/string_util.h>
53 #include <ksm/string_util2.h>
54 #include "ksm/kmemsg.h"
55 #include "ksm/kmedef.h"
56 #include "ksm/dbsmsg.h"
57 #include "ksm/dbsdef.h"
58 #include "ksm/message.h"
59 
60 #include <libhsm.h>
61 #include <libhsmdns.h>
62 #include <ldns/ldns.h>
63 
64 #include <libxml/tree.h>
65 #include <libxml/parser.h>
66 #include <libxml/xpointer.h>
67 #include <libxml/xpath.h>
68 #include <libxml/xpathInternals.h>
69 #include <libxml/relaxng.h>
70 #include <libxml/xmlreader.h>
71 #include <libxml/xmlsave.h>
72 
73 #define MAX(a, b) ((a) > (b) ? (a) : (b))
74 
75 /* Some value type flags */
76 #define INT_TYPE 0
77 #define DURATION_TYPE 1
78 #define BOOL_TYPE 2
79 #define REPO_TYPE 3
80 #define SERIAL_TYPE 4
81 #define ROLLOVER_TYPE 5
82 #define INT_TYPE_NO_FREE 6
83 
84 #ifndef MAXPATHLEN
85 # define MAXPATHLEN 4096
86 #endif
87 
88 /* We write one log message to syslog */
89 #ifdef LOG_DAEMON
90 #define DEFAULT_LOG_FACILITY LOG_DAEMON
91 #else
92 #define DEFAULT_LOG_FACILITY LOG_USER
93 #endif /* LOG_DAEMON */
94 
95 extern char *optarg;
96 extern int optind;
97 const char *progname = NULL;
98 char *config = (char *) OPENDNSSEC_CONFIG_FILE;
99 
100 char *o_keystate = NULL;
101 char *o_algo = NULL;
102 char *o_input = NULL;
103 char *o_cka_id = NULL;
104 char *o_size = NULL;
105 char *o_interval = NULL;
106 char *o_output = NULL;
107 char *o_policy = NULL;
108 char *o_repository = NULL;
109 char *o_signerconf = NULL;
110 char *o_keytype = NULL;
111 char *o_time = NULL;
112 char *o_retire = NULL;
113 char *o_zone = NULL;
114 char *o_zonetotal = NULL;
115 char *o_keytag = NULL;
116 static int all_flag = 0;
117 static int ds_flag = 0;
118 static int retire_flag = 1;
119 static int verbose_flag = 0;
120 static int xml_flag = 1;
121 static int td_flag = 0;
122 static int force_flag = 0;
123 
124 static int restart_enforcerd(void);
125 
131 #if defined(HAVE_SYSLOG_R) && defined(HAVE_OPENLOG_R) && defined(HAVE_CLOSELOG_R)
132 struct syslog_data sdata = SYSLOG_DATA_INIT;
133 #else
134 #undef HAVE_SYSLOG_R
135 #undef HAVE_OPENLOG_R
136 #undef HAVE_CLOSELOG_R
137 #endif
138 
139  void
141 {
142  fprintf(stderr,
143  " help\n"
144  " --version aka -V\n");
145 }
146 
147  void
149 {
150  fprintf(stderr,
151  " setup\n"
152  "\tImport config into a database (deletes current contents)\n");
153 }
154 
155  void
157 {
158  fprintf(stderr,
159  " start|stop|notify\n"
160  "\tStart, stop or SIGHUP the ods-enforcerd\n");
161 }
162 
163  void
165 {
166  fprintf(stderr,
167  " update kasp\n"
168  " update zonelist\n"
169  " update conf\n"
170  " update all\n"
171  "\tUpdate database from config\n");
172 }
173 
174  void
176 {
177  fprintf(stderr,
178  " zone add\n"
179  "\t--zone <zone> aka -z\n"
180  "\t[--policy <policy>] aka -p\n"
181  "\t[--signerconf <signerconf.xml>] aka -s\n"
182  "\t[--input <input>] aka -i\n"
183  "\t[--output <output>] aka -o\n"
184  "\t[--no-xml] aka -m\n");
185 }
186 
187  void
189 {
190  fprintf(stderr,
191  " zone delete\n"
192  "\t--zone <zone> | --all aka -z / -a\n"
193  "\t[--no-xml] aka -m\n");
194 }
195 
196  void
198 {
199  fprintf(stderr,
200  " zone list\n");
201 }
202 
203  void
205 {
206  fprintf(stderr,
207  "usage: %s [-c <config> | --config <config>] zone \n\n",
208  progname);
209  usage_zoneadd ();
210  usage_zonedel ();
211  usage_zonelist ();
212 }
213 
214  void
216 {
217  fprintf(stderr,
218  " repository list\n");
219 }
220 
221  void
223 {
224  fprintf(stderr,
225  " policy export\n"
226  "\t--policy [policy_name] | --all aka -p / -a\n");
227 }
228 
229  void
231 {
232  fprintf(stderr,
233  " policy import\n");
234 }
235 
236  void
238 {
239  fprintf(stderr,
240  " policy list\n");
241 }
242 
243  void
245 {
246  fprintf(stderr,
247  " policy purge\n");
248 }
249 
250  void
252 {
253  fprintf(stderr,
254  "usage: %s [-c <config> | --config <config>] \n\n",
255  progname);
258  usage_policylist ();
260 }
261 
262  void
264 {
265  fprintf(stderr,
266  " key list\n"
267  "\t[--verbose]\n"
268  "\t--zone <zone> | --all aka -z / -a\n"
269 #if 0
270  "\t(will appear soon:\n"
271  "\t[--keystate <state>] aka -e\n"
272  "\t[--keytype <type>] aka -t\n"
273  "\t[--ds] aka -d)\n"
274 #endif
275  );
276 }
277 
278  void
280 {
281  fprintf(stderr,
282  " key export\n"
283  "\t--zone <zone> | --all aka -z / -a\n"
284  "\t[--keystate <state>] aka -e\n"
285  "\t[--keytype <type>] aka -t\n"
286  "\t[--ds] aka -d\n");
287 }
288 
289  void
291 {
292  fprintf(stderr,
293  " key import\n"
294  "\t--cka_id <CKA_ID> aka -k\n"
295  "\t--repository <repository> aka -r\n"
296  "\t--zone <zone> aka -z\n"
297  "\t--bits <size> aka -b\n"
298  "\t--algorithm <algorithm> aka -g\n"
299  "\t--keystate <state> aka -e\n"
300  "\t--keytype <type> aka -t\n"
301  "\t--time <time> aka -w\n"
302  "\t[--retire <retire>] aka -y\n");
303 }
304 
305  void
307 {
308  fprintf(stderr,
309  " key rollover\n"
310  "\t--zone zone aka -z\n"
311  "\t--keytype <type> | --all aka -t / -a\n"
312  " key rollover\n"
313  "\t--policy policy aka -p\n"
314  "\t--keytype <type> | --all aka -t / -a\n");
315 }
316 
317  void
319 {
320  fprintf(stderr,
321  " key purge\n"
322  "\t--zone <zone> aka -z\n"
323  " key purge\n"
324  "\t--policy <policy> aka -p\n");
325 }
326 
327  void
329 {
330  fprintf(stderr,
331  " key generate\n"
332  "\t--policy <policy> aka -p\n"
333  "\t--interval <interval> aka -n\n"
334  "\t[--zonetotal <total no. of zones>] aka -Z\n");
335 }
336 
337  void
339 {
340  fprintf(stderr,
341  " key ksk-retire\n"
342  "\t--zone <zone> aka -z\n"
343  "\t--keytag <keytag> | --cka_id <CKA_ID> aka -x / -k\n");
344 }
345 
346  void
348 {
349  fprintf(stderr,
350  " key ds-seen\n"
351  /*"\t--zone <zone> (or --all) aka -z\n"*/
352  "\t--zone <zone> aka -z\n"
353  "\t--keytag <keytag> | --cka_id <CKA_ID> aka -x / -k\n"
354  "\t--no-retire\n");
355 }
356 
357  void
359 {
360  fprintf(stderr,
361  "usage: %s [-c <config> | --config <config>] \n\n",
362  progname);
363  usage_keylist ();
364  usage_keyexport ();
365  usage_keyimport ();
366  usage_keyroll ();
367  usage_keypurge ();
368  usage_keygen ();
370  usage_keydsseen ();
371 }
372 
373  void
375 {
376  fprintf(stderr,
377  " backup prepare\n"
378  "\t--repository <repository> aka -r\n"
379  " backup commit\n"
380  "\t--repository <repository> aka -r\n"
381  " backup rollback\n"
382  "\t--repository <repository> aka -r\n"
383  " backup list\n"
384  "\t--repository <repository> aka -r\n"
385  " backup done\n"
386  "\t--repository <repository> aka -r\n");
387 }
388 
389  void
391 {
392  fprintf(stderr,
393  " rollover list\n"
394  "\t[--zone <zone>]\n");
395 }
396 
397  void
399 {
400  fprintf(stderr,
401  " database backup\n"
402  "\t[--output <output>] aka -o\n");
403 }
404 
405  void
407 {
408  fprintf(stderr,
409  " zonelist export\n"
410  " zonelist import\n");
411 }
412 
413  void
415 {
416  fprintf(stderr,
417  "usage: %s [-c <config> | --config <config>] command [options]\n\n",
418  progname);
419 
420  usage_general ();
421  usage_setup ();
422  usage_control ();
423  usage_update ();
424  usage_zoneadd ();
425  usage_zonedel ();
426  usage_zonelist ();
427  usage_repo ();
430  usage_policylist ();
432  usage_keylist ();
433  usage_keyexport ();
434  usage_keyimport ();
435  usage_keyroll ();
436  usage_keypurge ();
437  usage_keygen ();
439  usage_keydsseen ();
440  usage_backup ();
441  usage_rollover ();
442  usage_database ();
443  usage_zonelist2 ();
444 
445 }
446 
447  void
449 {
450  fprintf(stderr,
451  "\n\tAllowed date/time strings are of the form:\n"
452 
453  "\tYYYYMMDD[HH[MM[SS]]] (all numeric)\n"
454  "\n"
455  "\tor D-MMM-YYYY[:| ]HH[:MM[:SS]] (alphabetic month)\n"
456  "\tor DD-MMM-YYYY[:| ]HH[:MM[:SS]] (alphabetic month)\n"
457  "\tor YYYY-MMM-DD[:| ]HH[:MM[:SS]] (alphabetic month)\n"
458  "\n"
459  "\tD-MM-YYYY[:| ]HH[:MM[:SS]] (numeric month)\n"
460  "\tDD-MM-YYYY[:| ]HH[:MM[:SS]] (numeric month)\n"
461  "\tor YYYY-MM-DD[:| ]HH[:MM[:SS]] (numeric month)\n"
462  "\n"
463  "\t... and the distinction between them is given by the location of the\n"
464  "\thyphens.\n");
465 }
466 
467 void
469 {
470  fprintf(stderr,
471  "key states: GENERATE|PUBLISH|READY|ACTIVE|RETIRE|DEAD\n");
472 }
473 
474 void
476 {
477  fprintf(stderr,
478  "key types: KSK|ZSK\n");
479 }
480 
481 /*
482  * Do initial import of config files into database
483  */
484  int
486 {
487  DB_HANDLE dbhandle;
488  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
489  char* zone_list_filename; /* Extracted from conf.xml */
490  char* kasp_filename; /* Extracted from conf.xml */
491  int status = 0;
492 
493  /* Database connection details */
494  char *dbschema = NULL;
495  char *host = NULL;
496  char *port = NULL;
497  char *user = NULL;
498  char *password = NULL;
499 
500  char quoted_user[KSM_NAME_LENGTH];
501  char quoted_password[KSM_NAME_LENGTH];
502 
503  char* setup_command = NULL;
504  char* lock_filename = NULL;
505 
506  int user_certain;
507  printf("*WARNING* This will erase all data in the database; are you sure? [y/N] ");
508 
509  user_certain = getchar();
510  if (user_certain != 'y' && user_certain != 'Y') {
511  printf("Okay, quitting...\n");
512  exit(0);
513  }
514 
515  /* Right then, they asked for it */
516 
517  /* Read the database details out of conf.xml */
518  status = get_db_details(&dbschema, &host, &port, &user, &password);
519  if (status != 0) {
520  StrFree(host);
521  StrFree(port);
522  StrFree(dbschema);
523  StrFree(user);
524  StrFree(password);
525  return(status);
526  }
527 
528  /* If we are in sqlite mode then take a lock out on a file to
529  prevent multiple access (not sure that we can be sure that sqlite is
530  safe for multiple processes to access). */
531  if (DbFlavour() == SQLITE_DB) {
532 
533  /* Make sure that nothing is happening to the DB */
534  StrAppend(&lock_filename, dbschema);
535  StrAppend(&lock_filename, ".our_lock");
536 
537  lock_fd = fopen(lock_filename, "w");
538  status = get_lite_lock(lock_filename, lock_fd);
539  if (status != 0) {
540  printf("Error getting db lock\n");
541  if (lock_fd != NULL) {
542  fclose(lock_fd);
543  }
544  StrFree(lock_filename);
545  StrFree(host);
546  StrFree(port);
547  StrFree(dbschema);
548  StrFree(user);
549  StrFree(password);
550  return(1);
551  }
552  StrFree(lock_filename);
553 
554  /* Run the setup script */
555  /* will look like: <SQL_BIN> <DBSCHEMA> < <SQL_SETUP> */
556  StrAppend(&setup_command, SQL_BIN);
557  StrAppend(&setup_command, " ");
558  StrAppend(&setup_command, dbschema);
559  StrAppend(&setup_command, " < ");
560  StrAppend(&setup_command, SQL_SETUP);
561 
562  if (system(setup_command) != 0)
563  {
564  printf("Could not call db setup command:\n\t%s\n", setup_command);
565  db_disconnect(lock_fd);
566  StrFree(host);
567  StrFree(port);
568  StrFree(dbschema);
569  StrFree(user);
570  StrFree(password);
571  StrFree(setup_command);
572  return(1);
573  }
574  StrFree(setup_command);
575 
576  /* If we are running as root then chmod the file so that the
577  final user/group can access it. */
578  if (fix_file_perms(dbschema) != 0)
579  {
580  printf("Couldn't fix permissions on file %s\n", dbschema);
581  printf("Will coninue with setup, but you may need to manually change ownership\n");
582  }
583  }
584  else {
585  /* MySQL setup */
586  /* will look like: <SQL_BIN> -u <USER> -h <HOST> -P <PORT> -p<PASSWORD> <DBSCHEMA> < <SQL_SETUP> */
587 
588  /* Get a quoted version of the username */
589  status = ShellQuoteString(user, quoted_user, KSM_NAME_LENGTH);
590  if (status != 0) {
591  printf("Failed to connect to database, username too long.\n");
592  db_disconnect(lock_fd);
593  StrFree(host);
594  StrFree(port);
595  StrFree(dbschema);
596  StrFree(user);
597  StrFree(password);
598  return(1);
599  }
600 
601  /* Get a quoted version of the password */
602  status = ShellQuoteString(password, quoted_password, KSM_NAME_LENGTH);
603  if (status != 0) {
604  printf("Failed to connect to database, password too long.\n");
605  db_disconnect(lock_fd);
606  StrFree(host);
607  StrFree(port);
608  StrFree(dbschema);
609  StrFree(user);
610  StrFree(password);
611  return(1);
612  }
613 
614  StrAppend(&setup_command, SQL_BIN);
615  StrAppend(&setup_command, " -u '");
616  StrAppend(&setup_command, quoted_user);
617  StrAppend(&setup_command, "'");
618  if (host != NULL) {
619  StrAppend(&setup_command, " -h ");
620  StrAppend(&setup_command, host);
621  if (port != NULL) {
622  StrAppend(&setup_command, " -P ");
623  StrAppend(&setup_command, port);
624  }
625  }
626  if (password != NULL) {
627  StrAppend(&setup_command, " -p'");
628  StrAppend(&setup_command, quoted_password);
629  StrAppend(&setup_command, "'");
630  }
631  StrAppend(&setup_command, " ");
632  StrAppend(&setup_command, dbschema);
633  StrAppend(&setup_command, " < ");
634  StrAppend(&setup_command, SQL_SETUP);
635 
636  if (system(setup_command) != 0)
637  {
638  printf("Could not call db setup command:\n\t%s\n", setup_command);
639  StrFree(host);
640  StrFree(port);
641  StrFree(dbschema);
642  StrFree(user);
643  StrFree(password);
644  StrFree(setup_command);
645  return(1);
646  }
647  StrFree(setup_command);
648  }
649 
650  /* try to connect to the database */
651  status = DbConnect(&dbhandle, dbschema, host, password, user, port);
652  if (status != 0) {
653  printf("Failed to connect to database\n");
654  db_disconnect(lock_fd);
655  StrFree(host);
656  StrFree(port);
657  StrFree(dbschema);
658  StrFree(user);
659  StrFree(password);
660  return(1);
661  }
662 
663  /* Free these up early */
664  StrFree(host);
665  StrFree(port);
666  StrFree(dbschema);
667  StrFree(user);
668  StrFree(password);
669 
670  /*
671  * Now we will read the conf.xml file again, but this time we will not validate.
672  * Instead we just learn the location of the zonelist.xml and kasp.xml files.
673  */
674  status = read_filenames(&zone_list_filename, &kasp_filename);
675  if (status != 0) {
676  printf("Failed to read conf.xml\n");
677  db_disconnect(lock_fd);
678  return(1);
679  }
680 
681  /*
682  * Now we will read the conf.xml file again, but this time we will not validate.
683  * Instead we just extract the RepositoryList into the database
684  */
685  status = update_repositories();
686  if (status != 0) {
687  printf("Failed to update repositories\n");
688  db_disconnect(lock_fd);
689  StrFree(zone_list_filename);
690  return(1);
691  }
692 
693  /*
694  * Now read the kasp.xml which should be in the same directory.
695  * This lists all of the policies.
696  */
697  status = update_policies(kasp_filename);
698  if (status != 0) {
699  printf("Failed to update policies\n");
700  printf("SETUP FAILED\n");
701  db_disconnect(lock_fd);
702  StrFree(zone_list_filename);
703  return(1);
704  }
705 
706  StrFree(kasp_filename);
707 
708  /*
709  * Take the zonelist we learnt above and read it, updating or inserting zone
710  * records in the database as we go.
711  */
712  status = update_zones(zone_list_filename);
713  StrFree(zone_list_filename);
714  if (status != 0) {
715  printf("Failed to update zones\n");
716  db_disconnect(lock_fd);
717  return(1);
718  }
719 
720  /* Release sqlite lock file (if we have it) */
721  db_disconnect(lock_fd);
722 
723  DbDisconnect(dbhandle);
724 
725  return 0;
726 }
727 
728 /*
729  * Do incremental update of config files into database
730  *
731  * returns 0 on success
732  * 1 on error (and will have sent a message to stdout)
733  */
734  int
735 cmd_update (const char* qualifier)
736 {
737  DB_HANDLE dbhandle;
738  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
739  char* zone_list_filename = NULL; /* Extracted from conf.xml */
740  char* kasp_filename = NULL; /* Extracted from conf.xml */
741  int status = 0;
742  int done_something = 0;
743 
744  /* try to connect to the database */
745  status = db_connect(&dbhandle, &lock_fd, 1);
746  if (status != 0) {
747  printf("Failed to connect to database\n");
748  db_disconnect(lock_fd);
749  return(1);
750  }
751 
752  /*
753  * Now we will read the conf.xml file again, but this time we will not validate.
754  * Instead we just learn the location of the zonelist.xml and kasp.xml files.
755  */
756  if (strncmp(qualifier, "ZONELIST", 8) == 0 ||
757  strncmp(qualifier, "KASP", 4) == 0 ||
758  strncmp(qualifier, "ALL", 3) == 0) {
759  status = read_filenames(&zone_list_filename, &kasp_filename);
760  if (status != 0) {
761  printf("Failed to read conf.xml\n");
762  db_disconnect(lock_fd);
763  return(1);
764  }
765  }
766 
767  /*
768  * Read the conf.xml file yet again, but this time we will not validate.
769  * Instead we just extract the RepositoryList into the database.
770  */
771  if (strncmp(qualifier, "CONF", 4) == 0 ||
772  strncmp(qualifier, "ALL", 3) == 0) {
773  status = update_repositories();
774  if (status != 0) {
775  printf("Failed to update repositories\n");
776  db_disconnect(lock_fd);
777  if (strncmp(qualifier, "ALL", 3) == 0) {
778  StrFree(kasp_filename);
779  StrFree(zone_list_filename);
780  }
781  return(1);
782  }
783  done_something = 1;
784  }
785 
786  /*
787  * Now read the kasp.xml which should be in the same directory.
788  * This lists all of the policies.
789  */
790  if (strncmp(qualifier, "KASP", 4) == 0 ||
791  strncmp(qualifier, "ALL", 3) == 0) {
792  status = update_policies(kasp_filename);
793  if (status != 0) {
794  printf("Failed to update policies\n");
795  db_disconnect(lock_fd);
796  StrFree(kasp_filename);
797  StrFree(zone_list_filename);
798  return(1);
799  }
800  done_something = 1;
801  }
802 
803  /*
804  * Take the zonelist we learnt above and read it, updating or inserting zone
805  * records in the database as we go.
806  */
807  if (strncmp(qualifier, "ZONELIST", 8) == 0 ||
808  strncmp(qualifier, "ALL", 3) == 0) {
809  status = update_zones(zone_list_filename);
810  if (status != 0) {
811  printf("Failed to update zones\n");
812  db_disconnect(lock_fd);
813  StrFree(kasp_filename);
814  StrFree(zone_list_filename);
815  return(1);
816  }
817  done_something = 1;
818  }
819 
820  /*
821  * See if we did anything, otherwise log an error
822  */
823  if (done_something == 0) {
824  printf("Unrecognised command update %s. Please specify one of:\n", qualifier);
825  usage_update();
826  } else {
827  /* Need to poke the enforcer to wake it up */
828  if (restart_enforcerd() != 0)
829  {
830  fprintf(stderr, "Could not HUP ods-enforcerd\n");
831  }
832  }
833 
834 
835  /* Release sqlite lock file (if we have it) */
836  db_disconnect(lock_fd);
837 
838  DbDisconnect(dbhandle);
839 
840  if (kasp_filename != NULL) {
841  StrFree(kasp_filename);
842  }
843  if (zone_list_filename != NULL) {
844  StrFree(zone_list_filename);
845  }
846 
847  return 0;
848 }
849 
850 /*
851  * Add a zone to the config and database.
852  *
853  * Use XMLwriter to update the zonelist.xml found in conf.xml.
854  * Then call update_zones to push these changes into the database.
855  * zonelist.xml will be backed up, as will the DB file if we are using sqlite
856  *
857  */
858  int
860 {
861  DB_HANDLE dbhandle;
862  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
863  char* zonelist_filename = NULL;
864  char* backup_filename = NULL;
865  /* The settings that we need for the zone */
866  char* sig_conf_name = NULL;
867  char* input_name = NULL;
868  char* output_name = NULL;
869  int policy_id = 0;
870  int new_zone; /* ignored */
871 
872  DB_RESULT result; /* Result of parameter query */
873  KSM_PARAMETER data; /* Parameter information */
874 
875  xmlDocPtr doc = NULL;
876 
877  int status = 0;
878 
879  char *path = getcwd(NULL, MAXPATHLEN);
880  if (path == NULL) {
881  printf("Couldn't malloc path: %s\n", strerror(errno));
882  exit(1);
883  }
884 
885  /* See what arguments we were passed (if any) otherwise set the defaults */
886  if (o_zone == NULL) {
887  printf("Please specify a zone with the --zone option\n");
888  usage_zone();
889  return(1);
890  }
891 
892  if (o_policy == NULL) {
893  o_policy = StrStrdup("default");
894  }
895  /*
896  * Set defaults and turn any relative paths into absolute
897  * (sort of, not the neatest output)
898  */
899  if (o_signerconf == NULL) {
900  StrAppend(&sig_conf_name, OPENDNSSEC_STATE_DIR);
901  StrAppend(&sig_conf_name, "/signconf/");
902  StrAppend(&sig_conf_name, o_zone);
903  StrAppend(&sig_conf_name, ".xml");
904  }
905  else if (*o_signerconf != '/') {
906  StrAppend(&sig_conf_name, path);
907  StrAppend(&sig_conf_name, "/");
908  StrAppend(&sig_conf_name, o_signerconf);
909  } else {
910  StrAppend(&sig_conf_name, o_signerconf);
911  }
912 
913  if (o_input == NULL) {
914  StrAppend(&input_name, OPENDNSSEC_STATE_DIR);
915  StrAppend(&input_name, "/unsigned/");
916  StrAppend(&input_name, o_zone);
917  }
918  else if (*o_input != '/') {
919  StrAppend(&input_name, path);
920  StrAppend(&input_name, "/");
921  StrAppend(&input_name, o_input);
922  } else {
923  StrAppend(&input_name, o_input);
924  }
925 
926  if (o_output == NULL) {
927  StrAppend(&output_name, OPENDNSSEC_STATE_DIR);
928  StrAppend(&output_name, "/signed/");
929  StrAppend(&output_name, o_zone);
930  }
931  else if (*o_output != '/') {
932  StrAppend(&output_name, path);
933  StrAppend(&output_name, "/");
934  StrAppend(&output_name, o_output);
935  } else {
936  StrAppend(&output_name, o_output);
937  }
938 
939  free(path);
940 
941  /* Set zonelist from the conf.xml that we have got */
942  status = read_zonelist_filename(&zonelist_filename);
943  if (status != 0) {
944  printf("couldn't read zonelist\n");
945  StrFree(zonelist_filename);
946  StrFree(sig_conf_name);
947  StrFree(input_name);
948  StrFree(output_name);
949  return(1);
950  }
951 
952  /*
953  * Push this new zonelist into the database
954  */
955 
956  /* try to connect to the database */
957  status = db_connect(&dbhandle, &lock_fd, 1);
958  if (status != 0) {
959  printf("Failed to connect to database\n");
960  db_disconnect(lock_fd);
961  StrFree(zonelist_filename);
962  StrFree(sig_conf_name);
963  StrFree(input_name);
964  StrFree(output_name);
965  return(1);
966  }
967 
968  /* Now stick this zone into the database */
969  status = KsmPolicyIdFromName(o_policy, &policy_id);
970  if (status != 0) {
971  printf("Error, can't find policy : %s\n", o_policy);
972  printf("Failed to update zones\n");
973  db_disconnect(lock_fd);
974  StrFree(zonelist_filename);
975  StrFree(sig_conf_name);
976  StrFree(input_name);
977  StrFree(output_name);
978  return(1);
979  }
980  status = KsmImportZone(o_zone, policy_id, 1, &new_zone, sig_conf_name, input_name, output_name);
981  if (status != 0) {
982  if (status == -2) {
983  printf("Failed to Import zone %s; it already exists\n", o_zone);
984  } else if (status == -3) {
985  printf("Failed to Import zone %s; it already exists both with and without a trailing dot\n", o_zone);
986  } else {
987  printf("Failed to Import zone\n");
988  }
989  db_disconnect(lock_fd);
990  StrFree(zonelist_filename);
991  StrFree(sig_conf_name);
992  StrFree(input_name);
993  StrFree(output_name);
994  return(1);
995  }
996 
997  /* If need be (keys shared on policy) link existing keys to zone */
998  /* First work out if the keys are shared on this policy */
999  status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
1000  if (status != 0) {
1001  printf("Can't retrieve shared-keys parameter for policy\n");
1002  db_disconnect(lock_fd);
1003  StrFree(zonelist_filename);
1004  StrFree(sig_conf_name);
1005  StrFree(input_name);
1006  StrFree(output_name);
1007  return(1);
1008  }
1009  status = KsmParameter(result, &data);
1010  if (status != 0) {
1011  printf("Can't retrieve shared-keys parameter for policy\n");
1012  db_disconnect(lock_fd);
1013  StrFree(zonelist_filename);
1014  StrFree(sig_conf_name);
1015  StrFree(input_name);
1016  StrFree(output_name);
1017  return(1);
1018  }
1019  KsmParameterEnd(result);
1020 
1021  /* If the policy does not share keys then skip this */
1022  if (data.value == 1) {
1023  status = LinkKeys(o_zone, policy_id);
1024  if (status != 0) {
1025  printf("Failed to Link Keys to zone\n");
1026  /* Carry on and write the xml if the error code was 2
1027  (not enough keys) */
1028  if (status != 2) {
1029  db_disconnect(lock_fd);
1030  StrFree(zonelist_filename);
1031  StrFree(sig_conf_name);
1032  StrFree(input_name);
1033  StrFree(output_name);
1034  return(1);
1035  }
1036  }
1037  }
1038 
1039  /* Release sqlite lock file (if we have it) */
1040  db_disconnect(lock_fd);
1041  DbDisconnect(dbhandle);
1042 
1043  if (xml_flag == 1) {
1044  /* Read the file and add our new node in memory */
1045  /* TODO don't add if it already exists */
1046  xmlKeepBlanksDefault(0);
1047  xmlTreeIndentString = "\t";
1048  doc = add_zone_node(zonelist_filename, o_zone, o_policy, sig_conf_name, input_name, output_name);
1049 
1050  StrFree(sig_conf_name);
1051  StrFree(input_name);
1052  StrFree(output_name);
1053 
1054  if (doc == NULL) {
1055  StrFree(zonelist_filename);
1056  return(1);
1057  }
1058 
1059  /* Backup the current zonelist */
1060  StrAppend(&backup_filename, zonelist_filename);
1061  StrAppend(&backup_filename, ".backup");
1062  status = backup_file(zonelist_filename, backup_filename);
1063  StrFree(backup_filename);
1064  if (status != 0) {
1065  StrFree(zonelist_filename);
1066  return(status);
1067  }
1068 
1069  /* Save our new one over, TODO should we validate it first? */
1070  status = xmlSaveFormatFile(zonelist_filename, doc, 1);
1071  StrFree(zonelist_filename);
1072  xmlFreeDoc(doc);
1073 
1074  if (status == -1) {
1075  printf("couldn't save zonelist\n");
1076  return(1);
1077  }
1078  }
1079 
1080  /* TODO - KICK THE ENFORCER? */
1081  /* <matthijs> TODO - ods-signer update? */
1082 
1083  if (xml_flag == 0) {
1084  printf("Imported zone: %s into database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone);
1085  } else {
1086  printf("Imported zone: %s\n", o_zone);
1087  }
1088 
1089 
1090  return 0;
1091 }
1092 
1093 /*
1094  * Delete a zone from the config
1095  */
1096  int
1098 {
1099 
1100  char* zonelist_filename = NULL;
1101  char* backup_filename = NULL;
1102  /* The settings that we need for the zone */
1103  int zone_id = -1;
1104  int policy_id = -1;
1105 
1106  xmlDocPtr doc = NULL;
1107 
1108  int status = 0;
1109  int user_certain; /* Continue ? */
1110 
1111  /* Database connection details */
1112  DB_HANDLE dbhandle;
1113  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
1114 
1115  /* We should either have a policy name or --all but not both */
1116  if (all_flag && o_zone != NULL) {
1117  printf("can not use --all with --zone\n");
1118  return(1);
1119  }
1120  else if (!all_flag && o_zone == NULL) {
1121  printf("please specify either --zone <zone> or --all\n");
1122  return(1);
1123  }
1124 
1125  /* Warn and confirm if they have asked to delete all zones */
1126  if (all_flag == 1) {
1127  printf("*WARNING* This will remove all zones from OpenDNSSEC; are you sure? [y/N] ");
1128 
1129  user_certain = getchar();
1130  if (user_certain != 'y' && user_certain != 'Y') {
1131  printf("Okay, quitting...\n");
1132  exit(0);
1133  }
1134  }
1135 
1136  /* try to connect to the database */
1137  status = db_connect(&dbhandle, &lock_fd, 1);
1138  if (status != 0) {
1139  printf("Failed to connect to database\n");
1140  db_disconnect(lock_fd);
1141  return(1);
1142  }
1143 
1144  /* Put dot back in if we need to; delete zone is the only time we do this */
1145  if (td_flag == 1) {
1146  StrAppend(&o_zone, ".");
1147  }
1148  /*
1149  * DO XML STUFF FIRST
1150  */
1151 
1152  if (xml_flag == 1) {
1153  /* Set zonelist from the conf.xml that we have got */
1154  status = read_zonelist_filename(&zonelist_filename);
1155  if (status != 0) {
1156  printf("couldn't read zonelist\n");
1157  db_disconnect(lock_fd);
1158  StrFree(zonelist_filename);
1159  return(1);
1160  }
1161 
1162  /* Read the file and delete our zone node(s) in memory */
1163  /* N.B. This is deliberately _not_ trailing dot agnostic; the user will have to ask to delete the exact zone */
1164  doc = del_zone_node(zonelist_filename, o_zone);
1165  if (doc == NULL) {
1166  db_disconnect(lock_fd);
1167  StrFree(zonelist_filename);
1168  return(1);
1169  }
1170 
1171  /* rename the Signconf file so that if the zone is readded the old
1172  * file will not be used */
1173  status = rename_signconf(zonelist_filename, o_zone);
1174  if (status != 0) {
1175  StrFree(zonelist_filename);
1176  db_disconnect(lock_fd);
1177  return(status);
1178  }
1179 
1180  /* Backup the current zonelist */
1181  StrAppend(&backup_filename, zonelist_filename);
1182  StrAppend(&backup_filename, ".backup");
1183  status = backup_file(zonelist_filename, backup_filename);
1184  StrFree(backup_filename);
1185  if (status != 0) {
1186  StrFree(zonelist_filename);
1187  db_disconnect(lock_fd);
1188  return(status);
1189  }
1190 
1191  /* Save our new one over, TODO should we validate it first? */
1192  status = xmlSaveFormatFile(zonelist_filename, doc, 1);
1193  xmlFreeDoc(doc);
1194  StrFree(zonelist_filename);
1195  if (status == -1) {
1196  printf("Could not save %s\n", zonelist_filename);
1197  db_disconnect(lock_fd);
1198  return(1);
1199  }
1200  }
1201 
1202  /*
1203  * NOW SORT OUT THE DATABASE (zone_id will still be -1 if we are deleting all)
1204  */
1205 
1206  /* See if the zone exists and get its ID, assuming we are not deleting all */
1207  if (all_flag == 0) {
1208  status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
1209  if (status != 0) {
1210  printf("Couldn't find zone %s\n", o_zone);
1211  db_disconnect(lock_fd);
1212  return(1);
1213  }
1214 
1215  }
1216 
1217  /* Mark keys as dead */
1218  status = KsmMarkKeysAsDead(zone_id);
1219  if (status != 0) {
1220  printf("Error: failed to mark keys as dead in database\n");
1221  db_disconnect(lock_fd);
1222  return(status);
1223  }
1224 
1225  /* Finally, we can delete the zone */
1226  status = KsmDeleteZone(zone_id);
1227 
1228  if (status != 0) {
1229  printf("Error: failed to remove zone%s from database\n", (all_flag == 1) ? "s" : "");
1230  db_disconnect(lock_fd);
1231  return status;
1232  }
1233 
1234  /* Call the signer_engine_cli to tell it that the zonelist has changed */
1235  if (all_flag == 0) {
1236  if (system(SIGNER_CLI_UPDATE) != 0)
1237  {
1238  printf("Could not call signer engine\n");
1239  }
1240  }
1241 
1242  /* Release sqlite lock file (if we have it) */
1243  db_disconnect(lock_fd);
1244 
1245  if (xml_flag == 0) {
1246  printf("Deleted zone: %s from database only, please run \"ods-ksmutil zonelist export\" to update zonelist.xml\n", o_zone);
1247  }
1248 
1249  return 0;
1250 }
1251 
1252 /*
1253  * List a zone
1254  */
1255  int
1257 {
1258 
1259  DB_HANDLE dbhandle;
1260  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
1261 
1262  char* zonelist_filename = NULL;
1263  int* zone_ids; /* List of zone_ids seen from zonelist.xml */
1264 
1265  xmlTextReaderPtr reader = NULL;
1266  int ret = 0; /* status of the XML parsing */
1267  char* tag_name = NULL;
1268 
1269  int file_zone_count = 0; /* As a quick check we will compare the number of */
1270  int j = 0; /* Another counter */
1271  char buffer[256]; /* For constructing part of the command */
1272  char* sql = NULL; /* SQL "IN" query */
1273  DB_RESULT result; /* Result of the query */
1274  DB_ROW row = NULL; /* Row data */
1275  char* temp_name = NULL;
1276 
1277  int status = 0;
1278 
1279  /* Set zonelist from the conf.xml that we have got */
1280  status = read_zonelist_filename(&zonelist_filename);
1281  if (status != 0) {
1282  printf("couldn't read zonelist\n");
1283  if (zonelist_filename != NULL) {
1284  StrFree(zonelist_filename);
1285  }
1286  return(1);
1287  }
1288 
1289  /* try to connect to the database */
1290  status = db_connect(&dbhandle, &lock_fd, 1);
1291  if (status != 0) {
1292  printf("Failed to connect to database\n");
1293  db_disconnect(lock_fd);
1294  return(1);
1295  }
1296 
1297  /* Read through the file counting zones TODO better way to do this? */
1298  reader = xmlNewTextReaderFilename(zonelist_filename);
1299  if (reader != NULL) {
1300  ret = xmlTextReaderRead(reader);
1301  while (ret == 1) {
1302  tag_name = (char*) xmlTextReaderLocalName(reader);
1303  /* Found <Zone> */
1304  if (strncmp(tag_name, "Zone", 4) == 0
1305  && strncmp(tag_name, "ZoneList", 8) != 0
1306  && xmlTextReaderNodeType(reader) == 1) {
1307  file_zone_count++;
1308  }
1309  /* Read the next line */
1310  ret = xmlTextReaderRead(reader);
1311  StrFree(tag_name);
1312  }
1313  xmlFreeTextReader(reader);
1314  if (ret != 0) {
1315  printf("%s : failed to parse\n", zonelist_filename);
1316  return 1;
1317  }
1318  } else {
1319  printf("Unable to open %s\n", zonelist_filename);
1320  return 1;
1321  }
1322 
1323  /* Allocate space for the list of zone IDs */
1324  zone_ids = MemMalloc(file_zone_count * sizeof(int));
1325 
1326  /* Read the file and list the zones as we go */
1327  list_zone_node(zonelist_filename, zone_ids);
1328 
1329  /* Now see if there are any zones in the DB which are not in the file */
1330  if (file_zone_count != 0) {
1331  StrAppend(&sql, "select name from zones where id not in (");
1332  for (j = 0; j < file_zone_count; ++j) {
1333  if (j != 0) {
1334  StrAppend(&sql, ",");
1335  }
1336  snprintf(buffer, sizeof(buffer), "%d", zone_ids[j]);
1337  StrAppend(&sql, buffer);
1338  }
1339  StrAppend(&sql, ")");
1340  } else {
1341  StrAppend(&sql, "select name from zones");
1342  }
1343 
1344  status = DbExecuteSql(DbHandle(), sql, &result);
1345  if (status == 0) {
1346  status = DbFetchRow(result, &row);
1347  while (status == 0) {
1348  /* Got a row, print it */
1349  DbString(row, 0, &temp_name);
1350 
1351  printf("Found zone %s in DB but not zonelist.\n", temp_name);
1352  status = DbFetchRow(result, &row);
1353  file_zone_count++;
1354  }
1355 
1356  /* Convert EOF status to success */
1357 
1358  if (status == -1) {
1359  status = 0;
1360  }
1361 
1362  DbFreeResult(result);
1363  }
1364 
1365  db_disconnect(lock_fd);
1366  DbDisconnect(dbhandle);
1367 
1368  if (file_zone_count == 0) {
1369  printf("No zones in DB or zonelist.\n");
1370  }
1371 
1372  MemFree(zone_ids);
1373  StrFree(sql);
1374  StrFree(zonelist_filename);
1375  StrFree(temp_name);
1376 
1377  return 0;
1378 }
1379 
1380 /*
1381  * To export:
1382  * keys|ds for zone
1383  */
1384  int
1386 {
1387  int status = 0;
1388  /* Database connection details */
1389  DB_HANDLE dbhandle;
1390 
1391  int zone_id = -1;
1392  int state_id = -1;
1393  int keytype_id = KSM_TYPE_KSK;
1394 
1395  char *case_keytype = NULL;
1396  char *case_keystate = NULL;
1397  char *zone_name = NULL;
1398 
1399  /* Key information */
1400  hsm_key_t *key = NULL;
1401  ldns_rr *dnskey_rr = NULL;
1402  ldns_rr *ds_sha1_rr = NULL;
1403  ldns_rr *ds_sha256_rr = NULL;
1404  hsm_sign_params_t *sign_params = NULL;
1405 
1406  /* To find the ttl of the DS */
1407  int policy_id = -1;
1408  int rrttl = -1;
1409  int param_id = -1; /* unused */
1410 
1411  char* sql = NULL;
1412  KSM_KEYDATA data; /* Data for each key */
1413  DB_RESULT result; /* Result set from query */
1414  size_t nchar; /* Number of characters written */
1415  char buffer[256]; /* For constructing part of the command */
1416 
1417  int done_something = 0; /* Have we exported any keys? */
1418 
1419  /* See what arguments we were passed (if any) otherwise set the defaults */
1420  /* Check keystate, can be state or keytype */
1421  if (o_keystate != NULL) {
1422  case_keystate = StrStrdup(o_keystate);
1423  (void) StrToUpper(case_keystate);
1424  if (strncmp(case_keystate, "KEYPUBLISH", 10) == 0 || strncmp(o_keystate, "10", 2) == 0) {
1425  state_id = KSM_STATE_KEYPUBLISH;
1426  }
1427  else if (strncmp(case_keystate, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) {
1428  state_id = KSM_STATE_GENERATE;
1429  }
1430  else if (strncmp(case_keystate, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) {
1431  state_id = KSM_STATE_PUBLISH;
1432  }
1433  else if (strncmp(case_keystate, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) {
1434  state_id = KSM_STATE_READY;
1435  }
1436  else if (strncmp(case_keystate, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) {
1437  state_id = KSM_STATE_ACTIVE;
1438  }
1439  else if (strncmp(case_keystate, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) {
1440  state_id = KSM_STATE_RETIRE;
1441  }
1442  else if (strncmp(case_keystate, "DEAD", 4) == 0 || strncmp(o_keystate, "6", 1) == 0) {
1443  state_id = KSM_STATE_DEAD;
1444  }
1445  else if (strncmp(case_keystate, "DSSUB", 5) == 0 || strncmp(o_keystate, "7", 1) == 0) {
1446  state_id = KSM_STATE_DSSUB;
1447  }
1448  else if (strncmp(case_keystate, "DSPUBLISH", 9) == 0 || strncmp(o_keystate, "8", 1) == 0) {
1449  state_id = KSM_STATE_DSPUBLISH;
1450  }
1451  else if (strncmp(case_keystate, "DSREADY", 7) == 0 || strncmp(o_keystate, "9", 1) == 0) {
1452  state_id = KSM_STATE_DSREADY;
1453  }
1454  else {
1455  printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE, RETIRE, DEAD, DSSUB, DSPUBLISH, DSREADY or KEYPUBLISH\n", o_keystate);
1456 
1457  StrFree(case_keystate);
1458  return(1);
1459  }
1460  StrFree(case_keystate);
1461  }
1462 
1463  /* Check keytype */
1464  if (o_keytype != NULL) {
1465  case_keytype = StrStrdup(o_keytype);
1466  (void) StrToUpper(case_keytype);
1467  if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) {
1468  keytype_id = KSM_TYPE_KSK;
1469  }
1470  else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) {
1471  keytype_id = KSM_TYPE_ZSK;
1472  }
1473  else {
1474  printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype);
1475 
1476  StrFree(case_keytype);
1477  return(1);
1478  }
1479  StrFree(case_keytype);
1480  }
1481 
1482  /* try to connect to the database */
1483  status = db_connect(&dbhandle, NULL, 0);
1484  if (status != 0) {
1485  printf("Failed to connect to database\n");
1486  return(1);
1487  }
1488 
1489  /* check that the zone name is valid and use it to get some ids */
1490  if (o_zone != NULL) {
1491  status = KsmZoneIdFromName(o_zone, &zone_id);
1492  if (status != 0) {
1493  /* Try again with td */
1494  StrAppend(&o_zone, ".");
1495  status = KsmZoneIdFromName(o_zone, &zone_id);
1496  if (status != 0) {
1497  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
1498  return(status);
1499  }
1500  }
1501  }
1502 
1503  status = hsm_open(config, hsm_prompt_pin, NULL);
1504  if (status) {
1505  hsm_print_error(NULL);
1506  exit(-1);
1507  }
1508 
1509  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1510  if (state_id != -1) {
1511  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, state_id, 0);
1512  } else {
1513  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d)",
1516  if (nchar >= sizeof(buffer)) {
1517  status = -1;
1518  hsm_close();
1519  return status;
1520  }
1521  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, 0);
1522 
1523  }
1524  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype_id, 1);
1525  if (zone_id != -1) {
1526  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 2);
1527  }
1528  DqsOrderBy(&sql, "STATE");
1529  DqsEnd(&sql);
1530 
1531  status = KsmKeyInitSql(&result, sql);
1532  if (status == 0) {
1533  status = KsmKey(result, &data);
1534  while (status == 0) {
1535 
1536  /* Code to output the DNSKEY record (stolen from hsmutil) */
1537  key = hsm_find_key_by_id(NULL, data.location);
1538 
1539  if (!key) {
1540  printf("Key %s in DB but not repository\n", data.location);
1541  hsm_close();
1542  return -1;
1543  }
1544 
1545  sign_params = hsm_sign_params_new();
1546  /* If zone_id == -1 then we need to work out the zone name from data.zone_id */
1547  if (zone_id == -1) {
1548  status = KsmZoneNameFromId(data.zone_id, &zone_name);
1549  if (status != 0) {
1550  printf("Error: unable to find zone name for id %d\n", zone_id);
1551  hsm_sign_params_free(sign_params);
1552  hsm_close();
1553  return(status);
1554  }
1555  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name);
1556  StrFree(zone_name);
1557  }
1558  else {
1559  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, o_zone);
1560  }
1561 
1562  sign_params->algorithm = data.algorithm;
1563  sign_params->flags = LDNS_KEY_ZONE_KEY;
1564  if (keytype_id == KSM_TYPE_KSK) {
1565  sign_params->flags += LDNS_KEY_SEP_KEY;
1566  }
1567  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
1568  sign_params->keytag = ldns_calc_keytag(dnskey_rr);
1569 
1570  if (ds_flag == 0) {
1571 
1572  /* Set TTL if we can find it; else leave it as the default */
1573  /* We need a policy id */
1574  status = KsmPolicyIdFromZoneId(data.zone_id, &policy_id);
1575  if (status == 0) {
1576 
1577  /* Use this to get the TTL parameter value */
1578  if (keytype_id == KSM_TYPE_KSK) {
1579  status = KsmParameterValue(KSM_PAR_KSKTTL_STRING, KSM_PAR_KSKTTL_CAT, &rrttl, policy_id, &param_id);
1580  } else {
1581  status = KsmParameterValue(KSM_PAR_ZSKTTL_STRING, KSM_PAR_ZSKTTL_CAT, &rrttl, policy_id, &param_id);
1582  }
1583  if (status == 0) {
1584  ldns_rr_set_ttl(dnskey_rr, rrttl);
1585  }
1586  }
1587 
1588  printf("\n;%s %s DNSKEY record:\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
1589  ldns_rr_print(stdout, dnskey_rr);
1590  }
1591  else {
1592 
1593  /* Set TTL if we can find it; else leave it as the default */
1594  /* We need a policy id */
1595  status = KsmPolicyIdFromZoneId(data.zone_id, &policy_id);
1596  if (status == 0) {
1597 
1598  /* Use this to get the DSTTL parameter value */
1599  status = KsmParameterValue(KSM_PAR_DSTTL_STRING, KSM_PAR_DSTTL_CAT, &rrttl, policy_id, &param_id);
1600  if (status == 0) {
1601  ldns_rr_set_ttl(dnskey_rr, rrttl);
1602  }
1603  }
1604 
1605  printf("\n;%s %s DS record (SHA1):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
1606  ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
1607  ldns_rr_print(stdout, ds_sha1_rr);
1608 
1609  printf("\n;%s %s DS record (SHA256):\n", KsmKeywordStateValueToName(data.state), (keytype_id == KSM_TYPE_KSK ? "KSK" : "ZSK"));
1610  ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
1611  ldns_rr_print(stdout, ds_sha256_rr);
1612  }
1613 
1614  done_something = 1;
1615 
1616  hsm_sign_params_free(sign_params);
1617  hsm_key_free(key);
1618  status = KsmKey(result, &data);
1619 
1620  }
1621  /* Convert EOF status to success */
1622  if (status == -1) {
1623  status = 0;
1624  }
1625 
1626  KsmKeyEnd(result);
1627  }
1628 
1629  /* If we did nothing then explain why not */
1630  if (!done_something) {
1631  if (state_id != -1) {
1632  printf("No keys in %s state to export.\n", KsmKeywordStateValueToName(state_id) );
1633  } else {
1634  printf("No keys in READY state or higher to export.\n");
1635  }
1636  }
1637 
1638  /* TODO when the above is working then replicate it twice for the case where keytype == -1 */
1639 
1640  if (dnskey_rr != NULL) {
1641  ldns_rr_free(dnskey_rr);
1642  }
1643  if (ds_sha1_rr != NULL) {
1644  ldns_rr_free(ds_sha1_rr);
1645  }
1646  if (ds_sha256_rr != NULL) {
1647  ldns_rr_free(ds_sha256_rr);
1648  }
1649 
1650  hsm_close();
1651  DbDisconnect(dbhandle);
1652 
1653  return 0;
1654 }
1655 
1656 /*
1657  * To export:
1658  * policies (all, unless one is named) to xml
1659  */
1660  int
1662 {
1663  int status = 0;
1664  /* Database connection details */
1665  DB_HANDLE dbhandle;
1666 
1667  xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0");
1668  xmlNodePtr root;
1669  KSM_POLICY *policy;
1670 
1671  DB_RESULT result; /* Result set from query */
1672 
1673  /* We should either have a policy name or --all but not both */
1674  if (all_flag && o_policy != NULL) {
1675  printf("can not use --all with --policy\n");
1676  return(1);
1677  }
1678  else if (!all_flag && o_policy == NULL) {
1679  printf("please specify either --policy <policy> or --all\n");
1680  return(1);
1681  }
1682 
1683  /* try to connect to the database */
1684  status = db_connect(&dbhandle, NULL, 0);
1685  if (status != 0) {
1686  printf("Failed to connect to database\n");
1687  return(1);
1688  }
1689 
1690  /* Make some space for the policy */
1691  policy = (KSM_POLICY *)malloc(sizeof(KSM_POLICY));
1692  policy->signer = (KSM_SIGNER_POLICY *)malloc(sizeof(KSM_SIGNER_POLICY));
1693  policy->signature = (KSM_SIGNATURE_POLICY *)malloc(sizeof(KSM_SIGNATURE_POLICY));
1694  policy->zone = (KSM_ZONE_POLICY *)malloc(sizeof(KSM_ZONE_POLICY));
1695  policy->parent = (KSM_PARENT_POLICY *)malloc(sizeof(KSM_PARENT_POLICY));
1696  policy->keys = (KSM_COMMON_KEY_POLICY *)malloc(sizeof(KSM_COMMON_KEY_POLICY));
1697  policy->ksk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY));
1698  policy->zsk = (KSM_KEY_POLICY *)malloc(sizeof(KSM_KEY_POLICY));
1699  policy->denial = (KSM_DENIAL_POLICY *)malloc(sizeof(KSM_DENIAL_POLICY));
1700  policy->enforcer = (KSM_ENFORCER_POLICY *)malloc(sizeof(KSM_ENFORCER_POLICY));
1701  /* policy->audit = (KSM_AUDIT_POLICY *)malloc(sizeof(KSM_AUDIT_POLICY)); */
1702  policy->audit = (char *)calloc(KSM_POLICY_AUDIT_LENGTH, sizeof(char));
1703  policy->description = (char *)calloc(KSM_POLICY_DESC_LENGTH, sizeof(char));
1704  if (policy->signer == NULL || policy->signature == NULL ||
1705  policy->zone == NULL || policy->parent == NULL ||
1706  policy->keys == NULL ||
1707  policy->ksk == NULL || policy->zsk == NULL ||
1708  policy->denial == NULL || policy->enforcer == NULL) {
1709  fprintf(stderr, "Malloc for policy struct failed\n");
1710  exit(1);
1711  }
1712 
1713  /* Setup doc with a root node of <KASP> */
1714  xmlKeepBlanksDefault(0);
1715  xmlTreeIndentString = " ";
1716  root = xmlNewDocNode(doc, NULL, (const xmlChar *)"KASP", NULL);
1717  (void) xmlDocSetRootElement(doc, root);
1718 
1719  /* Read policies (all if policy_name == NULL; else named policy only) */
1720  status = KsmPolicyInit(&result, o_policy);
1721  if (status == 0) {
1722  /* get the first policy */
1723  status = KsmPolicy(result, policy);
1724  KsmPolicyRead(policy);
1725 
1726  while (status == 0) {
1727  append_policy(doc, policy);
1728 
1729  /* get next policy */
1730  status = KsmPolicy(result, policy);
1731  KsmPolicyRead(policy);
1732 
1733  }
1734  }
1735 
1736  xmlSaveFormatFile("-", doc, 1);
1737 
1738  xmlFreeDoc(doc);
1739  KsmPolicyFree(policy);
1740 
1741  DbDisconnect(dbhandle);
1742 
1743  return 0;
1744 }
1745 
1746 /*
1747  * To export:
1748  * zonelist to xml
1749  */
1750  int
1752 {
1753  int status = 0;
1754  /* Database connection details */
1755  DB_HANDLE dbhandle;
1756 
1757  xmlDocPtr doc = xmlNewDoc((const xmlChar *)"1.0");
1758  xmlNodePtr root;
1759  KSM_ZONE *zone;
1760  int prev_policy_id = -1;
1761 
1762  DB_RESULT result; /* Result set from query */
1763 
1764  /* try to connect to the database */
1765  status = db_connect(&dbhandle, NULL, 0);
1766  if (status != 0) {
1767  printf("Failed to connect to database\n");
1768  return(1);
1769  }
1770 
1771  /* Make some space for the zone */
1772  zone = (KSM_ZONE *)malloc(sizeof(KSM_ZONE));
1773  if (zone == NULL) {
1774  fprintf(stderr, "Malloc for zone struct failed\n");
1775  exit(1);
1776  }
1777 
1778  /* Setup doc with a root node of <ZoneList> */
1779  xmlKeepBlanksDefault(0);
1780  xmlTreeIndentString = " ";
1781  root = xmlNewDocNode(doc, NULL, (const xmlChar *)"ZoneList", NULL);
1782  (void) xmlDocSetRootElement(doc, root);
1783 
1784  /* Read zones */
1785  status = KsmZoneInit(&result, -1);
1786  if (status == 0) {
1787  /* get the first zone */
1788  status = KsmZone(result, zone);
1789 
1790  while (status == 0) {
1791  if (zone->policy_id != prev_policy_id) {
1792  prev_policy_id = zone->policy_id;
1793  status = get_policy_name_from_id(zone);
1794  if (status != 0) {
1795  fprintf(stderr, "Couldn't get name for policy with ID: %d, exiting...\n", zone->policy_id);
1796  return(1);
1797  }
1798  }
1799  append_zone(doc, zone);
1800 
1801  /* get next zone */
1802  status = KsmZone(result, zone);
1803 
1804  }
1805  }
1806 
1807  xmlSaveFormatFile("-", doc, 1);
1808 
1809  xmlFreeDoc(doc);
1810  /*KsmZoneFree(zone);*/
1811 
1812  DbDisconnect(dbhandle);
1813 
1814  return 0;
1815 }
1816 
1817 /*
1818  * To rollover a zone (or all zones on a policy if keys are shared)
1819  */
1820  int
1822 {
1823  /* Database connection details */
1824  DB_HANDLE dbhandle;
1825  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
1826  DB_RESULT result; /* Result of parameter query */
1827  KSM_PARAMETER data; /* Parameter information */
1828 
1829  int key_type = -1;
1830  int zone_id = -1;
1831  int policy_id = -1;
1832 
1833  int status = 0;
1834  int user_certain;
1835 
1836  char logmsg[256]; /* For the message that we log when we are done here */
1837 
1838  /* If we were given a keytype, turn it into a number */
1839  if (o_keytype != NULL) {
1842  }
1843 
1844  /* try to connect to the database */
1845  status = db_connect(&dbhandle, &lock_fd, 1);
1846  if (status != 0) {
1847  printf("Failed to connect to database\n");
1848  db_disconnect(lock_fd);
1849  return(1);
1850  }
1851 
1852  status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
1853  if (status != 0) {
1854  /* Try again with td */
1855  StrAppend(&o_zone, ".");
1856  status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
1857  if (status != 0) {
1858  printf("Error, can't find zone : %s\n", o_zone);
1859  db_disconnect(lock_fd);
1860  return(status);
1861  }
1862  }
1863 
1864  /* Get the shared_keys parameter */
1865  status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
1866  if (status != 0) {
1867  db_disconnect(lock_fd);
1868  return(status);
1869  }
1870  status = KsmParameter(result, &data);
1871  if (status != 0) {
1872  db_disconnect(lock_fd);
1873  return(status);
1874  }
1875  KsmParameterEnd(result);
1876 
1877  /* Warn and confirm if this will roll more than one zone */
1878  if (data.value == 1) {
1879  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] ");
1880 
1881  user_certain = getchar();
1882  if (user_certain != 'y' && user_certain != 'Y') {
1883  printf("Okay, quitting...\n");
1884  db_disconnect(lock_fd);
1885  exit(0);
1886  }
1887  }
1888 
1889  status = keyRoll(zone_id, -1, key_type);
1890  if (status != 0) {
1891  db_disconnect(lock_fd);
1892  return(status);
1893  }
1894 
1895  /* Let them know that it seemed to work */
1896  snprintf(logmsg, 256, "Manual key rollover for key type %s on zone %s initiated" , (o_keytype == NULL) ? "all" : o_keytype, o_zone);
1897  printf("\n%s\n", logmsg);
1898 
1899 /* send the msg to syslog */
1900 #ifdef HAVE_OPENLOG_R
1901  openlog_r("ods-ksmutil", 0, DEFAULT_LOG_FACILITY, &sdata);
1902 #else
1903  openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY);
1904 #endif
1905 #ifdef HAVE_SYSLOG_R
1906  syslog_r(LOG_INFO, &sdata, "%s", logmsg);
1907 #else
1908  syslog(LOG_INFO, "%s", logmsg);
1909 #endif
1910 #ifdef HAVE_CLOSELOG_R
1911  closelog_r(&sdata);
1912 #else
1913  closelog();
1914 #endif
1915 
1916  /* Release sqlite lock file (if we have it) */
1917  db_disconnect(lock_fd);
1918 
1919  /* Need to poke the enforcer to wake it up */
1920  if (restart_enforcerd() != 0)
1921  {
1922  fprintf(stderr, "Could not HUP ods-enforcerd\n");
1923  }
1924 
1925  DbDisconnect(dbhandle);
1926 
1927  return 0;
1928 }
1929 
1930 /*
1931  * To rollover all zones on a policy
1932  */
1933  int
1935 {
1936  /* Database connection details */
1937  DB_HANDLE dbhandle;
1938  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
1939 
1940  DB_RESULT result; /* To see if the policy shares keys or not */
1941 
1942  int zone_count = -1;
1943 
1944  int key_type = -1;
1945  int policy_id = 0;
1946 
1947  int status = 0;
1948  int user_certain;
1949 
1950  char logmsg[256]; /* For the message that we log when we are done here */
1951 
1952  /* If we were given a keytype, turn it into a number */
1953  if (o_keytype != NULL) {
1956  }
1957 
1958  /* try to connect to the database */
1959  status = db_connect(&dbhandle, &lock_fd, 1);
1960  if (status != 0) {
1961  printf("Failed to connect to database\n");
1962  db_disconnect(lock_fd);
1963  return(1);
1964  }
1965 
1966  status = KsmPolicyIdFromName(o_policy, &policy_id);
1967  if (status != 0) {
1968  printf("Error, can't find policy : %s\n", o_policy);
1969  db_disconnect(lock_fd);
1970  return(status);
1971  }
1972 
1973  /* Warn and confirm */
1974  printf("*WARNING* This will roll all keys on the policy; are you sure? [y/N] ");
1975 
1976  user_certain = getchar();
1977  if (user_certain != 'y' && user_certain != 'Y') {
1978  printf("Okay, quitting...\n");
1979  db_disconnect(lock_fd);
1980  exit(0);
1981  }
1982 
1983  /* Find out how many zones we will need to do */
1984  /* how many zones on this policy */
1985  status = KsmZoneCountInit(&result, policy_id);
1986  if (status == 0) {
1987  status = KsmZoneCount(result, &zone_count);
1988  }
1989  DbFreeResult(result);
1990 
1991  if (status == 0) {
1992  /* make sure that we have at least one zone */
1993  if (zone_count == 0) {
1994  printf("No zones on policy; nothing to roll\n");
1995  db_disconnect(lock_fd);
1996  return status;
1997  }
1998  } else {
1999  printf("Couldn't count zones on policy; quitting...\n");
2000  db_disconnect(lock_fd);
2001  exit(1);
2002  }
2003 
2004  status = keyRoll(-1, policy_id, key_type);
2005  if (status != 0) {
2006  db_disconnect(lock_fd);
2007  return(status);
2008  }
2009 
2010  /* Let them know that it seemed to work */
2011  snprintf(logmsg, 256, "Manual key rollover for key type %s on policy %s initiated" , (o_keytype == NULL) ? "all" : o_keytype, o_policy);
2012  printf("%s\n", logmsg);
2013 
2014 /* send the msg to syslog */
2015 #ifdef HAVE_OPENLOG_R
2016  openlog_r("ods-ksmutil", 0, DEFAULT_LOG_FACILITY, &sdata);
2017 #else
2018  openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY);
2019 #endif
2020 #ifdef HAVE_SYSLOG_R
2021  syslog_r(LOG_INFO, &sdata, "%s", logmsg);
2022 #else
2023  syslog(LOG_INFO, "%s", logmsg);
2024 #endif
2025 #ifdef HAVE_CLOSELOG_R
2026  closelog_r(&sdata);
2027 #else
2028  closelog();
2029 #endif
2030 
2031  /* Release sqlite lock file (if we have it) */
2032  db_disconnect(lock_fd);
2033 
2034  /* Need to poke the enforcer to wake it up */
2035  if (restart_enforcerd() != 0)
2036  {
2037  fprintf(stderr, "Could not HUP ods-enforcerd\n");
2038  }
2039 
2040  DbDisconnect(dbhandle);
2041 
2042  return 0;
2043 }
2044 
2045 /*
2046  * purge dead keys from the database
2047  */
2048  int
2050 {
2051  int status = 0;
2052 
2053  int policy_id = -1;
2054  int zone_id = -1;
2055 
2056  /* Database connection details */
2057  DB_HANDLE dbhandle;
2058  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2059 
2060  /* try to connect to the database */
2061  status = db_connect(&dbhandle, &lock_fd, 1);
2062  if (status != 0) {
2063  printf("Failed to connect to database\n");
2064  db_disconnect(lock_fd);
2065  return(1);
2066  }
2067 
2068  /* Turn policy name into an id (if provided) */
2069  if (o_policy != NULL) {
2070  status = KsmPolicyIdFromName(o_policy, &policy_id);
2071  if (status != 0) {
2072  printf("Error: unable to find a policy named \"%s\" in database\n", o_policy);
2073  db_disconnect(lock_fd);
2074  return status;
2075  }
2076  }
2077 
2078  /* Turn zone name into an id (if provided) */
2079  if (o_zone != NULL) {
2080  status = KsmZoneIdFromName(o_zone, &zone_id);
2081  if (status != 0) {
2082  /* Try again with td */
2083  StrAppend(&o_zone, ".");
2084  status = KsmZoneIdFromName(o_zone, &zone_id);
2085  if (status != 0) {
2086  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
2087  db_disconnect(lock_fd);
2088  return(status);
2089  }
2090  }
2091  }
2092 
2093  status = PurgeKeys(zone_id, policy_id);
2094 
2095  if (status != 0) {
2096  printf("Error: failed to purge dead keys\n");
2097  db_disconnect(lock_fd);
2098  return status;
2099  }
2100 
2101  /* Release sqlite lock file (if we have it) */
2102  db_disconnect(lock_fd);
2103 
2104  DbDisconnect(dbhandle);
2105  return 0;
2106 }
2107 
2108 /*
2109  * note that fact that a backup has been performed
2110  */
2111  int
2112 cmd_backup (const char* qualifier)
2113 {
2114  int status = 0;
2115 
2116  int repo_id = -1;
2117 
2118  /* Database connection details */
2119  DB_HANDLE dbhandle;
2120  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2121 
2122  char* datetime = DtParseDateTimeString("now");
2123 
2124  /* Check datetime in case it came back NULL */
2125  if (datetime == NULL) {
2126  printf("Couldn't turn \"now\" into a date, quitting...\n");
2127  exit(1);
2128  }
2129 
2130  /* try to connect to the database */
2131  status = db_connect(&dbhandle, &lock_fd, 1);
2132  if (status != 0) {
2133  printf("Failed to connect to database\n");
2134  db_disconnect(lock_fd);
2135  StrFree(datetime);
2136  return(1);
2137  }
2138 
2139  /* Turn repo name into an id (if provided) */
2140  if (o_repository != NULL) {
2141  status = KsmSmIdFromName(o_repository, &repo_id);
2142  if (status != 0) {
2143  printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
2144  db_disconnect(lock_fd);
2145  StrFree(datetime);
2146  return status;
2147  }
2148  }
2149 
2150  /* Do Pre first */
2151  if (strncmp(qualifier, "PREPARE", 7) == 0 ||
2152  strncmp(qualifier, "DONE", 4) == 0 ) {
2153  status = KsmMarkPreBackup(repo_id, datetime);
2154  if (status == -1) {
2155  printf("There were no keys to mark\n");
2156  }
2157  else if (status != 0) {
2158  printf("Error: failed to mark pre_backup as done\n");
2159  db_disconnect(lock_fd);
2160  StrFree(datetime);
2161  return status;
2162  } else {
2163  if (strncmp(qualifier, "PREPARE", 7) == 0) {
2164  if (o_repository != NULL) {
2165  printf("Marked repository %s as pre-backed up at %s\n", o_repository, datetime);
2166  } else {
2167  printf("Marked all repositories as pre-backed up at %s\n", datetime);
2168  }
2169  }
2170  }
2171  }
2172 
2173  /* Then commit */
2174  if (strncmp(qualifier, "COMMIT", 6) == 0 ||
2175  strncmp(qualifier, "DONE", 4) == 0 ) {
2176  status = KsmMarkBackup(repo_id, datetime);
2177  if (status == -1) {
2178  printf("There were no keys to mark\n");
2179  }
2180  else if (status != 0) {
2181  printf("Error: failed to mark backup as done\n");
2182  db_disconnect(lock_fd);
2183  StrFree(datetime);
2184  return status;
2185  } else {
2186  if (o_repository != NULL) {
2187  printf("Marked repository %s as backed up at %s\n", o_repository, datetime);
2188  } else {
2189  printf("Marked all repositories as backed up at %s\n", datetime);
2190  }
2191  }
2192  }
2193 
2194  /* Finally rollback */
2195  if (strncmp(qualifier, "ROLLBACK", 6) == 0 ) {
2196  status = KsmRollbackMarkPreBackup(repo_id);
2197  if (status == -1) {
2198  printf("There were no keys to rollback\n");
2199  }
2200  else if (status != 0) {
2201  printf("Error: failed to mark backup as done\n");
2202  db_disconnect(lock_fd);
2203  StrFree(datetime);
2204  return status;
2205  } else {
2206  if (o_repository != NULL) {
2207  printf("Rolled back pre-backup of repository %s\n", o_repository);
2208  } else {
2209  printf("Rolled back pre-backup of all repositories\n");
2210  }
2211  }
2212  }
2213 
2214  StrFree(datetime);
2215  /* Release sqlite lock file (if we have it) */
2216  db_disconnect(lock_fd);
2217 
2218  DbDisconnect(dbhandle);
2219  return 0;
2220 }
2221 
2222 /*
2223  * List rollovers
2224  */
2225  int
2227 {
2228  int status = 0;
2229 
2230  int qualifier_id = -1; /* ID of qualifer (if given) */
2231 
2232  /* Database connection details */
2233  DB_HANDLE dbhandle;
2234  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2235 
2236  /* try to connect to the database */
2237  status = db_connect(&dbhandle, &lock_fd, 1);
2238  if (status != 0) {
2239  printf("Failed to connect to database\n");
2240  db_disconnect(lock_fd);
2241  return(1);
2242  }
2243 
2244  /* Turn zone name into an id (if provided) */
2245  if (o_zone != NULL) {
2246  status = KsmZoneIdFromName(o_zone, &qualifier_id);
2247  if (status != 0) {
2248  /* Try again with td */
2249  StrAppend(&o_zone, ".");
2250  status = KsmZoneIdFromName(o_zone, &qualifier_id);
2251  if (status != 0) {
2252  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
2253  db_disconnect(lock_fd);
2254  return(status);
2255  }
2256  }
2257  }
2258 
2259  printf("Rollovers:\n");
2260 
2261  status = KsmListRollovers(qualifier_id);
2262 
2263  if (status != 0) {
2264  printf("Error: failed to list rollovers\n");
2265  db_disconnect(lock_fd);
2266  return status;
2267  }
2268 
2269  printf("\n");
2270 
2271  /* Release sqlite lock file (if we have it) */
2272  db_disconnect(lock_fd);
2273 
2274  DbDisconnect(dbhandle);
2275  return 0;
2276 }
2277 
2278 /*
2279  * List backups
2280  */
2281  int
2283 {
2284  int status = 0;
2285 
2286  int qualifier_id = -1; /* ID of qualifer (if given) */
2287 
2288  /* Database connection details */
2289  DB_HANDLE dbhandle;
2290  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2291 
2292  /* try to connect to the database */
2293  status = db_connect(&dbhandle, &lock_fd, 0);
2294  if (status != 0) {
2295  printf("Failed to connect to database\n");
2296  db_disconnect(lock_fd);
2297  return(1);
2298  }
2299 
2300  /* Turn repo name into an id (if provided) */
2301  if (o_repository != NULL) {
2302  status = KsmSmIdFromName(o_repository, &qualifier_id);
2303  if (status != 0) {
2304  printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
2305  db_disconnect(lock_fd);
2306  return status;
2307  }
2308  }
2309 
2310  printf("Backups:\n");
2311  status = KsmListBackups(qualifier_id, verbose_flag);
2312 
2313  if (status != 0) {
2314  printf("Error: failed to list backups\n");
2315  db_disconnect(lock_fd);
2316  return status;
2317  }
2318  printf("\n");
2319 
2320  /* Release sqlite lock file (if we have it) */
2321  db_disconnect(lock_fd);
2322 
2323  DbDisconnect(dbhandle);
2324  return 0;
2325 }
2326 
2327 /*
2328  * List repos
2329  */
2330  int
2332 {
2333  int status = 0;
2334 
2335  /* Database connection details */
2336  DB_HANDLE dbhandle;
2337  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2338 
2339  /* try to connect to the database */
2340  status = db_connect(&dbhandle, &lock_fd, 0);
2341  if (status != 0) {
2342  printf("Failed to connect to database\n");
2343  db_disconnect(lock_fd);
2344  return(1);
2345  }
2346 
2347  printf("Repositories:\n");
2348 
2349  status = KsmListRepos();
2350 
2351  if (status != 0) {
2352  printf("Error: failed to list repositories\n");
2353  if (lock_fd != NULL) {
2354  fclose(lock_fd);
2355  }
2356  return status;
2357  }
2358 
2359  printf("\n");
2360 
2361  /* Release sqlite lock file (if we have it) */
2362  db_disconnect(lock_fd);
2363 
2364  DbDisconnect(dbhandle);
2365  return 0;
2366 }
2367 
2368 /*
2369  * List policy
2370  */
2371  int
2373 {
2374  int status = 0;
2375 
2376  /* Database connection details */
2377  DB_HANDLE dbhandle;
2378  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2379 
2380  /* try to connect to the database */
2381  status = db_connect(&dbhandle, &lock_fd, 0);
2382  if (status != 0) {
2383  printf("Failed to connect to database\n");
2384  db_disconnect(lock_fd);
2385  return(1);
2386  }
2387 
2388  printf("Policies:\n");
2389 
2390  status = KsmListPolicies();
2391 
2392  if (status != 0) {
2393  printf("Error: failed to list policies\n");
2394  db_disconnect(lock_fd);
2395  return status;
2396  }
2397 
2398  printf("\n");
2399 
2400  /* Release sqlite lock file (if we have it) */
2401  db_disconnect(lock_fd);
2402 
2403  DbDisconnect(dbhandle);
2404  return 0;
2405 }
2406 
2407 /*
2408  * List keys
2409  */
2410  int
2412 {
2413  int status = 0;
2414  int qualifier_id = -1;
2415 
2416  /* Database connection details */
2417  DB_HANDLE dbhandle;
2418  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2419 
2420  /* try to connect to the database */
2421  status = db_connect(&dbhandle, &lock_fd, 0);
2422  if (status != 0) {
2423  printf("Failed to connect to database\n");
2424  db_disconnect(lock_fd);
2425  return(1);
2426  }
2427 
2428  /* Turn zone name into an id (if provided) */
2429  if (o_zone != NULL) {
2430  status = KsmZoneIdFromName(o_zone, &qualifier_id);
2431  if (status != 0) {
2432  /* Try again with td */
2433  StrAppend(&o_zone, ".");
2434  status = KsmZoneIdFromName(o_zone, &qualifier_id);
2435  if (status != 0) {
2436  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
2437  db_disconnect(lock_fd);
2438  return(status);
2439  }
2440  }
2441  }
2442 
2443  printf("Keys:\n");
2444 
2445  status = ListKeys(qualifier_id);
2446 
2447  if (status != 0) {
2448  printf("Error: failed to list keys\n");
2449  db_disconnect(lock_fd);
2450  return status;
2451  }
2452 
2453  printf("\n");
2454 
2455  /* Release sqlite lock file (if we have it) */
2456  db_disconnect(lock_fd);
2457 
2458  DbDisconnect(dbhandle);
2459  return 0;
2460 }
2461 
2462 /*
2463  * KSKretire
2464  find key (either by details provided or oldest active),
2465  make sure that it is unique and in active state,
2466  retire key and set its dead time,
2467  */
2468  int
2470 {
2471  int status = 0;
2472  int zone_id = -1;
2473  int policy_id = -1;
2474  int key_count = -1;
2475  int keytag_int = -1;
2476  int temp_key_state = -1;
2477  int temp_keypair_id = -1;
2478  char* temp_cka_id = NULL; /* This will be set if we find a single matching key */
2479  int user_certain; /* Continue ? */
2480 
2481  /* Database connection details */
2482  DB_HANDLE dbhandle;
2483  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2484 
2485  char* datetime = DtParseDateTimeString("now");
2486 
2487  /* Check datetime in case it came back NULL */
2488  if (datetime == NULL) {
2489  printf("Couldn't turn \"now\" into a date, quitting...\n");
2490  StrFree(datetime);
2491  exit(1);
2492  }
2493 
2494  /* Warn and confirm that they realise this will retire the old key */
2495  printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] ");
2496 
2497  user_certain = getchar();
2498  if (user_certain != 'y' && user_certain != 'Y') {
2499  printf("Okay, quitting...\n");
2500  exit(0);
2501  }
2502 
2503  /* try to connect to the database */
2504  status = db_connect(&dbhandle, &lock_fd, 1);
2505  if (status != 0) {
2506  printf("Failed to connect to database\n");
2507  db_disconnect(lock_fd);
2508  StrFree(datetime);
2509  return(1);
2510  }
2511 
2512  /* Turn zone name into an id (if provided) */
2513  if (o_zone != NULL) {
2514  status = KsmZoneIdFromName(o_zone, &zone_id);
2515  if (status != 0) {
2516  /* Try again with td */
2517  StrAppend(&o_zone, ".");
2518  status = KsmZoneIdFromName(o_zone, &zone_id);
2519  if (status != 0) {
2520  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
2521  db_disconnect(lock_fd);
2522  StrFree(datetime);
2523  return(status);
2524  }
2525  }
2526  }
2527 
2528  /* Check the keytag is numeric */
2529  if (o_keytag != NULL) {
2530  if (StrIsDigits(o_keytag)) {
2531  status = StrStrtoi(o_keytag, &keytag_int);
2532  if (status != 0) {
2533  printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag);
2534  db_disconnect(lock_fd);
2535  StrFree(datetime);
2536  return(status);
2537  }
2538  } else {
2539  printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag);
2540  db_disconnect(lock_fd);
2541  StrFree(datetime);
2542  return(1);
2543  }
2544  }
2545 
2546  if (o_keytag == NULL && o_cka_id == NULL) {
2547  /* We will retire the oldest key if there are 2 or more active keys */
2548  if (o_zone == NULL) {
2549  printf("Please provide a zone or details of the key to roll\n");
2551  db_disconnect(lock_fd);
2552  StrFree(datetime);
2553  return(-1);
2554  }
2555 
2556  status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
2557  if (status != 0) {
2558  printf("Error: failed to count active keys\n");
2559  db_disconnect(lock_fd);
2560  StrFree(datetime);
2561  return status;
2562  }
2563 
2564  /* If there are not at least 2 active keys then quit */
2565  if (key_count < 2) {
2566  printf("Error: completing this action would leave no active keys on zone, quitting...\n");
2567  db_disconnect(lock_fd);
2568  StrFree(datetime);
2569  return -1;
2570  }
2571 
2572  /* We will need a policy id for the next bit */
2573  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
2574  if (status != 0) {
2575  printf("Error: failed to find policy for zone\n");
2576  db_disconnect(lock_fd);
2577  StrFree(datetime);
2578  return status;
2579  }
2580 
2581  status = RetireOldKey(zone_id, policy_id, datetime);
2582 
2583  if (status == 0) {
2584  printf("Old key retired\n");
2585  } else {
2586  printf("Old key NOT retired\n");
2587  }
2588  } else {
2589 
2590  /*
2591  * Get a count of keys that match our specifiers, will also print out
2592  * matching keys; note that zone_id may be overwritten
2593  */
2594  status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id);
2595  if (status != 0) {
2596  printf("Error: failed to count keys\n");
2597  db_disconnect(lock_fd);
2598  StrFree(datetime);
2599  return status;
2600  }
2601 
2602  /* If the keycount is more than 1 then display the cka_ids of the keys */
2603  if (key_count > 1) {
2604  printf("More than one key matched your parameters, please include more information from the above keys\n");
2605  db_disconnect(lock_fd);
2606  StrFree(datetime);
2607  return -1;
2608  }
2609 
2610  /* If the keycount is 0 or the key is not ACTIVE then write a message and exit */
2611  if (key_count == 0 || temp_key_state != KSM_STATE_ACTIVE) {
2612  printf("No keys in the ACTIVE state matched your parameters, please check the parameters\n");
2613  db_disconnect(lock_fd);
2614  StrFree(datetime);
2615  return -1;
2616  }
2617 
2618  status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
2619  if (status != 0) {
2620  printf("Error: failed to count active keys\n");
2621  db_disconnect(lock_fd);
2622  StrFree(datetime);
2623  return status;
2624  }
2625 
2626  /* If there are not at least 2 active keys then quit */
2627  if (key_count < 2) {
2628  printf("Error: completing this action would leave no active keys on zone, quitting...\n");
2629  db_disconnect(lock_fd);
2630  StrFree(datetime);
2631  return -1;
2632  }
2633 
2634  /* We will need a policy id for the next bit */
2635  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
2636  if (status != 0) {
2637  printf("Error: failed to find policy for zone\n");
2638  db_disconnect(lock_fd);
2639  StrFree(datetime);
2640  return status;
2641  }
2642 
2643  /* Retire the key */
2644  status = ChangeKeyState(KSM_TYPE_KSK, temp_cka_id, zone_id, policy_id, datetime, KSM_STATE_RETIRE);
2645 
2646  /* Let them know that it seemed to work */
2647  if (status == 0) {
2648  printf("Key %s retired\n", temp_cka_id);
2649  }
2650  }
2651 
2652  /* Release sqlite lock file (if we have it) */
2653  db_disconnect(lock_fd);
2654 
2655  DbDisconnect(dbhandle);
2656 
2657  StrFree(datetime);
2658 
2659  return status;
2660 }
2661 
2662 /*
2663  * DS Seen
2664  mark key as having had its DS published
2665  i.e. change its state to ACTIVE and set the time
2666  also set the time at which it will go to RETIRED
2667  */
2668  int
2670 {
2671  int status = 0;
2672  int zone_id = -1;
2673  int policy_id = -1;
2674  int key_count = -1;
2675  int retired_count = -1;
2676  int keytag_int = -1;
2677  int temp_key_state = -1;
2678  int temp_keypair_id = -1;
2679  char* temp_cka_id = NULL; /* This will be set if we find a single matching key */
2680  int user_certain; /* Continue ? */
2681 
2682  /* Database connection details */
2683  DB_HANDLE dbhandle;
2684  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2685 
2686  char logmsg[256]; /* For the message that we log when a key moves */
2687 
2688  char* datetime = DtParseDateTimeString("now");
2689 
2690  /* Check datetime in case it came back NULL */
2691  if (datetime == NULL) {
2692  printf("Couldn't turn \"now\" into a date, quitting...\n");
2693  StrFree(datetime);
2694  exit(1);
2695  }
2696 
2697  /* Check that we have either a keytag or a cka_id */
2698  if (o_keytag == NULL && o_cka_id == NULL) {
2699  printf("Please provide a keytag or a CKA_ID for the key (CKA_ID will be used if both are provided\n");
2700  usage_keydsseen();
2701  StrFree(datetime);
2702  return(-1);
2703  }
2704 
2705  /* Warn and confirm that they realise this will retire the old key */
2706  if (0) {
2707  printf("*WARNING* This will retire the currently active KSK; are you sure? [y/N] ");
2708 
2709  user_certain = getchar();
2710  if (user_certain != 'y' && user_certain != 'Y') {
2711  printf("Okay, quitting...\n");
2712  exit(0);
2713  }
2714  }
2715  /* try to connect to the database */
2716  status = db_connect(&dbhandle, &lock_fd, 1);
2717  if (status != 0) {
2718  printf("Failed to connect to database\n");
2719  db_disconnect(lock_fd);
2720  StrFree(datetime);
2721  return(1);
2722  }
2723 
2724  /* Turn zone name into an id (if provided) */
2725  /* TODO sort out all flag */
2726  /*if (o_zone == NULL && !all_flag) {
2727  printf("Please specify a zone or use the --all flag to indicate all zones using this key\n");*/
2728  if (o_zone == NULL) {
2729  printf("Please specify a zone using the --zone flag\n");
2730  usage_keydsseen();
2731  StrFree(datetime);
2732  db_disconnect(lock_fd);
2733  return(-1);
2734  }
2735  else if (o_zone != NULL) {
2736  status = KsmZoneIdFromName(o_zone, &zone_id);
2737  if (status != 0) {
2738  /* Try again with td */
2739  StrAppend(&o_zone, ".");
2740  status = KsmZoneIdFromName(o_zone, &zone_id);
2741  if (status != 0) {
2742  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
2743  db_disconnect(lock_fd);
2744  StrFree(datetime);
2745  return(status);
2746  }
2747  }
2748  }
2749  else if (all_flag) {
2750  printf("*WARNING* This will act on every zone where this key is in use; are you sure? [y/N] ");
2751 
2752  user_certain = getchar();
2753  if (user_certain != 'y' && user_certain != 'Y') {
2754  printf("Okay, quitting...\n");
2755  exit(0);
2756  }
2757 
2758  zone_id = -1;
2759  }
2760 
2761  /* Check the keytag is numeric */
2762  if (o_keytag != NULL) {
2763  if (StrIsDigits(o_keytag)) {
2764  status = StrStrtoi(o_keytag, &keytag_int);
2765  if (status != 0) {
2766  printf("Error: Unable to convert keytag \"%s\"; to an integer\n", o_keytag);
2767  db_disconnect(lock_fd);
2768  StrFree(datetime);
2769  return(status);
2770  }
2771  } else {
2772  printf("Error: keytag \"%s\"; should be numeric only\n", o_keytag);
2773  db_disconnect(lock_fd);
2774  StrFree(datetime);
2775  return(1);
2776  }
2777  }
2778 
2779  /*
2780  * Get a count of keys that match our specifiers, will also print out
2781  * matching keys; note that zone_id may be overwritten
2782  */
2783  status = CountKeys(&zone_id, keytag_int, o_cka_id, &key_count, &temp_cka_id, &temp_key_state, &temp_keypair_id);
2784  if (status != 0) {
2785  printf("Error: failed to count keys\n");
2786  db_disconnect(lock_fd);
2787  StrFree(datetime);
2788  return status;
2789  }
2790 
2791  /* If the keycount is more than 1 then display the cka_ids of the keys */
2792  if (key_count > 1) {
2793  printf("More than one key matched your parameters, please include more information from the above keys\n");
2794  db_disconnect(lock_fd);
2795  StrFree(datetime);
2796  return -1;
2797  }
2798 
2799  /* If the key is already active then write a message and exit */
2800  if (temp_key_state == KSM_STATE_ACTIVE) {
2801  printf("Key is already active\n");
2802  db_disconnect(lock_fd);
2803  StrFree(datetime);
2804  return -1;
2805  }
2806 
2807  /* If the keycount is 0 then write a message and exit */
2808  if (key_count == 0) {
2809  printf("No keys in the READY state matched your parameters, please check the parameters\n");
2810  db_disconnect(lock_fd);
2811  StrFree(datetime);
2812  return -1;
2813  }
2814 
2815  /* We will need a policy id for the next bit */
2816  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
2817  if (status != 0) {
2818  printf("Error: failed to find policy for zone\n");
2819  db_disconnect(lock_fd);
2820  StrFree(datetime);
2821  return status;
2822  }
2823 
2824  /* Do stuff */
2825  status = MarkDSSeen(temp_keypair_id, zone_id, policy_id, datetime, temp_key_state);
2826 
2827  /* Let them know that it seemed to work */
2828  if (status == 0) {
2829  snprintf(logmsg, 256, "Key %s made %s", temp_cka_id, (temp_key_state == KSM_STATE_READY) ? "active" : "into standby");
2830  printf("%s\n", logmsg);
2831 
2832  /* send the msg to syslog */
2833 #ifdef HAVE_OPENLOG_R
2834  openlog_r("ods-ksmutil", 0, DEFAULT_LOG_FACILITY, &sdata);
2835 #else
2836  openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY);
2837 #endif
2838 #ifdef HAVE_SYSLOG_R
2839  syslog_r(LOG_INFO, &sdata, "%s", logmsg);
2840 #else
2841  syslog(LOG_INFO, "%s", logmsg);
2842 #endif
2843 #ifdef HAVE_CLOSELOG_R
2844  closelog_r(&sdata);
2845 #else
2846  closelog();
2847 #endif
2848 
2849  }
2850 
2851  /* Retire old key, unless asked not to */
2852  if (temp_key_state == KSM_STATE_READY) {
2853  if (retire_flag == 1) {
2854 
2855  /* We will retire the oldest key if there are 2 or more active keys */
2856  status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_ACTIVE, &key_count, zone_id);
2857  if (status != 0) {
2858  printf("Error: failed to count active keys\n");
2859  db_disconnect(lock_fd);
2860  StrFree(datetime);
2861  return status;
2862  }
2863 
2864  /* If there are not at least 2 active keys then quit */
2865  if (key_count < 2) {
2866  /* Count retired keys to work out if this is a new zone */
2867  /* TODO MAKE SURE THIS IS RIGHT !!! */
2868  status = CountKeysInState(KSM_TYPE_KSK, KSM_STATE_RETIRE, &retired_count, zone_id);
2869  if (status != 0) {
2870  printf("Error: failed to count retired keys\n");
2871  db_disconnect(lock_fd);
2872  StrFree(datetime);
2873  return status;
2874  }
2875 
2876  /* Cleanup and print an error message... */
2877  db_disconnect(lock_fd);
2878  StrFree(datetime);
2879  if (retired_count != 0) {
2880  printf("Error: retiring a key would leave no active keys on zone, skipping...\n");
2881  return -1;
2882  } else {
2883  /* ...Unless this looks like a new zone, in which case poke
2884  the enforcerd */
2885  if (restart_enforcerd() != 0)
2886  {
2887  fprintf(stderr, "Could not HUP ods-enforcerd\n");
2888  }
2889  return 0;
2890  }
2891  }
2892 
2893  status = RetireOldKey(zone_id, policy_id, datetime);
2894 
2895  /* Let them know that it seemed to work */
2896  if (status == 0) {
2897  printf("Old key retired\n");
2898  } else {
2899  printf("Old key NOT retired\n");
2900  }
2901  } else {
2902  printf("Old key NOT retired\n");
2903  }
2904  }
2905 
2906  /* Need to poke the enforcer to wake it up */
2907  if (restart_enforcerd() != 0)
2908  {
2909  fprintf(stderr, "Could not HUP ods-enforcerd\n");
2910  }
2911 
2912  /* Release sqlite lock file (if we have it) */
2913  db_disconnect(lock_fd);
2914 
2915  DbDisconnect(dbhandle);
2916 
2917  StrFree(datetime);
2918 
2919  return status;
2920 }
2921 
2922 /*
2923  * import a key into the ksm and set its values as specified
2924  */
2925  int
2927 {
2928  int status = 0;
2929 
2930  /* some strings to hold upper case versions of arguments */
2931  char* case_keytype = NULL; /* KSK or ZSK */
2932  char* case_algorithm = NULL; /* RSASHA1 or RSASHA1-NSEC3-SHA1 (5 or 7) */
2933  char* case_state = NULL; /* GENERATE, PUBLISH, READY, ACTIVE or RETIRE */
2934 
2935  int repo_id = -1;
2936  int zone_id = -1;
2937  int policy_id = -1;
2938  int cka_id_exists = -1; /* do we already have this id in the HSM */
2939  int keytype_id = -1;
2940  int size_int = -1;
2941  int algo_id = -1;
2942  int state_id = -1;
2943  char form_time[KSM_TIME_LENGTH]; /* YYYY-MM-DD HH:MM:SS + NULL Time after we reformat it */
2944  char form_opt_time[KSM_TIME_LENGTH]; /* Opt_time after we reformat it */
2945 
2946  DB_ID keypair_id = 0; /* This will be set when we enter the keypair */
2947  DB_ID ignore = 0; /* This will be set when we enter the dnsseckey */
2948 
2949  struct tm datetime; /* Used for getting the date/time */
2950 
2951  int fix_time = 0; /* Will we be setting the retire time? */
2952 
2953  /* Database connection details */
2954  DB_HANDLE dbhandle;
2955  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
2956 
2957  DB_RESULT result; /* Result of parameter query */
2958  KSM_PARAMETER data; /* Parameter information */
2959 
2960  int user_certain; /* Continue ? */
2961 
2962  /* Chech that we got all arguments. */
2963 
2964  if (o_cka_id == NULL) {
2965  printf("Error: please specify a CKA_ID with the --cka_id <CKA_ID>\n");
2966  return(1);
2967  }
2968  if (o_repository == NULL) {
2969  printf("Error: please specify a repository with the --repository <repository>\n");
2970  return(1);
2971  }
2972  if (o_zone == NULL) {
2973  printf("Error: please specify a zone with the --zone <zone>\n");
2974  return(1);
2975  }
2976  if (o_size == NULL) {
2977  printf("Error: please specify the number of bits with the --bits <size>\n");
2978  return(1);
2979  }
2980  if (o_algo == NULL) {
2981  printf("Error: please specify the algorithm with the --algorithm <algorithm>\n");
2982  return(1);
2983  }
2984  if (o_keystate == NULL) {
2985  printf("Error: please specify the state with the --keystate <state>\n");
2986  return(1);
2987  }
2988  if (o_keytype == NULL) {
2989  printf("Error: please specify a keytype, KSK or ZSK, with the --keytype <type>\n");
2990  return(1);
2991  }
2992  if (o_time == NULL) {
2993  printf("Error: please specify the time of when the key entered the given state with the --time <time>\n");
2994  return(1);
2995  }
2996 
2997  /* try to connect to the database */
2998  status = db_connect(&dbhandle, &lock_fd, 1);
2999  if (status != 0) {
3000  printf("Failed to connect to database\n");
3001  db_disconnect(lock_fd);
3002  return(1);
3003  }
3004 
3005  /* check that the repository exists */
3006  status = KsmSmIdFromName(o_repository, &repo_id);
3007  if (status != 0) {
3008  printf("Error: unable to find a repository named \"%s\" in database\n", o_repository);
3009  db_disconnect(lock_fd);
3010  return status;
3011  }
3012 
3013  /* check that the zone name is valid and use it to get some ids */
3014  status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
3015  if (status != 0) {
3016  /* Try again with td */
3017  StrAppend(&o_zone, ".");
3018  status = KsmZoneIdAndPolicyFromName(o_zone, &policy_id, &zone_id);
3019  if (status != 0) {
3020  printf("Error: unable to find a zone named \"%s\" in database\n", o_zone);
3021  db_disconnect(lock_fd);
3022  return(status);
3023  }
3024  }
3025 
3026  /* Check that the cka_id does not exist (in the specified HSM) */
3027  status = (KsmCheckHSMkeyID(repo_id, o_cka_id, &cka_id_exists));
3028  if (status != 0) {
3029  db_disconnect(lock_fd);
3030  return(status);
3031  }
3032  if (cka_id_exists == 1) {
3033  printf("Error: key with CKA_ID \"%s\" already exists in database\n", o_cka_id);
3034  db_disconnect(lock_fd);
3035  return(1);
3036  }
3037 
3038  /* Check the Keytype */
3039  case_keytype = StrStrdup(o_keytype);
3040  (void) StrToUpper(case_keytype);
3041  if (strncmp(case_keytype, "KSK", 3) == 0 || strncmp(o_keytype, "257", 3) == 0) {
3042  keytype_id = 257;
3043  }
3044  else if (strncmp(case_keytype, "ZSK", 3) == 0 || strncmp(o_keytype, "256", 3) == 0) {
3045  keytype_id = 256;
3046  }
3047  else {
3048  printf("Error: Unrecognised keytype %s; should be one of KSK or ZSK\n", o_keytype);
3049 
3050  db_disconnect(lock_fd);
3051  StrFree(case_keytype);
3052  return(1);
3053  }
3054  StrFree(case_keytype);
3055 
3056  /* Check the size is numeric */
3057  if (StrIsDigits(o_size)) {
3058  status = StrStrtoi(o_size, &size_int);
3059  if (status != 0) {
3060  printf("Error: Unable to convert bits \"%s\"; to an integer\n", o_size);
3061  db_disconnect(lock_fd);
3062  return(status);
3063  }
3064  } else {
3065  printf("Error: Bits \"%s\"; should be numeric only\n", o_size);
3066  db_disconnect(lock_fd);
3067  return(1);
3068  }
3069 
3070  /* Check the algorithm */
3071  if (StrIsDigits(o_algo)) {
3072  /* Accept it as-is; The HSM will tell us if the number is not valid */
3073  status = StrStrtoi(o_algo, &algo_id);
3074  } else {
3075  /* Convert name to an id, we get 0 if it is unrecognised */
3076  case_algorithm = StrStrdup(o_algo);
3077  (void) StrToLower(case_algorithm);
3078 
3079  algo_id = KsmKeywordAlgorithmNameToValue(case_algorithm);
3080  StrFree(case_algorithm);
3081  }
3082 
3083  if (status != 0 || algo_id == 0 || hsm_supported_algorithm(algo_id) != 0) {
3084  printf("Error: Key algorithm %s not supported; try one of RSASHA1, RSASHA1-NSEC3-SHA1 or RSASHA256\n", o_algo);
3085  db_disconnect(lock_fd);
3086  return(status);
3087  }
3088 
3089  /* Check the state */
3090  case_state = StrStrdup(o_keystate);
3091  (void) StrToUpper(case_state);
3092  if (strncmp(case_state, "GENERATE", 8) == 0 || strncmp(o_keystate, "1", 1) == 0) {
3093  state_id = 1;
3094  }
3095  else if (strncmp(case_state, "PUBLISH", 7) == 0 || strncmp(o_keystate, "2", 1) == 0) {
3096  state_id = 2;
3097  }
3098  else if (strncmp(case_state, "READY", 5) == 0 || strncmp(o_keystate, "3", 1) == 0) {
3099  state_id = 3;
3100  }
3101  else if (strncmp(case_state, "ACTIVE", 6) == 0 || strncmp(o_keystate, "4", 1) == 0) {
3102  state_id = 4;
3103  }
3104  else if (strncmp(case_state, "RETIRE", 6) == 0 || strncmp(o_keystate, "5", 1) == 0) {
3105  state_id = 5;
3106  }
3107  else {
3108  printf("Error: Unrecognised state %s; should be one of GENERATE, PUBLISH, READY, ACTIVE or RETIRE\n", o_keystate);
3109 
3110  db_disconnect(lock_fd);
3111  StrFree(case_state);
3112  return(1);
3113  }
3114  StrFree(case_state);
3115 
3116  /* Check, and convert, the time(s) */
3117  status = DtGeneral(o_time, &datetime);
3118  if (status != 0) {
3119  printf("Error: unable to convert \"%s\" into a date\n", o_time);
3120  date_help();
3121 
3122  db_disconnect(lock_fd);
3123  return(status);
3124  }
3125  else {
3126  snprintf(form_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
3127  datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday,
3128  datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
3129  }
3130 
3131  if (o_retire != NULL) {
3132  /* can only specify a retire time if the key is being inserted in the active state */
3133  if (state_id != KSM_STATE_ACTIVE) {
3134  printf("Error: unable to specify retire time for a key in state \"%s\"\n", o_keystate);
3135  db_disconnect(lock_fd);
3136  return(status);
3137  }
3138 
3139  status = DtGeneral(o_retire, &datetime);
3140  if (status != 0) {
3141  printf("Error: unable to convert retire time \"%s\" into a date\n", o_retire);
3142  date_help();
3143 
3144  db_disconnect(lock_fd);
3145  return(status);
3146  }
3147  else {
3148  snprintf(form_opt_time, KSM_TIME_LENGTH, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
3149  datetime.tm_year + 1900, datetime.tm_mon + 1, datetime.tm_mday,
3150  datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
3151  fix_time = 1;
3152  }
3153  } else {
3154  form_opt_time[0] = '\0';
3155  }
3156 
3157  /* Find out if this zone has any others on a "shared keys" policy and warn */
3158  status = KsmParameterInit(&result, "zones_share_keys", "keys", policy_id);
3159  if (status != 0) {
3160  db_disconnect(lock_fd);
3161  return(status);
3162  }
3163  status = KsmParameter(result, &data);
3164  if (status != 0) {
3165  db_disconnect(lock_fd);
3166  return(status);
3167  }
3168  KsmParameterEnd(result);
3169 
3170  /* Warn and confirm if this will roll more than one zone */
3171  if (data.value == 1) {
3172  printf("*WARNING* This zone shares keys with others, the key will be added to all; are you sure? [y/N] ");
3173 
3174  user_certain = getchar();
3175  if (user_certain != 'y' && user_certain != 'Y') {
3176  printf("Okay, quitting...\n");
3177  db_disconnect(lock_fd);
3178  exit(0);
3179  }
3180  }
3181 
3182  /* create basic keypair */
3183  status = KsmImportKeyPair(policy_id, o_cka_id, repo_id, size_int, algo_id, state_id, form_time, fix_time, &keypair_id);
3184  if (status != 0) {
3185  printf("Error: couldn't import key\n");
3186  db_disconnect(lock_fd);
3187  return(status);
3188  }
3189 
3190  /* allocate key to zone(s) */
3191  /* TODO might not need this any more */
3192 /* if (data.value == 1) {
3193  status = KsmDnssecKeyCreateOnPolicy(policy_id, (int) keypair_id, keytype_id);
3194  } else {*/
3195  status = KsmDnssecKeyCreate(zone_id, (int) keypair_id, keytype_id, state_id, form_time, form_opt_time, &ignore);
3196 
3197  if (status != 0) {
3198  printf("Error: couldn't allocate key to zone(s)\n");
3199  db_disconnect(lock_fd);
3200  return(status);
3201  }
3202 
3203  printf("Key imported into zone(s)\n");
3204 
3205  /* Release sqlite lock file (if we have it) */
3206  db_disconnect(lock_fd);
3207 
3208  DbDisconnect(dbhandle);
3209  return 0;
3210 }
3211 
3212 /*
3213  * make a backup of a sqlite database
3214  */
3215  int
3217 {
3218  /* Database details */
3219  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
3220 
3221  /* what we will read from the file */
3222  char *dbschema = NULL;
3223  char *host = NULL;
3224  char *port = NULL;
3225  char *user = NULL;
3226  char *password = NULL;
3227 
3228  int status;
3229 
3230  char* backup_filename = NULL;
3231  char* lock_filename;
3232 
3233  char *path = getenv("PWD");
3234 
3235  if (DbFlavour() != SQLITE_DB) {
3236  printf("Sorry, currently this utility can only backup a sqlite database file\n");
3237  return -1;
3238  }
3239 
3240  /* Read the database details out of conf.xml */
3241  status = get_db_details(&dbschema, &host, &port, &user, &password);
3242  if (status != 0) {
3243  StrFree(host);
3244  StrFree(port);
3245  StrFree(dbschema);
3246  StrFree(user);
3247  StrFree(password);
3248  return(status);
3249  }
3250 
3251  /* set up DB lock */
3252  lock_filename = NULL;
3253  StrAppend(&lock_filename, dbschema);
3254  StrAppend(&lock_filename, ".our_lock");
3255 
3256  lock_fd = fopen(lock_filename, "w");
3257  status = get_lite_lock(lock_filename, lock_fd);
3258  if (status != 0) {
3259  printf("Error getting db lock\n");
3260  if (lock_fd != NULL) {
3261  fclose(lock_fd);
3262  }
3263  StrFree(host);
3264  StrFree(port);
3265  StrFree(dbschema);
3266  StrFree(user);
3267  StrFree(password);
3268  return(1);
3269  }
3270  StrFree(lock_filename);
3271 
3272  /* Work out what file to output */
3273  if (o_output == NULL) {
3274  StrAppend(&backup_filename, dbschema);
3275  StrAppend(&backup_filename, ".backup");
3276  } else if (*o_output != '/') {
3277  StrAppend(&backup_filename, path);
3278  StrAppend(&backup_filename, "/");
3279  StrAppend(&backup_filename, o_output);
3280  } else {
3281  StrAppend(&backup_filename, o_output);
3282  }
3283 
3284  status = backup_file(dbschema, backup_filename);
3285 
3286  StrFree(backup_filename);
3287 
3288  /* Cleanup */
3289  StrFree(host);
3290  StrFree(port);
3291  StrFree(dbschema);
3292  StrFree(user);
3293  StrFree(password);
3294 
3295  /* Release sqlite lock */
3296  db_disconnect(lock_fd);
3297 
3298  return status;
3299 }
3300 
3301 /*
3302  * Delete any policies with no zones
3303  */
3304  int
3306 {
3307  int status = 0;
3308 
3309  char* kasp_filename = NULL;
3310  char* zonelist_filename = NULL;
3311  char* backup_filename = NULL;
3312 
3313  DB_HANDLE dbhandle;
3314  FILE* lock_fd = NULL;
3315  KSM_POLICY *policy;
3316  DB_RESULT result; /* Result set from policy query */
3317  DB_RESULT result2; /* Result set from zone count query */
3318  char sql[KSM_SQL_SIZE];
3319  int size = -1;
3320  char* sql2;
3321 
3322  FILE *test;
3323  int zone_count = -1;
3324 
3325  xmlDocPtr doc = NULL;
3326 
3327  int user_certain;
3328  printf("*WARNING* This feature is experimental and has not been fully tested; are you sure? [y/N] ");
3329 
3330  user_certain = getchar();
3331  if (user_certain != 'y' && user_certain != 'Y') {
3332  printf("Okay, quitting...\n");
3333  exit(0);
3334  }
3335 
3336  /* Read the conf.xml file to learn the location of the kasp.xml file. */
3337  status = read_filenames(&zonelist_filename, &kasp_filename);
3338  if (status != 0) {
3339  printf("Failed to read conf.xml\n");
3340  db_disconnect(lock_fd);
3341  return(1);
3342  }
3343 
3344  /* Backup the current kasp.xml */
3345  StrAppend(&backup_filename, kasp_filename);
3346  StrAppend(&backup_filename, ".backup");
3347  status = backup_file(kasp_filename, backup_filename);
3348  StrFree(backup_filename);
3349  if (status != 0) {
3350  StrFree(kasp_filename);
3351  db_disconnect(lock_fd);
3352  return(status);
3353  }
3354 
3355  /* Check that we will be able to make the changes to kasp.xml */
3356  if ((test = fopen(kasp_filename, "ab"))==NULL) {
3357  printf("Cannot open kasp.xml for writing: %s\n", strerror(errno));
3358  return(-1);
3359  } else {
3360  fclose(test);
3361  }
3362 
3363  /* try to connect to the database */
3364  status = db_connect(&dbhandle, &lock_fd, 1);
3365  if (status != 0) {
3366  printf("Failed to connect to database\n");
3367  db_disconnect(lock_fd);
3368  return(1);
3369  }
3370 
3371  /* Start a transaction */
3372  status = DbBeginTransaction();
3373  if (status != 0) {
3374  /* Something went wrong */
3375 
3377  db_disconnect(lock_fd);
3378  return status;
3379  }
3380 
3381  /* Loop through each policy */
3382  policy = KsmPolicyAlloc();
3383  if (policy == NULL) {
3384  printf("Malloc for policy struct failed\n");
3385  exit(1);
3386  }
3387 
3388  /* Read all policies */
3389  status = KsmPolicyInit(&result, NULL);
3390  if (status == 0) {
3391  /* get the first policy */
3392  status = KsmPolicy(result, policy);
3393  while (status == 0) {
3394  /* Count zones on this policy */
3395  status = KsmZoneCountInit(&result2, policy->id);
3396  if (status == 0) {
3397  status = KsmZoneCount(result2, &zone_count);
3398  }
3399  DbFreeResult(result2);
3400 
3401  if (status == 0) {
3402  /* Only carry on if we have no zones */
3403  if (zone_count == 0) {
3404  printf("No zones on policy %s; purging...\n", policy->name);
3405  /* set keystate to 6 across the board */
3406  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);
3407 
3408  /* Quick check that we didn't run out of space */
3409  if (size < 0 || size >= KSM_SQL_SIZE) {
3410  printf("Couldn't construct SQL to kill orphaned keys\n");
3411  db_disconnect(lock_fd);
3412  KsmPolicyFree(policy);
3413  return -1;
3414  }
3415 
3416  status = DbExecuteSqlNoResult(DbHandle(), sql);
3417 
3418  /* Report any errors */
3419  if (status != 0) {
3420  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
3421  db_disconnect(lock_fd);
3422  KsmPolicyFree(policy);
3423  return status;
3424  }
3425 
3426  /* call purge keys on that policy (all zones) */
3427  status = PurgeKeys(-1, policy->id);
3428  if (status != 0) {
3429  printf("Key purge failed for policy %s\n", policy->name);
3430  db_disconnect(lock_fd);
3431  KsmPolicyFree(policy);
3432  return status;
3433  }
3434 
3435  /* Delete the policy from DB */
3436  sql2 = DdsInit("parameters_policies");
3437  DdsConditionInt(&sql2, "policy_id", DQS_COMPARE_EQ, policy->id, 0);
3438  DdsEnd(&sql2);
3439  status = DbExecuteSqlNoResult(DbHandle(), sql2);
3440  DdsFree(sql2);
3441 
3442  if (status != 0)
3443  {
3444  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
3445  db_disconnect(lock_fd);
3446  KsmPolicyFree(policy);
3447  return status;
3448  }
3449 
3450  sql2 = DdsInit("policies");
3451  DdsConditionInt(&sql2, "id", DQS_COMPARE_EQ, policy->id, 0);
3452  DdsEnd(&sql2);
3453  status = DbExecuteSqlNoResult(DbHandle(), sql2);
3454  DdsFree(sql2);
3455 
3456  if (status != 0)
3457  {
3458  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
3459  db_disconnect(lock_fd);
3460  KsmPolicyFree(policy);
3461  return status;
3462  }
3463 
3464  /* Delete the policy from the XML */
3465  /* Read the file and delete our policy node(s) in memory */
3466  doc = del_policy_node(kasp_filename, policy->name);
3467  if (doc == NULL) {
3468  db_disconnect(lock_fd);
3469  KsmPolicyFree(policy);
3470  StrFree(kasp_filename);
3471  return(1);
3472  }
3473 
3474  /* Save our new file over the old, TODO should we validate it first? */
3475  status = xmlSaveFormatFile(kasp_filename, doc, 1);
3476  xmlFreeDoc(doc);
3477  if (status == -1) {
3478  printf("Could not save %s\n", kasp_filename);
3479  StrFree(kasp_filename);
3480  db_disconnect(lock_fd);
3481  KsmPolicyFree(policy);
3482  return(1);
3483  }
3484 
3485  }
3486  } else {
3487  printf("Couldn't count zones on policy; quitting...\n");
3488  db_disconnect(lock_fd);
3489  exit(1);
3490  }
3491 
3492  /* get next policy */
3493  status = KsmPolicy(result, policy);
3494  }
3495  /* Reset EOF */
3496  if (status == -1) {
3497  status = 0;
3498  }
3499  DbFreeResult(result);
3500  }
3501 
3502  /* Commit or Rollback */
3503  if (status == 0) {
3504  /* Everything worked by the looks of it */
3505  DbCommit();
3506  } else {
3507  /* Whatever happened, it was not good */
3508  DbRollback();
3509  }
3510 
3511  StrFree(kasp_filename);
3512  db_disconnect(lock_fd);
3513  KsmPolicyFree(policy);
3514  return status;
3515 }
3516 
3517 /*
3518  * Send command to ods-control
3519  */
3520  int
3521 cmd_control(char *command)
3522 {
3523  int status = 0;
3524  char* ods_control_cmd = NULL;
3525  char* ptr = command;
3526 
3527  /* We need the command in lower case */
3528  if (ptr) {
3529  while (*ptr) {
3530  *ptr = tolower((int) *ptr);
3531  ++ptr;
3532  }
3533  }
3534 
3535  /* Call "ods-control enforcer COMMAND" */
3536  StrAppend(&ods_control_cmd, ODS_EN_CONTROL);
3537  StrAppend(&ods_control_cmd, command);
3538 
3539  status = system(ods_control_cmd);
3540  if (status != 0)
3541  {
3542  fprintf(stderr, "Couldn't run %s\n", ods_control_cmd);
3543  }
3544 
3545  StrFree(ods_control_cmd);
3546 
3547  return(status);
3548 }
3549 
3550 /*
3551  * Fairly basic main, just pass most things through to their handlers
3552  */
3553  int
3554 main (int argc, char *argv[])
3555 {
3556  int result;
3557  int ch;
3558  char* case_command = NULL;
3559  char* case_verb = NULL;
3560 
3561  int option_index = 0;
3562  static struct option long_options[] =
3563  {
3564  {"all", no_argument, 0, 'a'},
3565  {"bits", required_argument, 0, 'b'},
3566  {"config", required_argument, 0, 'c'},
3567  {"ds", no_argument, 0, 'd'},
3568  {"keystate", required_argument, 0, 'e'},
3569  {"no-retire", no_argument, 0, 'f'},
3570  {"algorithm", required_argument, 0, 'g'},
3571  {"help", no_argument, 0, 'h'},
3572  {"input", required_argument, 0, 'i'},
3573  {"cka_id", required_argument, 0, 'k'},
3574  {"no-xml", no_argument, 0, 'm'},
3575  {"interval", required_argument, 0, 'n'},
3576  {"output", required_argument, 0, 'o'},
3577  {"policy", required_argument, 0, 'p'},
3578  {"repository", required_argument, 0, 'r'},
3579  {"signerconf", required_argument, 0, 's'},
3580  {"keytype", required_argument, 0, 't'},
3581  {"time", required_argument, 0, 'w'},
3582  {"verbose", no_argument, 0, 'v'},
3583  {"version", no_argument, 0, 'V'},
3584  {"keytag", required_argument, 0, 'x'},
3585  {"retire", required_argument, 0, 'y'},
3586  {"zone", required_argument, 0, 'z'},
3587  {"zonetotal", required_argument, 0, 'Z'},
3588  {0,0,0,0}
3589  };
3590 
3591  progname = argv[0];
3592 
3593  while ((ch = getopt_long(argc, argv, "ab:c:de:fg:hi:k:n:o:p:r:s:t:vVw:x:y:z:Z", long_options, &option_index)) != -1) {
3594  switch (ch) {
3595  case 'a':
3596  all_flag = 1;
3597  break;
3598  case 'b':
3599  o_size = StrStrdup(optarg);
3600  break;
3601  case 'c':
3602  config = StrStrdup(optarg);
3603  break;
3604  case 'd':
3605  ds_flag = 1;
3606  break;
3607  case 'e':
3609  break;
3610  case 'f':
3611  retire_flag = 0;
3612  break;
3613  case 'g':
3614  o_algo = StrStrdup(optarg);
3615  break;
3616  case 'h':
3617  usage();
3618  states_help();
3619  types_help();
3620  date_help();
3621  exit(0);
3622  break;
3623  case 'i':
3625  break;
3626  case 'k':
3628  break;
3629  case 'm':
3630  xml_flag = 0;
3631  break;
3632  case 'n':
3634  break;
3635  case 'o':
3637  break;
3638  case 'p':
3640  break;
3641  case 'r':
3643  break;
3644  case 's':
3646  break;
3647  case 't':
3649  break;
3650  case 'V':
3651  printf("%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
3652  exit(0);
3653  break;
3654  case 'v':
3655  verbose_flag = 1;
3656  break;
3657  case 'w':
3658  o_time = StrStrdup(optarg);
3659  break;
3660  case 'x':
3662  break;
3663  case 'y':
3665  break;
3666  case 'z':
3667  /* Remove trailing dot here */
3668  o_zone = StrStrdup(optarg);
3669  if (strlen(o_zone) > 1 && o_zone[strlen(o_zone)-1] == '.') {
3670  o_zone[strlen(o_zone)-1] = '\0';
3671  td_flag = 1;
3672  }
3673 
3674  break;
3675  case 'Z':
3677  break;
3678  default:
3679  usage();
3680  exit(1);
3681  }
3682  }
3683  argc -= optind;
3684  argv += optind;
3685 
3686  if (!argc) {
3687  usage();
3688  exit(1);
3689  }
3690 
3691 
3692  /*(void) KsmInit();*/
3693  MsgInit();
3696 
3697  /* command should be one of SETUP UPDATE ZONE REPOSITORY POLICY KEY BACKUP or ROLLOVER */
3698  case_command = StrStrdup(argv[0]);
3699  (void) StrToUpper(case_command);
3700  if (argc > 1) {
3701  /* verb should be stuff like ADD, LIST, DELETE, etc */
3702  case_verb = StrStrdup(argv[1]);
3703  (void) StrToUpper(case_verb);
3704  } else {
3705  case_verb = StrStrdup("NULL");
3706  }
3707 
3708 
3709  if (!strncmp(case_command, "SETUP", 5)) {
3710  argc --;
3711  argv ++;
3712  result = cmd_setup();
3713  } else if (!strncmp(case_command, "UPDATE", 6)) {
3714  argc --;
3715  argv ++;
3716  result = cmd_update(case_verb);
3717  } else if (!strncmp(case_command, "START", 5) ||
3718  !strncmp(case_command, "STOP", 4) ||
3719  !strncmp(case_command, "NOTIFY", 6)) {
3720  argc --;
3721  argv ++;
3722  result = cmd_control(case_command);
3723  } else if (!strncmp(case_command, "ZONE", 4) && strlen(case_command) == 4) {
3724  argc --; argc --;
3725  argv ++; argv ++;
3726 
3727  /* verb should be add, delete or list */
3728  if (!strncmp(case_verb, "ADD", 3)) {
3729  result = cmd_addzone();
3730  } else if (!strncmp(case_verb, "DELETE", 6)) {
3731  result = cmd_delzone();
3732  } else if (!strncmp(case_verb, "LIST", 4)) {
3733  result = cmd_listzone();
3734  } else {
3735  printf("Unknown command: zone %s\n", case_verb);
3736  usage_zone();
3737  result = -1;
3738  }
3739  } else if (!strncmp(case_command, "REPOSITORY", 10)) {
3740  argc --; argc --;
3741  argv ++; argv ++;
3742  /* verb should be list */
3743  if (!strncmp(case_verb, "LIST", 4)) {
3744  result = cmd_listrepo();
3745  } else {
3746  printf("Unknown command: repository %s\n", case_verb);
3747  usage_repo();
3748  result = -1;
3749  }
3750  } else if (!strncmp(case_command, "POLICY", 6)) {
3751  argc --; argc --;
3752  argv ++; argv ++;
3753  /* verb should be export, import, list or purge */
3754  if (!strncmp(case_verb, "EXPORT", 6)) {
3755  result = cmd_exportpolicy();
3756  } else if (!strncmp(case_verb, "IMPORT", 6)) {
3757  result = cmd_update("KASP");
3758  } else if (!strncmp(case_verb, "LIST", 4)) {
3759  result = cmd_listpolicy();
3760  } else if (!strncmp(case_verb, "PURGE", 5)) {
3761  result = cmd_purgepolicy();
3762  } else {
3763  printf("Unknown command: policy %s\n", case_verb);
3764  usage_policy();
3765  result = -1;
3766  }
3767  } else if (!strncmp(case_command, "KEY", 3)) {
3768  argc --; argc --;
3769  argv ++; argv ++;
3770  /* verb should be list, export import, rollover, purge, generate, ksk-retire or ds-seen */
3771  if (!strncmp(case_verb, "LIST", 4)) {
3772  result = cmd_listkeys();
3773  }
3774  else if (!strncmp(case_verb, "EXPORT", 6)) {
3775  result = cmd_exportkeys();
3776  }
3777  else if (!strncmp(case_verb, "IMPORT", 6)) {
3778  result = cmd_import();
3779  }
3780  else if (!strncmp(case_verb, "ROLLOVER", 8)) {
3781  /* Check that we have either a key type or the all flag */
3782  if (all_flag == 0 && o_keytype == NULL) {
3783  printf("Please specify either a keytype, KSK or ZSK, with the --keytype <type> option or use the --all option\n");
3784  usage_keyroll();
3785  result = -1;
3786  }
3787  else {
3788  /* Are we rolling a zone or a whole policy? */
3789  if (o_zone != NULL && o_policy == NULL) {
3790  result = cmd_rollzone();
3791  }
3792  else if (o_zone == NULL && o_policy != NULL) {
3793  result = cmd_rollpolicy();
3794  }
3795  else {
3796  printf("Please provide either a zone OR a policy to rollover\n");
3797  usage_keyroll();
3798  result = -1;
3799  }
3800  }
3801  }
3802  else if (!strncmp(case_verb, "PURGE", 5)) {
3803  if ((o_zone != NULL && o_policy == NULL) ||
3804  (o_zone == NULL && o_policy != NULL)){
3805  result = cmd_keypurge();
3806  }
3807  else {
3808  printf("Please provide either a zone OR a policy to key purge\n");
3809  usage_keypurge();
3810  result = -1;
3811  }
3812  }
3813  else if (!strncmp(case_verb, "GENERATE", 8)) {
3814  result = cmd_genkeys();
3815  }
3816  else if (!strncmp(case_verb, "KSK-RETIRE", 10)) {
3817  result = cmd_kskretire();
3818  }
3819  else if (!strncmp(case_verb, "DS-SEEN", 7)) {
3820  result = cmd_dsseen();
3821  } else {
3822  printf("Unknown command: key %s\n", case_verb);
3823  usage_key();
3824  result = -1;
3825  }
3826  } else if (!strncmp(case_command, "BACKUP", 6)) {
3827  argc --; argc --;
3828  argv ++; argv ++;
3829  /* verb should be done, prepare, commit, rollback or list */
3830  if (!strncmp(case_verb, "DONE", 4) ||
3831  !strncmp(case_verb, "PREPARE", 7) ||
3832  !strncmp(case_verb, "COMMIT", 6) ||
3833  !strncmp(case_verb, "ROLLBACK", 8)) {
3834  result = cmd_backup(case_verb);
3835  }
3836  else if (!strncmp(case_verb, "LIST", 4)) {
3837  result = cmd_listbackups();
3838  } else {
3839  printf("Unknown command: backup %s\n", case_verb);
3840  usage_backup();
3841  result = -1;
3842  }
3843  } else if (!strncmp(case_command, "ROLLOVER", 8)) {
3844  argc --; argc --;
3845  argv ++; argv ++;
3846  if (!strncmp(case_verb, "LIST", 4)) {
3847  result = cmd_listrolls();
3848  } else {
3849  printf("Unknown command: rollover %s\n", case_verb);
3850  usage_rollover();
3851  result = -1;
3852  }
3853  } else if (!strncmp(case_command, "DATABASE", 8)) {
3854  argc --; argc --;
3855  argv ++; argv ++;
3856  /* verb should be backup */
3857  if (!strncmp(case_verb, "BACKUP", 6)) {
3858  result = cmd_dbbackup();
3859  } else {
3860  printf("Unknown command: database %s\n", case_verb);
3861  usage_database();
3862  result = -1;
3863  }
3864  } else if (!strncmp(case_command, "ZONELIST", 8)) {
3865  argc --; argc --;
3866  argv ++; argv ++;
3867  /* verb should be import or export */
3868  if (!strncmp(case_verb, "EXPORT", 6)) {
3869  result = cmd_exportzonelist();
3870  }
3871  else if (!strncmp(case_verb, "IMPORT", 6)) {
3872  result = cmd_update("ZONELIST");
3873  } else {
3874  printf("Unknown command: zonelist %s\n", case_verb);
3875  usage_zonelist2();
3876  result = -1;
3877  }
3878  } else {
3879  printf("Unknown command: %s\n", argv[0]);
3880  usage();
3881  result = -1;
3882  }
3883 
3884  StrFree(case_command);
3885  StrFree(case_verb);
3886 
3887  /*(void) hsm_close();*/
3888  /*if (config) free(config);*/
3889 
3890  xmlCleanupParser();
3891  xmlCleanupGlobals();
3892  xmlCleanupThreads();
3893 
3894  exit(result);
3895 }
3896 
3897 
3898 /*
3899  * Given a conf.xml location connect to the database contained within it
3900  *
3901  * A lock will be taken out on the DB if it is SQLite; so it is important to release it
3902  * in the calling Fn when we are done with it.
3903  * If backup is set to 1 then a backup will be made (of a sqlite DB file)
3904  *
3905  * Returns 0 if a connection was made.
3906  * 1 if a connection could not be made.
3907  * -1 if any of the config files could not be read/parsed
3908  *
3909  */
3910  int
3911 db_connect(DB_HANDLE *dbhandle, FILE** lock_fd, int backup)
3912 {
3913  /* what we will read from the file */
3914  char *dbschema = NULL;
3915  char *host = NULL;
3916  char *port = NULL;
3917  char *user = NULL;
3918  char *password = NULL;
3919 
3920  int status;
3921 
3922  char* backup_filename = NULL;
3923  char* lock_filename;
3924 
3925  /* Read the database details out of conf.xml */
3926  status = get_db_details(&dbschema, &host, &port, &user, &password);
3927  if (status != 0) {
3928  StrFree(host);
3929  StrFree(port);
3930  StrFree(dbschema);
3931  StrFree(user);
3932  StrFree(password);
3933  return(status);
3934  }
3935 
3936  /* If we are in sqlite mode then take a lock out on a file to
3937  prevent multiple access (not sure that we can be sure that sqlite is
3938  safe for multiple processes to access). */
3939  if (DbFlavour() == SQLITE_DB) {
3940 
3941  /* set up lock filename (it may have changed?) */
3942  if (lock_fd != NULL) {
3943  lock_filename = NULL;
3944  StrAppend(&lock_filename, dbschema);
3945  StrAppend(&lock_filename, ".our_lock");
3946 
3947  *lock_fd = fopen(lock_filename, "w");
3948  status = get_lite_lock(lock_filename, *lock_fd);
3949  if (status != 0) {
3950  printf("Error getting db lock\n");
3951  if (*lock_fd != NULL) {
3952  fclose(*lock_fd);
3953  }
3954  StrFree(host);
3955  StrFree(port);
3956  StrFree(dbschema);
3957  StrFree(user);
3958  StrFree(password);
3959  return(1);
3960  }
3961  StrFree(lock_filename);
3962  }
3963 
3964  /* Make a backup of the sqlite DB */
3965  if (backup == 1) {
3966  StrAppend(&backup_filename, dbschema);
3967  StrAppend(&backup_filename, ".backup");
3968 
3969  status = backup_file(dbschema, backup_filename);
3970 
3971  StrFree(backup_filename);
3972 
3973  if (status == 1) {
3974  if (lock_fd != NULL) {
3975  fclose(*lock_fd);
3976  }
3977  StrFree(host);
3978  StrFree(port);
3979  StrFree(dbschema);
3980  StrFree(user);
3981  StrFree(password);
3982  return(status);
3983  }
3984  }
3985 
3986  }
3987 
3988  /* Finally we can do what we came here to do, connect to the database */
3989  status = DbConnect(dbhandle, dbschema, host, password, user, port);
3990 
3991  /* Cleanup */
3992  StrFree(host);
3993  StrFree(port);
3994  StrFree(dbschema);
3995  StrFree(user);
3996  StrFree(password);
3997 
3998  return(status);
3999 }
4000 
4001 /*
4002  * Release the lock if the DB is SQLite
4003  *
4004  */
4005  void
4006 db_disconnect(FILE* lock_fd)
4007 {
4008  int status = 0;
4009 
4010  if (DbFlavour() == SQLITE_DB) {
4011  if (lock_fd != NULL) {
4012  status = release_lite_lock(lock_fd);
4013  if (status != 0) {
4014  printf("Error releasing db lock");
4015  /*fclose(lock_fd);*/
4016  return;
4017  }
4018  fclose(lock_fd);
4019  }
4020  }
4021  return;
4022 }
4023 
4024 /* To overcome the potential differences in sqlite compile flags assume that it is not
4025  happy with multiple connections.
4026 
4027  The following 2 functions take out a lock and release it
4028  */
4029 
4030 int get_lite_lock(char *lock_filename, FILE* lock_fd)
4031 {
4032  struct flock fl;
4033  struct timeval tv;
4034 
4035  if (lock_fd == NULL) {
4036  printf("%s could not be opened\n", lock_filename);
4037  return 1;
4038  }
4039 
4040  memset(&fl, 0, sizeof(struct flock));
4041  fl.l_type = F_WRLCK;
4042  fl.l_whence = SEEK_SET;
4043  fl.l_pid = getpid();
4044 
4045  while (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
4046  if (errno == EACCES || errno == EAGAIN) {
4047  printf("%s already locked, sleep\n", lock_filename);
4048 
4049  /* sleep for 10 seconds TODO make this configurable? */
4050  tv.tv_sec = 10;
4051  tv.tv_usec = 0;
4052  select(0, NULL, NULL, NULL, &tv);
4053 
4054  } else {
4055  printf("couldn't get lock on %s; %s\n", lock_filename, strerror(errno));
4056  return 1;
4057  }
4058  }
4059 
4060  return 0;
4061 
4062 }
4063 
4064 int release_lite_lock(FILE* lock_fd)
4065 {
4066  struct flock fl;
4067 
4068  if (lock_fd == NULL) {
4069  return 1;
4070  }
4071 
4072  memset(&fl, 0, sizeof(struct flock));
4073  fl.l_type = F_UNLCK;
4074  fl.l_whence = SEEK_SET;
4075 
4076  if (fcntl(fileno(lock_fd), F_SETLK, &fl) == -1) {
4077  return 1;
4078  }
4079 
4080  return 0;
4081 }
4082 
4083 /*
4084  * Now we will read the conf.xml file again, but this time we will not validate.
4085  * Instead we just learn the location of the zonelist.xml and kasp.xml files.
4086  */
4087 int read_filenames(char** zone_list_filename, char** kasp_filename)
4088 {
4089  xmlTextReaderPtr reader = NULL;
4090  xmlDocPtr doc = NULL;
4091  xmlXPathContextPtr xpathCtx = NULL;
4092  xmlXPathObjectPtr xpathObj = NULL;
4093  int ret = 0; /* status of the XML parsing */
4094  char* tag_name = NULL;
4095  char* temp_char = NULL;
4096 
4097  xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
4098  xmlChar *kaspfile_expr = (unsigned char*) "//Common/PolicyFile";
4099 
4100  /* Start reading the file; we will be looking for "Repository" tags */
4101  reader = xmlNewTextReaderFilename(config);
4102  if (reader != NULL) {
4103  ret = xmlTextReaderRead(reader);
4104  while (ret == 1) {
4105  tag_name = (char*) xmlTextReaderLocalName(reader);
4106  /* Found <Common> */
4107  if (strncmp(tag_name, "Common", 6) == 0
4108  && xmlTextReaderNodeType(reader) == 1) {
4109 
4110  /* Expand this node and get the rest of the info with XPath */
4111  xmlTextReaderExpand(reader);
4112  doc = xmlTextReaderCurrentDoc(reader);
4113  if (doc == NULL) {
4114  printf("Error: can not read Common section\n");
4115  /* Don't return? try to parse the rest of the file? */
4116  ret = xmlTextReaderRead(reader);
4117  continue;
4118  }
4119 
4120  xpathCtx = xmlXPathNewContext(doc);
4121  if(xpathCtx == NULL) {
4122  printf("Error: can not create XPath context for Common section\n");
4123  /* Don't return? try to parse the rest of the file? */
4124  ret = xmlTextReaderRead(reader);
4125  continue;
4126  }
4127 
4128  /* Evaluate xpath expression for ZoneListFile */
4129  xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
4130  if(xpathObj == NULL) {
4131  printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr);
4132  /* Don't return? try to parse the rest of the file? */
4133  ret = xmlTextReaderRead(reader);
4134  continue;
4135  }
4136  *zone_list_filename = NULL;
4137  temp_char = (char*) xmlXPathCastToString(xpathObj);
4138  StrAppend(zone_list_filename, temp_char);
4139  StrFree(temp_char);
4140  xmlXPathFreeObject(xpathObj);
4141  printf("zonelist filename set to %s.\n", *zone_list_filename);
4142 
4143  /* Evaluate xpath expression for KaspFile */
4144  xpathObj = xmlXPathEvalExpression(kaspfile_expr, xpathCtx);
4145  xmlXPathFreeContext(xpathCtx);
4146  if(xpathObj == NULL) {
4147  printf("Error: unable to evaluate xpath expression: %s\n", kaspfile_expr);
4148  /* Don't return? try to parse the rest of the file? */
4149  ret = xmlTextReaderRead(reader);
4150  continue;
4151  }
4152  *kasp_filename = NULL;
4153  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
4154  /*
4155  * Found Something, set it
4156  */
4157  temp_char = (char*) xmlXPathCastToString(xpathObj);
4158  StrAppend(kasp_filename, temp_char);
4159  StrFree(temp_char);
4160  } else {
4161  /*
4162  * Set a default
4163  */
4164  /* XXX this should be parse from the the main config */
4165  StrAppend(kasp_filename, OPENDNSSEC_CONFIG_DIR);
4166  StrAppend(kasp_filename, "/kasp.xml");
4167  }
4168  printf("kasp filename set to %s.\n", *kasp_filename);
4169 
4170  xmlXPathFreeObject(xpathObj);
4171  }
4172  /* Read the next line */
4173  ret = xmlTextReaderRead(reader);
4174 
4175  StrFree(tag_name);
4176  }
4177  xmlFreeTextReader(reader);
4178  if (ret != 0) {
4179  printf("%s : failed to parse\n", config);
4180  return(1);
4181  }
4182  } else {
4183  printf("Unable to open %s\n", config);
4184  return(1);
4185  }
4186  if (doc) {
4187  xmlFreeDoc(doc);
4188  }
4189 
4190  return 0;
4191 }
4192 
4193 /*
4194  * Read the conf.xml file yet again, but this time we will not validate.
4195  * Instead we just extract the RepositoryList into the database.
4196  */
4198 {
4199  int status = 0;
4200  xmlDocPtr doc = NULL;
4201  xmlXPathContextPtr xpathCtx = NULL;
4202  xmlXPathObjectPtr xpathObj = NULL;
4203  xmlNode *curNode;
4204  char* repo_name = NULL;
4205  char* repo_capacity = NULL;
4206  int require_backup = 0;
4207  int i = 0;
4208 
4209  xmlChar *node_expr = (unsigned char*) "//Configuration/RepositoryList/Repository";
4210 
4211  /* Start reading the file; we will be looking for "Repository" tags */
4212  /* Load XML document */
4213  doc = xmlParseFile(config);
4214  if (doc == NULL) {
4215  printf("Unable to open %s\n", config);
4216  return(1);
4217  }
4218 
4219  /* Create xpath evaluation context */
4220  xpathCtx = xmlXPathNewContext(doc);
4221  if(xpathCtx == NULL) {
4222  xmlFreeDoc(doc);
4223  return(1);
4224  }
4225 
4226  /* Evaluate xpath expression */
4227  xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx);
4228  if(xpathObj == NULL) {
4229  xmlXPathFreeContext(xpathCtx);
4230  xmlFreeDoc(doc);
4231  return(1);
4232  }
4233 
4234  if (xpathObj->nodesetval) {
4235  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
4236 
4237  require_backup = 0;
4238  StrAppend(&repo_capacity, "");
4239 
4240  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
4241  repo_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i],
4242  (const xmlChar *)"name");
4243  while (curNode) {
4244  if (xmlStrEqual(curNode->name, (const xmlChar *)"Capacity")) {
4245  repo_capacity = (char *) xmlNodeGetContent(curNode);
4246  }
4247  if (xmlStrEqual(curNode->name, (const xmlChar *)"RequireBackup")) {
4248  require_backup = 1;
4249  }
4250 
4251  curNode = curNode->next;
4252  }
4253 
4254  if (strlen(repo_name) != 0) {
4255  /* Log what we are about to do */
4256  printf("Repository %s found\n", repo_name);
4257  if (strlen(repo_capacity) == 0) {
4258  printf("No Maximum Capacity set.\n");
4259  /*
4260  * We have all the information, update/insert this repository
4261  */
4262  status = KsmImportRepository(repo_name, "0", require_backup);
4263  } else {
4264  printf("Capacity set to %s.\n", repo_capacity);
4265  /*
4266  * We have all the information, update/insert this repository
4267  */
4268  status = KsmImportRepository(repo_name, repo_capacity, require_backup);
4269  }
4270  if (require_backup == 0) {
4271  printf("RequireBackup NOT set; please make sure that you know the potential problems of using keys which are not recoverable\n");
4272  } else {
4273  printf("RequireBackup set.\n");
4274  }
4275 
4276  if (status != 0) {
4277  printf("Error Importing Repository %s", repo_name);
4278  /* Don't return? try to parse the rest of the zones? */
4279  }
4280  } else {
4281  printf("WARNING: Repository found with NULL name, skipping...\n");
4282  }
4283  StrFree(repo_name);
4284  StrFree(repo_capacity);
4285  }
4286  }
4287 
4288  if (xpathObj) {
4289  xmlXPathFreeObject(xpathObj);
4290  }
4291  if (xpathCtx) {
4292  xmlXPathFreeContext(xpathCtx);
4293  }
4294  if (doc) {
4295  xmlFreeDoc(doc);
4296  }
4297 
4298  return 0;
4299 }
4300 
4301 /* Read kasp.xml, validate it and grab each policy in it as we go. */
4302 int update_policies(char* kasp_filename)
4303 {
4304  int status;
4305 
4306  /* what we will read from the file */
4307  char *policy_name = NULL;
4308  char *policy_description = NULL;
4309 
4310  /* All of the XML stuff */
4311  xmlDocPtr doc = NULL;
4312  xmlDocPtr pol_doc = NULL;
4313  xmlDocPtr rngdoc = NULL;
4314  xmlNode *curNode;
4315  xmlNode *childNode;
4316  xmlNode *childNode2;
4317  xmlNode *childNode3;
4318  xmlChar *opt_out_flag = (xmlChar *)"N";
4319  xmlChar *share_keys_flag = (xmlChar *)"N";
4320  xmlChar *man_roll_flag = (xmlChar *)"N";
4321  xmlChar *rfc5011_flag = (xmlChar *)"N";
4322  int standby_keys_flag = 0;
4323  xmlXPathContextPtr xpathCtx = NULL;
4324  xmlXPathObjectPtr xpathObj = NULL;
4325  xmlRelaxNGParserCtxtPtr rngpctx = NULL;
4326  xmlRelaxNGValidCtxtPtr rngctx = NULL;
4327  xmlRelaxNGPtr schema = NULL;
4328  int i = 0;
4329 
4330  xmlChar *node_expr = (unsigned char*) "//Policy";
4331 
4332 
4333 /* xmlChar *audit_expr = (unsigned char*) "//Policy/Audit"; */
4334  int audit_found = 0; /* flag to say whether an Audit flag was found or not */
4335 
4336  KSM_POLICY *policy;
4337 
4338  /* Some stuff for the algorithm change check */
4339  int value = 0;
4340  int algo_change = 0;
4341  int user_certain;
4342  char* changes_made = NULL;
4343  int size = -1;
4344  char tmp_change[KSM_MSG_LENGTH];
4345 
4346  /* Some files, the xml and rng */
4347  const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/kasp.rng";
4348  char* kaspcheck_cmd = NULL;
4349  char* kaspcheck_cmd_version = NULL;
4350 
4351  StrAppend(&kaspcheck_cmd, ODS_AU_KASPCHECK);
4352  StrAppend(&kaspcheck_cmd, " -c ");
4353  StrAppend(&kaspcheck_cmd, config);
4354 
4355  StrAppend(&kaspcheck_cmd_version, ODS_AU_KASPCHECK);
4356  StrAppend(&kaspcheck_cmd_version, " -v > /dev/null");
4357 
4358  /* Run kaspcheck */
4359  status = system(kaspcheck_cmd_version);
4360  if (status == 0)
4361  {
4362  status = system(kaspcheck_cmd);
4363  if (status != 0)
4364  {
4365  fprintf(stderr, "ods-kaspcheck returned an error, please check your policy\n");
4366  StrFree(kaspcheck_cmd);
4367  StrFree(kaspcheck_cmd_version);
4368  return(-1);
4369  }
4370  }
4371  else
4372  {
4373  fprintf(stderr, "Couldn't run ods-kaspcheck (Auditor is not installed), will carry on\n");
4374  }
4375 
4376  StrFree(kaspcheck_cmd);
4377  StrFree(kaspcheck_cmd_version);
4378 
4379  /* Load XML document */
4380  doc = xmlParseFile(kasp_filename);
4381  if (doc == NULL) {
4382  printf("Error: unable to parse file \"%s\"\n", kasp_filename);
4383  return(-1);
4384  }
4385 
4386  /* Load rng document: TODO make the rng stuff optional? */
4387  rngdoc = xmlParseFile(rngfilename);
4388  if (rngdoc == NULL) {
4389  printf("Error: unable to parse file \"%s\"\n", rngfilename);
4390  return(-1);
4391  }
4392 
4393  /* Create an XML RelaxNGs parser context for the relax-ng document. */
4394  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
4395  if (rngpctx == NULL) {
4396  printf("Error: unable to create XML RelaxNGs parser context\n");
4397  return(-1);
4398  }
4399 
4400  /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
4401  schema = xmlRelaxNGParse(rngpctx);
4402  if (schema == NULL) {
4403  printf("Error: unable to parse a schema definition resource\n");
4404  return(-1);
4405  }
4406 
4407  /* Create an XML RelaxNGs validation context based on the given schema */
4408  rngctx = xmlRelaxNGNewValidCtxt(schema);
4409  if (rngctx == NULL) {
4410  printf("Error: unable to create RelaxNGs validation context based on the schema\n");
4411  return(-1);
4412  }
4413 
4414  /* Validate a document tree in memory. */
4415  status = xmlRelaxNGValidateDoc(rngctx,doc);
4416  if (status != 0) {
4417  printf("Error validating file \"%s\"\n", kasp_filename);
4418  return(-1);
4419  }
4420 
4421  /* Allocate some space for our policy */
4422  policy = KsmPolicyAlloc();
4423  if (policy == NULL) {
4424  printf("Malloc for policy struct failed");
4425  exit(1);
4426  }
4427 
4428  /* Create xpath evaluation context */
4429  xpathCtx = xmlXPathNewContext(doc);
4430  if(xpathCtx == NULL) {
4431  xmlFreeDoc(doc);
4432  KsmPolicyFree(policy);
4433  return(1);
4434  }
4435 
4436  /* Evaluate xpath expression */
4437  xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx);
4438  if(xpathObj == NULL) {
4439  xmlXPathFreeContext(xpathCtx);
4440  xmlFreeDoc(doc);
4441  KsmPolicyFree(policy);
4442  return(1);
4443  }
4444 
4445  if (xpathObj->nodesetval) {
4446 
4447  /*
4448  * We will loop through twice, the first time to check on any algorithm
4449  * changes (which are not advised)
4450  */
4451  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) { /* foreach policy */
4452 
4453  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
4454  policy_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], (const xmlChar *)"name");
4455  if (strlen(policy_name) == 0) {
4456  /* error */
4457  printf("Error extracting policy name from %s\n", kasp_filename);
4458  break;
4459  }
4460 
4461  /*
4462  * Only carry on if this is an existing policy
4463  */
4464  SetPolicyDefaults(policy, policy_name);
4465  status = KsmPolicyExists(policy_name);
4466  if (status == 0) {
4467  /* Policy exists */
4468  status = KsmPolicyRead(policy);
4469  if(status != 0) {
4470  printf("Error: unable to read policy %s; skipping\n", policy_name);
4471  break;
4472  }
4473 
4474  while (curNode) {
4475  if (xmlStrEqual(curNode->name, (const xmlChar *)"Keys")) {
4476  childNode = curNode->children;
4477  while (childNode){
4478  if (xmlStrEqual(childNode->name, (const xmlChar *)"KSK")) {
4479  childNode2 = childNode->children;
4480  while (childNode2){
4481  if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
4482  /* Compare with existing */
4483  value = 0;
4484  status = StrStrtoi((char *)xmlNodeGetContent(childNode2), &value);
4485  if (status != 0) {
4486  printf("Error extracting KSK algorithm for policy %s, exiting...", policy_name);
4487  return status;
4488  }
4489  if (value != policy->ksk->algorithm) {
4490  /* Changed */
4491  if (!algo_change) {
4492  printf("\n\nAlgorithm change attempted... details:\n");
4493  StrAppend(&changes_made, "Algorithm changes made, details:");
4494  algo_change = 1;
4495  }
4496  size = snprintf(tmp_change, KSM_MSG_LENGTH, "Policy: %s, KSK algorithm changed from %d to %d.", policy_name, policy->ksk->algorithm, value);
4497  /* Check overflow */
4498  if (size < 0 || size >= KSM_MSG_LENGTH) {
4499  printf("Error constructing log message for policy %s, exiting...", policy_name);
4500  return -1;
4501  }
4502  printf("%s\n", tmp_change);
4503  StrAppend(&changes_made, " ");
4504  StrAppend(&changes_made, tmp_change);
4505  }
4506 
4507  }
4508  childNode2 = childNode2->next;
4509  }
4510 
4511  } /* End of KSK */
4512  /* ZSK */
4513  else if (xmlStrEqual(childNode->name, (const xmlChar *)"ZSK")) {
4514  childNode2 = childNode->children;
4515  while (childNode2){
4516  if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
4517  /* Compare with existing */
4518  value = 0;
4519  status = StrStrtoi((char *)xmlNodeGetContent(childNode2), &value);
4520  if (status != 0) {
4521  printf("Error extracting ZSK algorithm for policy %s, exiting...", policy_name);
4522  return status;
4523  }
4524  if (value != policy->zsk->algorithm) {
4525  /* Changed */
4526  if (!algo_change) {
4527  printf("\n\nAlgorithm change attempted... details:\n");
4528  StrAppend(&changes_made, "Algorithm changes made, details:");
4529  algo_change = 1;
4530  }
4531  size = snprintf(tmp_change, KSM_MSG_LENGTH, "Policy: %s, ZSK algorithm changed from %d to %d.", policy_name, policy->zsk->algorithm, value);
4532  /* Check overflow */
4533  if (size < 0 || size >= KSM_MSG_LENGTH) {
4534  printf("Error constructing log message for policy %s, exiting...", policy_name);
4535  return -1;
4536  }
4537  printf("%s\n", tmp_change);
4538  StrAppend(&changes_made, " ");
4539  StrAppend(&changes_made, tmp_change);
4540  }
4541 
4542  }
4543  childNode2 = childNode2->next;
4544  }
4545 
4546  } /* End of ZSK */
4547 
4548  childNode = childNode->next;
4549  }
4550  }
4551  curNode = curNode->next;
4552  }
4553  }
4554  /* Free up some stuff that we don't need any more */
4555  StrFree(policy_name);
4556 
4557  } /* End of <Policy> */
4558 
4559  /*
4560  * Did we see any changes? If so then warn and confirm before continuing
4561  */
4562 
4563  if (algo_change == 1 && force_flag == 0) {
4564  printf("*WARNING* This will change the algorithms used as noted above. Algorithm rollover is _not_ supported by OpenDNSSEC and zones may break. Are you sure? [y/N] ");
4565 
4566  user_certain = getchar();
4567  if (user_certain != 'y' && user_certain != 'Y') {
4568  printf("\nOkay, quitting...\n");
4569  xmlXPathFreeContext(xpathCtx);
4570  xmlFreeDoc(doc);
4571  KsmPolicyFree(policy);
4572 
4573  exit(0);
4574  }
4575 
4576  /* Newline for the output */
4577  printf("\n");
4578 
4579  /*
4580  * Log this change to syslog for posterity
4581  */
4582 #ifdef HAVE_OPENLOG_R
4583  openlog_r("ods-ksmutil", 0, DEFAULT_LOG_FACILITY, &sdata);
4584 #else
4585  openlog("ods-ksmutil", 0, DEFAULT_LOG_FACILITY);
4586 #endif
4587 #ifdef HAVE_SYSLOG_R
4588  syslog_r(LOG_INFO, &sdata, "%s", changes_made);
4589 #else
4590  syslog(LOG_INFO, "%s", changes_made);
4591 #endif
4592 #ifdef HAVE_CLOSELOG_R
4593  closelog_r(&sdata);
4594 #else
4595  closelog();
4596 #endif
4597 
4598  }
4599 
4600  /*
4601  * Then loop through to actually make the updates
4602  */
4603  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
4604 
4605  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
4606  policy_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], (const xmlChar *)"name");
4607  if (strlen(policy_name) == 0) {
4608  /* error */
4609  printf("Error extracting policy name from %s\n", kasp_filename);
4610  break;
4611  }
4612  audit_found = 0;
4613 
4614  printf("Policy %s found\n", policy_name);
4615  while (curNode) {
4616  if (xmlStrEqual(curNode->name, (const xmlChar *)"Description")) {
4617  policy_description = (char *) xmlNodeGetContent(curNode);
4618 
4619  /* Insert or update this policy with the description found,
4620  we will need the policy_id too */
4621  SetPolicyDefaults(policy, policy_name);
4622  status = KsmPolicyExists(policy_name);
4623  if (status == 0) {
4624  /* Policy exists; we will be updating it */
4625  status = KsmPolicyRead(policy);
4626  if(status != 0) {
4627  printf("Error: unable to read policy %s; skipping\n", policy_name);
4628  curNode = curNode->next;
4629  break;
4630  }
4631  /* TODO Set description here ? */
4632  }
4633  else {
4634  /* New policy, insert it and get the new policy_id */
4635  status = KsmImportPolicy(policy_name, policy_description);
4636  if(status != 0) {
4637  printf("Error: unable to insert policy %s; skipping\n", policy_name);
4638  /* Don't return? try to parse the rest of the file? */
4639  continue;
4640  }
4641  status = KsmPolicySetIdFromName(policy);
4642 
4643  if (status != 0) {
4644  printf("Error: unable to get policy id for %s; skipping\n", policy_name);
4645  continue;
4646  }
4647  }
4648  }
4649  /* SIGNATURES */
4650  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Signatures")) {
4651  childNode = curNode->children;
4652  while (childNode){
4653  if (xmlStrEqual(childNode->name, (const xmlChar *)"Resign")) {
4654  SetParamOnPolicy(xmlNodeGetContent(childNode), "resign", "signature", policy->signature->resign, policy->id, DURATION_TYPE);
4655  }
4656  else if (xmlStrEqual(childNode->name, (const xmlChar *)"Refresh")) {
4657  SetParamOnPolicy(xmlNodeGetContent(childNode), "refresh", "signature", policy->signer->refresh, policy->id, DURATION_TYPE);
4658  }
4659  else if (xmlStrEqual(childNode->name, (const xmlChar *)"Validity")) {
4660  childNode2 = childNode->children;
4661  while (childNode2){
4662  if (xmlStrEqual(childNode2->name, (const xmlChar *)"Default")) {
4663  SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdefault", "signature", policy->signature->valdefault, policy->id, DURATION_TYPE);
4664  }
4665  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Denial")) {
4666  SetParamOnPolicy(xmlNodeGetContent(childNode2), "valdenial", "signature", policy->signature->valdenial, policy->id, DURATION_TYPE);
4667  }
4668  childNode2 = childNode2->next;
4669  }
4670  }
4671  else if (xmlStrEqual(childNode->name, (const xmlChar *)"Jitter")) {
4672  SetParamOnPolicy(xmlNodeGetContent(childNode), "jitter", "signature", policy->signer->jitter, policy->id, DURATION_TYPE);
4673  }
4674  else if (xmlStrEqual(childNode->name, (const xmlChar *)"InceptionOffset")) {
4675  SetParamOnPolicy(xmlNodeGetContent(childNode), "clockskew", "signature", policy->signature->clockskew, policy->id, DURATION_TYPE);
4676  }
4677  childNode = childNode->next;
4678  }
4679  } /* End of Signatures */
4680  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Denial")) {
4681  opt_out_flag = (xmlChar *)"N";
4682  childNode = curNode->children;
4683  while (childNode){
4684  if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC3")) {
4685  /* NSEC3 */
4686  status = KsmParameterSet("version", "denial", 3, policy->id);
4687  if (status != 0) {
4688  printf("Error: unable to insert/update %s for policy\n", "Denial version");
4689  }
4690  childNode2 = childNode->children;
4691  while (childNode2){
4692  if (xmlStrEqual(childNode2->name, (const xmlChar *)"OptOut")) {
4693  opt_out_flag = (xmlChar *)"Y";
4694  }
4695  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Resalt")) {
4696  SetParamOnPolicy(xmlNodeGetContent(childNode2), "resalt", "denial", policy->denial->resalt, policy->id, DURATION_TYPE);
4697  }
4698  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Hash")) {
4699  childNode3 = childNode2->children;
4700  while (childNode3){
4701  if (xmlStrEqual(childNode3->name, (const xmlChar *)"Algorithm")) {
4702  SetParamOnPolicy(xmlNodeGetContent(childNode3), "algorithm", "denial", policy->denial->algorithm, policy->id, INT_TYPE);
4703  }
4704  else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Iterations")) {
4705  SetParamOnPolicy(xmlNodeGetContent(childNode3), "iterations", "denial", policy->denial->iteration, policy->id, INT_TYPE);
4706  }
4707  else if (xmlStrEqual(childNode3->name, (const xmlChar *)"Salt")) {
4708  SetParamOnPolicy(xmlGetProp(childNode3, (const xmlChar *)"length"), "saltlength", "denial", policy->denial->saltlength, policy->id, INT_TYPE);
4709  }
4710  childNode3 = childNode3->next;
4711  }
4712  }
4713 
4714  childNode2 = childNode2->next;
4715  }
4716  /* Set things that we flagged */
4717  SetParamOnPolicy(opt_out_flag, "optout", "denial", policy->denial->optout, policy->id, BOOL_TYPE);
4718  } /* End of NSEC3 */
4719  else if (xmlStrEqual(childNode->name, (const xmlChar *)"NSEC")) {
4720  status = KsmParameterSet("version", "denial", 1, policy->id);
4721  if (status != 0) {
4722  printf("Error: unable to insert/update %s for policy\n", "Denial version");
4723  }
4724  }
4725  childNode = childNode->next;
4726  }
4727  } /* End of Denial */
4728  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Keys")) {
4729  share_keys_flag = (xmlChar *)"N";
4730  childNode = curNode->children;
4731  while (childNode){
4732  if (xmlStrEqual(childNode->name, (const xmlChar *)"TTL")) {
4733  SetParamOnPolicy(xmlNodeGetContent(childNode), "ttl", "keys", policy->keys->ttl, policy->id, DURATION_TYPE);
4734  }
4735  else if (xmlStrEqual(childNode->name, (const xmlChar *)"RetireSafety")) {
4736  SetParamOnPolicy(xmlNodeGetContent(childNode), "retiresafety", "keys", policy->keys->retire_safety, policy->id, DURATION_TYPE);
4737  }
4738  else if (xmlStrEqual(childNode->name, (const xmlChar *)"PublishSafety")) {
4739  SetParamOnPolicy(xmlNodeGetContent(childNode), "publishsafety", "keys", policy->keys->publish_safety, policy->id, DURATION_TYPE);
4740  }
4741  else if (xmlStrEqual(childNode->name, (const xmlChar *)"ShareKeys")) {
4742  share_keys_flag = (xmlChar *)"Y";
4743  }
4744  else if (xmlStrEqual(childNode->name, (const xmlChar *)"Purge")) {
4745  SetParamOnPolicy(xmlNodeGetContent(childNode), "purge", "keys", policy->keys->purge, policy->id, DURATION_TYPE);
4746  }
4747  /* KSK */
4748  else if (xmlStrEqual(childNode->name, (const xmlChar *)"KSK")) {
4749  man_roll_flag = (xmlChar *)"N";
4750  rfc5011_flag = (xmlChar *)"N";
4751  childNode2 = childNode->children;
4752  while (childNode2){
4753  if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
4754  SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "ksk", policy->ksk->algorithm, policy->id, INT_TYPE);
4755  SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "ksk", policy->ksk->bits, policy->id, INT_TYPE);
4756 
4757  }
4758  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) {
4759  SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "ksk", policy->ksk->lifetime, policy->id, DURATION_TYPE);
4760  }
4761  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) {
4762  if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "ksk", policy->ksk->sm, policy->id, REPO_TYPE) != 0) {
4763  printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n");
4764  /* return the error, we do not want to continue */
4765  xmlFreeDoc(pol_doc);
4766  xmlXPathFreeContext(xpathCtx);
4767  xmlRelaxNGFree(schema);
4768  xmlRelaxNGFreeValidCtxt(rngctx);
4769  xmlRelaxNGFreeParserCtxt(rngpctx);
4770  xmlFreeDoc(doc);
4771  xmlFreeDoc(rngdoc);
4772  KsmPolicyFree(policy);
4773 
4774  return(1);
4775  }
4776  }
4777  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) {
4778  SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE);
4779  standby_keys_flag = 1;
4780  }
4781  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) {
4782  man_roll_flag = (xmlChar *)"Y";
4783  }
4784  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RFC5011")) {
4785  rfc5011_flag = (xmlChar *)"Y";
4786  }
4787  /*else if (xmlStrEqual(childNode2->name, (const xmlChar *)"RolloverScheme")) {
4788  SetParamOnPolicy(xmlNodeGetContent(childNode2), "rollover_scheme", "ksk", policy->ksk->rollover_scheme, policy->id, ROLLOVER_TYPE);
4789  }*/
4790  childNode2 = childNode2->next;
4791  }
4792  /* Set things that we flagged */
4793  SetParamOnPolicy(man_roll_flag, "manual_rollover", "ksk", policy->ksk->manual_rollover, policy->id, BOOL_TYPE);
4794  SetParamOnPolicy(rfc5011_flag, "rfc5011", "ksk", policy->ksk->rfc5011, policy->id, BOOL_TYPE);
4795  if (standby_keys_flag == 0) {
4796  SetParamOnPolicy((xmlChar *)"0", "standby", "ksk", policy->ksk->standby_keys, policy->id, INT_TYPE_NO_FREE);
4797  } else {
4798  standby_keys_flag = 0;
4799  }
4800  } /* End of KSK */
4801  /* ZSK */
4802  else if (xmlStrEqual(childNode->name, (const xmlChar *)"ZSK")) {
4803  man_roll_flag = (xmlChar *)"N";
4804  childNode2 = childNode->children;
4805  while (childNode2){
4806  if (xmlStrEqual(childNode2->name, (const xmlChar *)"Algorithm")) {
4807  SetParamOnPolicy(xmlNodeGetContent(childNode2), "algorithm", "zsk", policy->zsk->algorithm, policy->id, INT_TYPE);
4808  SetParamOnPolicy(xmlGetProp(childNode2, (const xmlChar *)"length"), "bits", "zsk", policy->zsk->bits, policy->id, INT_TYPE);
4809 
4810  }
4811  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Lifetime")) {
4812  SetParamOnPolicy(xmlNodeGetContent(childNode2), "lifetime", "zsk", policy->zsk->lifetime, policy->id, DURATION_TYPE);
4813  }
4814  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Repository")) {
4815  if (SetParamOnPolicy(xmlNodeGetContent(childNode2), "repository", "zsk", policy->zsk->sm, policy->id, REPO_TYPE) != 0) {
4816  printf("Please either add the repository to conf.xml or remove the reference to it from kasp.xml\n");
4817  /* return the error, we do not want to continue */
4818  xmlFreeDoc(pol_doc);
4819  xmlXPathFreeContext(xpathCtx);
4820  xmlRelaxNGFree(schema);
4821  xmlRelaxNGFreeValidCtxt(rngctx);
4822  xmlRelaxNGFreeParserCtxt(rngpctx);
4823  xmlFreeDoc(doc);
4824  xmlFreeDoc(rngdoc);
4825  KsmPolicyFree(policy);
4826 
4827  return(1);
4828  }
4829  }
4830  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Standby")) {
4831  SetParamOnPolicy(xmlNodeGetContent(childNode2), "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE);
4832  standby_keys_flag = 1;
4833  }
4834  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"ManualRollover")) {
4835  man_roll_flag = (xmlChar *)"Y";
4836  }
4837  childNode2 = childNode2->next;
4838  }
4839  /* Set things that we flagged */
4840  SetParamOnPolicy(man_roll_flag, "manual_rollover", "zsk", policy->zsk->manual_rollover, policy->id, BOOL_TYPE);
4841  } /* End of ZSK */
4842 
4843  childNode = childNode->next;
4844  }
4845  /* Set things that we flagged */
4846  SetParamOnPolicy(share_keys_flag, "zones_share_keys", "keys", policy->keys->share_keys, policy->id, BOOL_TYPE);
4847  if (standby_keys_flag == 0) {
4848  SetParamOnPolicy((xmlChar *)"0", "standby", "zsk", policy->zsk->standby_keys, policy->id, INT_TYPE_NO_FREE);
4849  } else {
4850  standby_keys_flag = 0;
4851  }
4852 
4853  } /* End of Keys */
4854  /* Zone */
4855  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Zone")) {
4856  childNode = curNode->children;
4857  while (childNode){
4858  if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) {
4859  SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "zone", policy->zone->propdelay, policy->id, DURATION_TYPE);
4860  }
4861  else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) {
4862  childNode2 = childNode->children;
4863  while (childNode2){
4864  if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
4865  SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "zone", policy->zone->soa_ttl, policy->id, DURATION_TYPE);
4866  }
4867  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) {
4868  SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "zone", policy->zone->soa_min, policy->id, DURATION_TYPE);
4869  }
4870  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Serial")) {
4871  SetParamOnPolicy(xmlNodeGetContent(childNode2), "serial", "zone", policy->zone->serial, policy->id, SERIAL_TYPE);
4872  }
4873  childNode2 = childNode2->next;
4874  }
4875  }
4876  childNode = childNode->next;
4877  }
4878  } /* End of Zone */
4879  /* Parent */
4880  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Parent")) {
4881  childNode = curNode->children;
4882  while (childNode){
4883  if (xmlStrEqual(childNode->name, (const xmlChar *)"PropagationDelay")) {
4884  SetParamOnPolicy(xmlNodeGetContent(childNode), "propagationdelay", "parent", policy->parent->propdelay, policy->id, DURATION_TYPE);
4885  }
4886  else if (xmlStrEqual(childNode->name, (const xmlChar *)"DS")) {
4887  childNode2 = childNode->children;
4888  while (childNode2){
4889  if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
4890  SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttlds", "parent", policy->parent->ds_ttl, policy->id, DURATION_TYPE);
4891  }
4892  childNode2 = childNode2->next;
4893  }
4894  }
4895  else if (xmlStrEqual(childNode->name, (const xmlChar *)"SOA")) {
4896  childNode2 = childNode->children;
4897  while (childNode2){
4898  if (xmlStrEqual(childNode2->name, (const xmlChar *)"TTL")) {
4899  SetParamOnPolicy(xmlNodeGetContent(childNode2), "ttl", "parent", policy->parent->soa_ttl, policy->id, DURATION_TYPE);
4900  }
4901  else if (xmlStrEqual(childNode2->name, (const xmlChar *)"Minimum")) {
4902  SetParamOnPolicy(xmlNodeGetContent(childNode2), "min", "parent", policy->parent->soa_min, policy->id, DURATION_TYPE);
4903  }
4904  childNode2 = childNode2->next;
4905  }
4906  }
4907  childNode = childNode->next;
4908  }
4909  } /* End of Parent */
4910  /* Audit */
4911  else if (xmlStrEqual(curNode->name, (const xmlChar *)"Audit")) {
4912  status = KsmImportAudit(policy->id, "");
4913  childNode = curNode->children;
4914  while (childNode){
4915  if (xmlStrEqual(childNode->name, (const xmlChar *)"Partial")) {
4916  status = KsmImportAudit(policy->id, "<Partial/>");
4917  }
4918  childNode = childNode->next;
4919  }
4920  audit_found = 1;
4921  if(status != 0) {
4922  printf("Error: unable to insert Audit info for policy %s\n", policy->name);
4923  }
4924  }
4925 
4926  curNode = curNode->next;
4927  }
4928  /* Indicate in the database if we didn't find an audit tag */
4929  if (audit_found == 0) {
4930  status = KsmImportAudit(policy->id, "NULL");
4931  }
4932 
4933  /* Free up some stuff that we don't need any more */
4934  StrFree(policy_name);
4935  StrFree(policy_description);
4936 
4937  } /* End of <Policy> */
4938  }
4939 
4940  /* Cleanup */
4941  xmlXPathFreeContext(xpathCtx);
4942  xmlRelaxNGFree(schema);
4943  xmlRelaxNGFreeValidCtxt(rngctx);
4944  xmlRelaxNGFreeParserCtxt(rngpctx);
4945  xmlFreeDoc(doc);
4946  xmlFreeDoc(rngdoc);
4947  KsmPolicyFree(policy);
4948 
4949  return(status);
4950 }
4951 
4952 /* Read zonelist (as passed in) and insert/update any zones seen */
4953 int update_zones(char* zone_list_filename)
4954 {
4955  int status = 0;
4956  xmlTextReaderPtr reader = NULL;
4957  xmlDocPtr doc = NULL;
4958  xmlXPathContextPtr xpathCtx = NULL;
4959  xmlXPathObjectPtr xpathObj = NULL;
4960  int ret = 0; /* status of the XML parsing */
4961  char* zone_name = NULL;
4962  char* policy_name = NULL;
4963  char* current_policy = NULL;
4964  char* current_signconf = NULL;
4965  char* current_input = NULL;
4966  char* current_output = NULL;
4967  char* temp_char = NULL;
4968  char* tag_name = NULL;
4969  int policy_id = 0;
4970  int new_zone = 0; /* flag to say if the zone is new or not */
4971  int file_zone_count = 0; /* As a quick check we will compare the number of */
4972  int db_zone_count = 0; /* zones in the file to the number in the database */
4973  int* zone_ids; /* List of zone_ids seen from zonelist.xml */
4974  int temp_id;
4975 
4976  char* sql = NULL;
4977  DB_RESULT result; /* Result of the query */
4978  DB_RESULT result2; /* Result of the query */
4979  DB_RESULT result3; /* Result of the query */
4980  DB_ROW row = NULL; /* Row data */
4981  KSM_PARAMETER shared; /* Parameter information */
4982  int seen_zone = 0;
4983  int temp_count = 0;
4984  int i = 0;
4985 
4986  xmlChar *name_expr = (unsigned char*) "name";
4987  xmlChar *policy_expr = (unsigned char*) "//Zone/Policy";
4988  xmlChar *signconf_expr = (unsigned char*) "//Zone/SignerConfiguration";
4989  xmlChar *input_expr = (unsigned char*) "//Zone/Adapters/Input/File";
4990  xmlChar *output_expr = (unsigned char*) "//Zone/Adapters/Output/File";
4991 
4992  /* TODO validate the file ? */
4993  /* Read through the file counting zones TODO better way to do this? */
4994  reader = xmlNewTextReaderFilename(zone_list_filename);
4995  if (reader != NULL) {
4996  ret = xmlTextReaderRead(reader);
4997  while (ret == 1) {
4998  tag_name = (char*) xmlTextReaderLocalName(reader);
4999  /* Found <Zone> */
5000  if (strncmp(tag_name, "Zone", 4) == 0
5001  && strncmp(tag_name, "ZoneList", 8) != 0
5002  && xmlTextReaderNodeType(reader) == 1) {
5003  file_zone_count++;
5004  }
5005  /* Read the next line */
5006  ret = xmlTextReaderRead(reader);
5007  StrFree(tag_name);
5008  }
5009  xmlFreeTextReader(reader);
5010  if (ret != 0) {
5011  printf("%s : failed to parse\n", zone_list_filename);
5012  return 1;
5013  }
5014  } else {
5015  printf("Unable to open %s\n", zone_list_filename);
5016  return 1;
5017  }
5018 
5019  /* Allocate space for the list of zone IDs */
5020  zone_ids = MemMalloc(file_zone_count * sizeof(int));
5021 
5022  /* Start reading the file; we will be looking for "Zone" tags */
5023  reader = xmlNewTextReaderFilename(zone_list_filename);
5024  if (reader != NULL) {
5025  ret = xmlTextReaderRead(reader);
5026  while (ret == 1) {
5027  tag_name = (char*) xmlTextReaderLocalName(reader);
5028  /* Found <Zone> */
5029  if (strncmp(tag_name, "Zone", 4) == 0
5030  && strncmp(tag_name, "ZoneList", 8) != 0
5031  && xmlTextReaderNodeType(reader) == 1) {
5032  /* Get the repository name */
5033  zone_name = NULL;
5034  temp_char = (char*) xmlTextReaderGetAttribute(reader, name_expr);
5035  StrAppend(&zone_name, temp_char);
5036  StrFree(temp_char);
5037 
5038  /*
5039  It is tempting to remove the trailing dot here; however I am
5040  not sure that it is the right thing to do... It trashed my
5041  test setup by deleting the zone sion. and replacing it with
5042  sion (but of course none of the keys were moved). I think
5043  that allowing people to edit zonelist.xml means that we must
5044  allow them to add the td if they want to.
5045  */
5046 
5047  /* Make sure that we got something */
5048  if (zone_name == NULL) {
5049  /* error */
5050  printf("Error extracting zone name from %s\n", zone_list_filename);
5051  /* Don't return? try to parse the rest of the file? */
5052  ret = xmlTextReaderRead(reader);
5053  continue;
5054  }
5055 
5056  printf("Zone %s found\n", zone_name);
5057 
5058  /* Expand this node and get the rest of the info with XPath */
5059  xmlTextReaderExpand(reader);
5060  doc = xmlTextReaderCurrentDoc(reader);
5061  if (doc == NULL) {
5062  printf("Error: can not read zone \"%s\"; skipping\n", zone_name);
5063  /* Don't return? try to parse the rest of the zones? */
5064  ret = xmlTextReaderRead(reader);
5065  continue;
5066  }
5067 
5068  xpathCtx = xmlXPathNewContext(doc);
5069  if(xpathCtx == NULL) {
5070  printf("Error: can not create XPath context for \"%s\"; skipping zone\n", zone_name);
5071  /* Don't return? try to parse the rest of the zones? */
5072  ret = xmlTextReaderRead(reader);
5073  continue;
5074  }
5075 
5076  /* Extract the Policy name for this zone */
5077  /* Evaluate xpath expression for policy */
5078  xpathObj = xmlXPathEvalExpression(policy_expr, xpathCtx);
5079  if(xpathObj == NULL) {
5080  printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", policy_expr);
5081  /* Don't return? try to parse the rest of the zones? */
5082  ret = xmlTextReaderRead(reader);
5083  continue;
5084  }
5085 
5086  current_policy = NULL;
5087  temp_char = (char *)xmlXPathCastToString(xpathObj);
5088  StrAppend(&current_policy, temp_char);
5089  StrFree(temp_char);
5090  printf("Policy set to %s.\n", current_policy);
5091  xmlXPathFreeObject(xpathObj);
5092 
5093  /* If we have a different policy to last time get its ID */
5094  if (policy_name == NULL || strcmp(current_policy, policy_name) != 0) {
5095  StrFree(policy_name);
5096  StrAppend(&policy_name, current_policy);
5097 
5098  status = KsmPolicyIdFromName(policy_name, &policy_id);
5099  if (status != 0) {
5100  printf("Error, can't find policy : %s\n", policy_name);
5101  /* Don't return? try to parse the rest of the zones? */
5102  ret = xmlTextReaderRead(reader);
5103  continue;
5104  }
5105  }
5106 
5107  /* Extract the Signconf name for this zone */
5108  /* Evaluate xpath expression */
5109  xpathObj = xmlXPathEvalExpression(signconf_expr, xpathCtx);
5110  if(xpathObj == NULL) {
5111  printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", signconf_expr);
5112  /* Don't return? try to parse the rest of the zones? */
5113  ret = xmlTextReaderRead(reader);
5114  continue;
5115  }
5116 
5117  current_signconf = NULL;
5118  temp_char = (char *)xmlXPathCastToString(xpathObj);
5119  StrAppend(&current_signconf, temp_char);
5120  StrFree(temp_char);
5121  xmlXPathFreeObject(xpathObj);
5122 
5123  /* Extract the Input name for this zone */
5124  /* Evaluate xpath expression */
5125  xpathObj = xmlXPathEvalExpression(input_expr, xpathCtx);
5126  if(xpathObj == NULL) {
5127  printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", input_expr);
5128  /* Don't return? try to parse the rest of the zones? */
5129  ret = xmlTextReaderRead(reader);
5130  continue;
5131  }
5132 
5133  current_input = NULL;
5134  temp_char = (char *)xmlXPathCastToString(xpathObj);
5135  StrAppend(&current_input, temp_char);
5136  StrFree(temp_char);
5137  xmlXPathFreeObject(xpathObj);
5138 
5139  /* Extract the Output name for this zone */
5140  /* Evaluate xpath expression */
5141  xpathObj = xmlXPathEvalExpression(output_expr, xpathCtx);
5142  xmlXPathFreeContext(xpathCtx);
5143  if(xpathObj == NULL) {
5144  printf("Error: unable to evaluate xpath expression: %s; skipping zone\n", output_expr);
5145  /* Don't return? try to parse the rest of the zones? */
5146  ret = xmlTextReaderRead(reader);
5147  continue;
5148  }
5149 
5150  current_output = NULL;
5151  temp_char = (char *)xmlXPathCastToString(xpathObj);
5152  StrAppend(&current_output, temp_char);
5153  StrFree(temp_char);
5154  xmlXPathFreeObject(xpathObj);
5155 
5156  /*
5157  * Now we have all the information update/insert this repository
5158  */
5159  status = KsmImportZone(zone_name, policy_id, 0, &new_zone, current_signconf, current_input, current_output);
5160  if (status != 0) {
5161  if (status == -3) {
5162  printf("Error Importing zone %s; it already exists both with and without a trailing dot\n", zone_name);
5163  } else {
5164  printf("Error Importing Zone %s\n", zone_name);
5165  }
5166  /* Don't return? try to parse the rest of the zones? */
5167  ret = xmlTextReaderRead(reader);
5168  continue;
5169  }
5170 
5171  /* If need be link existing keys to zone */
5172  if (new_zone == 1) {
5173  printf("Added zone %s to database\n", zone_name);
5174  /* WITH NEW KEYSHARING LEAVE THIS TO THE ENFORCER TODO - CHECK THIS IS RIGHT */
5175  /*
5176  status = KsmLinkKeys(zone_name, policy_id);
5177  if (status != 0) {
5178  printf("Failed to Link Keys to zone\n");
5179  ret = xmlTextReaderRead(reader);
5180  continue;
5181  }*/
5182  }
5183 
5184  /* make a note of the zone_id */
5185  status = KsmZoneIdFromName(zone_name, &temp_id);
5186  if (status != 0) {
5187  printf("Error: unable to find a zone named \"%s\" in database\n", zone_name);
5188  printf("Error: Possibly two domains differ only by having a trailing dot or not?\n");
5189  StrFree(zone_ids);
5190  return(status);
5191  }
5192 
5193  /* We malloc'd this above */
5194  zone_ids[i] = temp_id;
5195  i++;
5196 
5197  StrFree(zone_name);
5198  StrFree(current_policy);
5199  StrFree(current_signconf);
5200  StrFree(current_input);
5201  StrFree(current_output);
5202 
5203  new_zone = 0;
5204 
5205  }
5206  /* Read the next line */
5207  ret = xmlTextReaderRead(reader);
5208  StrFree(tag_name);
5209  }
5210  xmlFreeTextReader(reader);
5211  if (ret != 0) {
5212  printf("%s : failed to parse\n", zone_list_filename);
5213  }
5214  } else {
5215  printf("Unable to open %s\n", zone_list_filename);
5216  }
5217  if (doc) {
5218  xmlFreeDoc(doc);
5219  }
5220  StrFree(policy_name);
5221 
5222  /* Now see how many zones are in the database */
5223  sql = DqsCountInit(DB_ZONE_TABLE);
5224  DqsEnd(&sql);
5225 
5226  /* Execute query and free up the query string */
5227  status = DbIntQuery(DbHandle(), &db_zone_count, sql);
5228  DqsFree(sql);
5229 
5230  /* If the 2 numbers match then our work is done */
5231  if (file_zone_count == db_zone_count) {
5232  StrFree(zone_ids);
5233  return 0;
5234  }
5235  /* If the file count is larger then something went wrong */
5236  else if (file_zone_count > db_zone_count) {
5237  printf("Failed to add all zones from zonelist\n");
5238  StrFree(zone_ids);
5239  return(1);
5240  }
5241 
5242  /* If we get here we need to do some deleting, get each zone in the db
5243  * and see if it is in the zone_list that we built earlier */
5244  /* In case there are thousands of zones we don't use an "IN" clause*/
5245  sql = DqsSpecifyInit(DB_ZONE_TABLE, "id, name, policy_id");
5246  DqsOrderBy(&sql, "ID");
5247  DqsEnd(&sql);
5248 
5249  status = DbExecuteSql(DbHandle(), sql, &result);
5250 
5251  if (status == 0) {
5252  status = DbFetchRow(result, &row);
5253  while (status == 0) {
5254  DbInt(row, 0, &temp_id);
5255  DbString(row, 1, &zone_name);
5256  DbInt(row, 2, &policy_id);
5257 
5258  seen_zone = 0;
5259  for (i = 0; i < db_zone_count; ++i) {
5260  if (temp_id == zone_ids[i]) {
5261  seen_zone = 1;
5262  break;
5263  }
5264  }
5265 
5266  if (seen_zone == 0) {
5267  /* We need to delete this zone */
5268  /* Get the shared_keys parameter */
5269  printf("Removing zone %s from database\n", zone_name);
5270 
5271  status = KsmParameterInit(&result2, "zones_share_keys", "keys", policy_id);
5272  if (status != 0) {
5273  DbFreeRow(row);
5274  DbStringFree(zone_name);
5275  StrFree(zone_ids);
5276  return(status);
5277  }
5278  status = KsmParameter(result2, &shared);
5279  if (status != 0) {
5280  DbFreeRow(row);
5281  DbStringFree(zone_name);
5282  StrFree(zone_ids);
5283  return(status);
5284  }
5285  KsmParameterEnd(result2);
5286 
5287  /* how many zones on this policy (needed to unlink keys) */
5288  status = KsmZoneCountInit(&result3, policy_id);
5289  if (status == 0) {
5290  status = KsmZoneCount(result3, &temp_count);
5291  }
5292  DbFreeResult(result3);
5293 
5294  /* Mark keys as dead if appropriate */
5295  if ((shared.value == 1 && temp_count == 1) || shared.value == 0) {
5296  status = KsmMarkKeysAsDead(temp_id);
5297  if (status != 0) {
5298  printf("Error: failed to mark keys as dead in database\n");
5299  StrFree(zone_ids);
5300  return(status);
5301  }
5302  }
5303 
5304  /* Finally, we can delete the zone (and any dnsseckeys entries) */
5305  status = KsmDeleteZone(temp_id);
5306  }
5307 
5308  status = DbFetchRow(result, &row);
5309  }
5310  /* Convert EOF status to success */
5311 
5312  if (status == -1) {
5313  status = 0;
5314  }
5315  DbFreeResult(result);
5316  }
5317 
5318  DusFree(sql);
5319  DbFreeRow(row);
5320  DbStringFree(zone_name);
5321  StrFree(zone_ids);
5322 
5323  return 0;
5324 }
5325 
5326 /*
5327  * This encapsulates all of the steps needed to insert/update a parameter value
5328  * try to update the policy value, if it has changed
5329  * TODO possible bug where parmeters which have a value of 0 are not written (because we
5330  * only write what looks like it has changed
5331  */
5332 int SetParamOnPolicy(const xmlChar* new_value, const char* name, const char* category, int current_value, int policy_id, int value_type)
5333 {
5334  int status = 0;
5335  int value = 0;
5336  char* temp_char = (char *)new_value;
5337 
5338  /* extract the value into an int */
5339  if (value_type == DURATION_TYPE) {
5340  if (strlen(temp_char) != 0) {
5341  status = DtXMLIntervalSeconds(temp_char, &value);
5342  if (status > 0) {
5343  printf("Error: unable to convert interval %s to seconds, error: %i\n", temp_char, status);
5344  StrFree(temp_char);
5345  return status;
5346  }
5347  else if (status == -1) {
5348  printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char);
5349  }
5350  StrFree(temp_char);
5351  } else {
5352  value = -1;
5353  }
5354  }
5355  else if (value_type == BOOL_TYPE) {
5356  /* Do we have an empty tag or no tag? */
5357  if (strncmp(temp_char, "Y", 1) == 0) {
5358  value = 1;
5359  } else {
5360  value = 0;
5361  }
5362  }
5363  else if (value_type == REPO_TYPE) {
5364  /* We need to convert the repository name into an id */
5365  status = KsmSmIdFromName(temp_char, &value);
5366  if (status != 0) {
5367  printf("Error: unable to find repository %s\n", temp_char);
5368  StrFree(temp_char);
5369  return status;
5370  }
5371  StrFree(temp_char);
5372  }
5373  else if (value_type == SERIAL_TYPE) {
5374  /* We need to convert the serial name into an id */
5375  status = KsmSerialIdFromName(temp_char, &value);
5376  if (status != 0) {
5377  printf("Error: unable to find serial type %s\n", temp_char);
5378  StrFree(temp_char);
5379  return status;
5380  }
5381  StrFree(temp_char);
5382  }
5383  else if (value_type == ROLLOVER_TYPE) {
5384  /* We need to convert the rollover scheme name into an id */
5385  value = KsmKeywordRollNameToValue(temp_char);
5386  if (value == 0) {
5387  printf("Error: unable to find rollover scheme %s\n", temp_char);
5388  StrFree(temp_char);
5389  return status;
5390  }
5391  StrFree(temp_char);
5392  }
5393  else {
5394  status = StrStrtoi(temp_char, &value);
5395  if (status != 0) {
5396  printf("Error: unable to convert %s to int\n", temp_char);
5397  StrFree(temp_char);
5398  return status;
5399  }
5400  if (value_type != INT_TYPE_NO_FREE) {
5401  StrFree(temp_char);
5402  }
5403  }
5404 
5405  /* Now update the policy with what we found, if it is different */
5406  if (value != current_value || current_value == 0) {
5407  status = KsmParameterSet(name, category, value, policy_id);
5408  if (status != 0) {
5409  printf("Error: unable to insert/update %s for policy\n", name);
5410  printf("Error: Is your database schema up to date?\n");
5411  return status;
5412  }
5413 
5414  /* Special step if salt length changed make sure that the salt is
5415  regenerated when the enforcer runs next */
5416  if (strncmp(name, "saltlength", 10) == 0) {
5417  status = KsmPolicyNullSaltStamp(policy_id);
5418  if (status != 0) {
5419  printf("Error: unable to insert/update %s for policy\n", name);
5420  printf("Error: Is your database schema up to date?\n");
5421  return status;
5422  }
5423  }
5424  }
5425 
5426  return 0;
5427 }
5428 
5429 void SetPolicyDefaults(KSM_POLICY *policy, char *name)
5430 {
5431  if (policy == NULL) {
5432  printf("Error, no policy provided");
5433  return;
5434  }
5435 
5436  if (name) {
5437  snprintf(policy->name, KSM_NAME_LENGTH, "%s", name);
5438  }
5439 
5440  policy->signer->refresh = 0;
5441  policy->signer->jitter = 0;
5442  policy->signer->propdelay = 0;
5443  policy->signer->soamin = 0;
5444  policy->signer->soattl = 0;
5445  policy->signer->serial = 0;
5446 
5447  policy->signature->clockskew = 0;
5448  policy->signature->resign = 0;
5449  policy->signature->valdefault = 0;
5450  policy->signature->valdenial = 0;
5451 
5452  policy->denial->version = 0;
5453  policy->denial->resalt = 0;
5454  policy->denial->algorithm = 0;
5455  policy->denial->iteration = 0;
5456  policy->denial->optout = 0;
5457  policy->denial->ttl = 0;
5458  policy->denial->saltlength = 0;
5459 
5460  policy->keys->ttl = 0;
5461  policy->keys->retire_safety = 0;
5462  policy->keys->publish_safety = 0;
5463  policy->keys->share_keys = 0;
5464  policy->keys->purge = -1;
5465 
5466  policy->ksk->algorithm = 0;
5467  policy->ksk->bits = 0;
5468  policy->ksk->lifetime = 0;
5469  policy->ksk->sm = 0;
5470  policy->ksk->overlap = 0;
5471  policy->ksk->ttl = 0;
5472  policy->ksk->rfc5011 = 0;
5473  policy->ksk->type = KSM_TYPE_KSK;
5474  policy->ksk->standby_keys = 0;
5475  policy->ksk->manual_rollover = 0;
5477 
5478  policy->zsk->algorithm = 0;
5479  policy->zsk->bits = 0;
5480  policy->zsk->lifetime = 0;
5481  policy->zsk->sm = 0;
5482  policy->zsk->overlap = 0;
5483  policy->zsk->ttl = 0;
5484  policy->zsk->rfc5011 = 0;
5485  policy->zsk->type = KSM_TYPE_ZSK;
5486  policy->zsk->standby_keys = 0;
5487  policy->zsk->manual_rollover = 0;
5488  policy->zsk->rollover_scheme = 0;
5489 
5490  policy->enforcer->keycreate = 0;
5491  policy->enforcer->backup_interval = 0;
5492  policy->enforcer->keygeninterval = 0;
5493 
5494  policy->zone->propdelay = 0;
5495  policy->zone->soa_ttl = 0;
5496  policy->zone->soa_min = 0;
5497  policy->zone->serial = 0;
5498 
5499  policy->parent->propdelay = 0;
5500  policy->parent->ds_ttl = 0;
5501  policy->parent->soa_ttl = 0;
5502  policy->parent->soa_min = 0;
5503 
5504 }
5505 
5506 /* make a backup of a file
5507  * Returns 0 on success
5508  * 1 on error
5509  * -1 if it could read the original but not open the backup
5510  */
5511 int backup_file(const char* orig_file, const char* backup_file)
5512 {
5513  FILE *from, *to;
5514  int ch;
5515 
5516  errno = 0;
5517  /* open source file */
5518  if((from = fopen( orig_file, "rb"))==NULL) {
5519  if (errno == ENOENT) {
5520  printf("File %s does not exist, nothing to backup\n", orig_file);
5521  return(0);
5522  }
5523  else {
5524  printf("Cannot open source file.\n");
5525  return(1); /* No point in trying to connect */
5526  }
5527  }
5528 
5529  /* open destination file */
5530  if((to = fopen(backup_file, "wb"))==NULL) {
5531  printf("Cannot open destination file, will not make backup.\n");
5532  fclose(from);
5533  return(-1);
5534  }
5535  else {
5536  /* copy the file */
5537  while(!feof(from)) {
5538  ch = fgetc(from);
5539  if(ferror(from)) {
5540  printf("Error reading source file.\n");
5541  fclose(from);
5542  fclose(to);
5543  return(1);
5544  }
5545  if(!feof(from)) fputc(ch, to);
5546  if(ferror(to)) {
5547  printf("Error writing destination file.\n");
5548  fclose(from);
5549  fclose(to);
5550  return(1);
5551  }
5552  }
5553 
5554  if(fclose(from)==EOF) {
5555  printf("Error closing source file.\n");
5556  fclose(to);
5557  return(1);
5558  }
5559 
5560  if(fclose(to)==EOF) {
5561  printf("Error closing destination file.\n");
5562  return(1);
5563  }
5564  }
5565  return(0);
5566 }
5567 
5568 /*
5569  * Given a conf.xml location extract the database details contained within it
5570  *
5571  * The caller will need to StrFree the char**s passed in
5572  *
5573  * Returns 0 if a full set of details was found
5574  * 1 if something didn't look right
5575  * -1 if any of the config files could not be read/parsed
5576  *
5577  */
5578  int
5579 get_db_details(char** dbschema, char** host, char** port, char** user, char** password)
5580 {
5581  /* All of the XML stuff */
5582  xmlDocPtr doc;
5583  xmlDocPtr rngdoc;
5584  xmlXPathContextPtr xpathCtx;
5585  xmlXPathObjectPtr xpathObj;
5586  xmlRelaxNGParserCtxtPtr rngpctx;
5587  xmlRelaxNGValidCtxtPtr rngctx;
5588  xmlRelaxNGPtr schema;
5589  xmlChar *litexpr = (unsigned char*) "//Configuration/Enforcer/Datastore/SQLite";
5590  xmlChar *mysql_host = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host";
5591  xmlChar *mysql_port = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Host/@port";
5592  xmlChar *mysql_db = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Database";
5593  xmlChar *mysql_user = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Username";
5594  xmlChar *mysql_pass = (unsigned char*) "//Configuration/Enforcer/Datastore/MySQL/Password";
5595 
5596  int status;
5597  int db_found = 0;
5598  char* temp_char = NULL;
5599 
5600  /* Some files, the xml and rng */
5601  const char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
5602 
5603  /* Load XML document */
5604  doc = xmlParseFile(config);
5605  if (doc == NULL) {
5606  printf("Error: unable to parse file \"%s\"\n", config);
5607  return(-1);
5608  }
5609 
5610  /* Load rng document: TODO make the rng stuff optional? */
5611  rngdoc = xmlParseFile(rngfilename);
5612  if (rngdoc == NULL) {
5613  printf("Error: unable to parse file \"%s\"\n", rngfilename);
5614  xmlFreeDoc(doc);
5615  return(-1);
5616  }
5617 
5618  /* Create an XML RelaxNGs parser context for the relax-ng document. */
5619  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
5620  xmlFreeDoc(rngdoc);
5621  if (rngpctx == NULL) {
5622  printf("Error: unable to create XML RelaxNGs parser context\n");
5623  xmlFreeDoc(doc);
5624  return(-1);
5625  }
5626 
5627  /* parse a schema definition resource and build an internal XML Schema structure which can be used to validate instances. */
5628  schema = xmlRelaxNGParse(rngpctx);
5629  xmlRelaxNGFreeParserCtxt(rngpctx);
5630  if (schema == NULL) {
5631  printf("Error: unable to parse a schema definition resource\n");
5632  xmlFreeDoc(doc);
5633  return(-1);
5634  }
5635 
5636  /* Create an XML RelaxNGs validation context based on the given schema */
5637  rngctx = xmlRelaxNGNewValidCtxt(schema);
5638  if (rngctx == NULL) {
5639  printf("Error: unable to create RelaxNGs validation context based on the schema\n");
5640  xmlRelaxNGFree(schema);
5641  xmlFreeDoc(doc);
5642  return(-1);
5643  }
5644 
5645  /* Validate a document tree in memory. */
5646  status = xmlRelaxNGValidateDoc(rngctx,doc);
5647  xmlRelaxNGFreeValidCtxt(rngctx);
5648  xmlRelaxNGFree(schema);
5649  if (status != 0) {
5650  printf("Error validating file \"%s\"\n", config);
5651  xmlFreeDoc(doc);
5652  return(-1);
5653  }
5654 
5655  /* Now parse a value out of the conf */
5656  /* Create xpath evaluation context */
5657  xpathCtx = xmlXPathNewContext(doc);
5658  if(xpathCtx == NULL) {
5659  printf("Error: unable to create new XPath context\n");
5660  xmlFreeDoc(doc);
5661  return(-1);
5662  }
5663 
5664  /* Evaluate xpath expression for SQLite file location */
5665  xpathObj = xmlXPathEvalExpression(litexpr, xpathCtx);
5666  if(xpathObj == NULL) {
5667  printf("Error: unable to evaluate xpath expression: %s\n", litexpr);
5668  xmlXPathFreeContext(xpathCtx);
5669  xmlFreeDoc(doc);
5670  return(-1);
5671  }
5672  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
5673  db_found = SQLITE_DB;
5674  temp_char = (char *)xmlXPathCastToString(xpathObj);
5675  StrAppend(dbschema, temp_char);
5676  StrFree(temp_char);
5677  if (verbose_flag) {
5678  fprintf(stderr, "SQLite database set to: %s\n", *dbschema);
5679  }
5680  }
5681  xmlXPathFreeObject(xpathObj);
5682 
5683  if (db_found == 0) {
5684  db_found = MYSQL_DB;
5685 
5686  /* Get all of the MySQL stuff read in too */
5687  /* HOST, optional */
5688  xpathObj = xmlXPathEvalExpression(mysql_host, xpathCtx);
5689  if(xpathObj == NULL) {
5690  printf("Error: unable to evaluate xpath expression: %s\n", mysql_host);
5691  xmlXPathFreeContext(xpathCtx);
5692  xmlFreeDoc(doc);
5693  return(-1);
5694  }
5695  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
5696  temp_char = (char *)xmlXPathCastToString(xpathObj);
5697  StrAppend(host, temp_char);
5698  StrFree(temp_char);
5699  if (verbose_flag) {
5700  fprintf(stderr, "MySQL database host set to: %s\n", *host);
5701  }
5702  }
5703  xmlXPathFreeObject(xpathObj);
5704 
5705  /* PORT, optional */
5706  xpathObj = xmlXPathEvalExpression(mysql_port, xpathCtx);
5707  if(xpathObj == NULL) {
5708  printf("Error: unable to evaluate xpath expression: %s\n", mysql_port);
5709  xmlXPathFreeContext(xpathCtx);
5710  xmlFreeDoc(doc);
5711  return(-1);
5712  }
5713  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
5714  temp_char = (char *)xmlXPathCastToString(xpathObj);
5715  StrAppend(port, temp_char);
5716  StrFree(temp_char);
5717  if (verbose_flag) {
5718  fprintf(stderr, "MySQL database port set to: %s\n", *port);
5719  }
5720  }
5721  xmlXPathFreeObject(xpathObj);
5722 
5723  /* SCHEMA */
5724  xpathObj = xmlXPathEvalExpression(mysql_db, xpathCtx);
5725  if(xpathObj == NULL) {
5726  printf("Error: unable to evaluate xpath expression: %s\n", mysql_db);
5727  xmlXPathFreeContext(xpathCtx);
5728  xmlFreeDoc(doc);
5729  return(-1);
5730  }
5731  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
5732  temp_char = (char *)xmlXPathCastToString(xpathObj);
5733  StrAppend(dbschema, temp_char);
5734  StrFree(temp_char);
5735  if (verbose_flag) {
5736  fprintf(stderr, "MySQL database schema set to: %s\n", *dbschema);
5737  }
5738  } else {
5739  db_found = 0;
5740  }
5741  xmlXPathFreeObject(xpathObj);
5742 
5743  /* DB USER */
5744  xpathObj = xmlXPathEvalExpression(mysql_user, xpathCtx);
5745  if(xpathObj == NULL) {
5746  printf("Error: unable to evaluate xpath expression: %s\n", mysql_user);
5747  xmlXPathFreeContext(xpathCtx);
5748  xmlFreeDoc(doc);
5749  return(-1);
5750  }
5751  if(xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
5752  temp_char = (char *)xmlXPathCastToString(xpathObj);
5753  StrAppend(user, temp_char);
5754  StrFree(temp_char);
5755  if (verbose_flag) {
5756  fprintf(stderr, "MySQL database user set to: %s\n", *user);
5757  }
5758  } else {
5759  db_found = 0;
5760  }
5761  xmlXPathFreeObject(xpathObj);
5762 
5763  /* DB PASSWORD */
5764  xpathObj = xmlXPathEvalExpression(mysql_pass, xpathCtx);
5765  if(xpathObj == NULL) {
5766  printf("Error: unable to evaluate xpath expression: %s\n", mysql_pass);
5767  xmlXPathFreeContext(xpathCtx);
5768  xmlFreeDoc(doc);
5769  return(-1);
5770  }
5771  /* password may be blank */
5772  temp_char = (char *)xmlXPathCastToString(xpathObj);
5773  StrAppend(password, temp_char);
5774  StrFree(temp_char);
5775  xmlXPathFreeObject(xpathObj);
5776 
5777  if (verbose_flag) {
5778  fprintf(stderr, "MySQL database password set\n");
5779  }
5780 
5781  }
5782 
5783  xmlXPathFreeContext(xpathCtx);
5784  xmlFreeDoc(doc);
5785 
5786  /* Check that we found one or the other database */
5787  if(db_found == 0) {
5788  printf("Error: unable to find complete database connection expression\n");
5789  return(-1);
5790  }
5791 
5792  /* Check that we found the right database type */
5793  if (db_found != DbFlavour()) {
5794  printf("Error: database in config file does not match libksm\n");
5795  return(-1);
5796  }
5797 
5798  return(status);
5799 }
5800 
5801 /*
5802  * Read the conf.xml file, we will not validate as that was done as we read the database.
5803  * Instead we just extract the RepositoryList into the database and also learn the
5804  * location of the zonelist.
5805  */
5806 int read_zonelist_filename(char** zone_list_filename)
5807 {
5808  xmlTextReaderPtr reader = NULL;
5809  xmlDocPtr doc = NULL;
5810  xmlXPathContextPtr xpathCtx = NULL;
5811  xmlXPathObjectPtr xpathObj = NULL;
5812  int ret = 0; /* status of the XML parsing */
5813  char* temp_char = NULL;
5814  char* tag_name = NULL;
5815 
5816  xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
5817 
5818  /* Start reading the file; we will be looking for "Common" tags */
5819  reader = xmlNewTextReaderFilename(config);
5820  if (reader != NULL) {
5821  ret = xmlTextReaderRead(reader);
5822  while (ret == 1) {
5823  tag_name = (char*) xmlTextReaderLocalName(reader);
5824  /* Found <Common> */
5825  if (strncmp(tag_name, "Common", 6) == 0
5826  && xmlTextReaderNodeType(reader) == 1) {
5827 
5828  /* Expand this node and get the rest of the info with XPath */
5829  xmlTextReaderExpand(reader);
5830  doc = xmlTextReaderCurrentDoc(reader);
5831  if (doc == NULL) {
5832  printf("Error: can not read Common section\n");
5833  /* Don't return? try to parse the rest of the file? */
5834  ret = xmlTextReaderRead(reader);
5835  continue;
5836  }
5837 
5838  xpathCtx = xmlXPathNewContext(doc);
5839  if(xpathCtx == NULL) {
5840  printf("Error: can not create XPath context for Common section\n");
5841  /* Don't return? try to parse the rest of the file? */
5842  ret = xmlTextReaderRead(reader);
5843  continue;
5844  }
5845 
5846  /* Evaluate xpath expression for ZoneListFile */
5847  xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
5848  if(xpathObj == NULL) {
5849  printf("Error: unable to evaluate xpath expression: %s\n", zonelist_expr);
5850  /* Don't return? try to parse the rest of the file? */
5851  ret = xmlTextReaderRead(reader);
5852  continue;
5853  }
5854  *zone_list_filename = NULL;
5855  temp_char = (char *)xmlXPathCastToString(xpathObj);
5856  xmlXPathFreeObject(xpathObj);
5857  StrAppend(zone_list_filename, temp_char);
5858  StrFree(temp_char);
5859  printf("zonelist filename set to %s.\n", *zone_list_filename);
5860  }
5861  /* Read the next line */
5862  ret = xmlTextReaderRead(reader);
5863  StrFree(tag_name);
5864  }
5865  xmlFreeTextReader(reader);
5866  if (ret != 0) {
5867  printf("%s : failed to parse\n", config);
5868  return(1);
5869  }
5870  } else {
5871  printf("Unable to open %s\n", config);
5872  return(1);
5873  }
5874  if (xpathCtx) {
5875  xmlXPathFreeContext(xpathCtx);
5876  }
5877  if (doc) {
5878  xmlFreeDoc(doc);
5879  }
5880 
5881  return 0;
5882 }
5883 
5884 xmlDocPtr add_zone_node(const char *docname,
5885  const char *zone_name,
5886  const char *policy_name,
5887  const char *sig_conf_name,
5888  const char *input_name,
5889  const char *output_name)
5890 {
5891  xmlDocPtr doc;
5892  xmlNodePtr cur;
5893  xmlNodePtr newzonenode;
5894  xmlNodePtr newadaptnode;
5895  xmlNodePtr newinputnode;
5896  xmlNodePtr newoutputnode;
5897  doc = xmlParseFile(docname);
5898  if (doc == NULL ) {
5899  fprintf(stderr,"Document not parsed successfully. \n");
5900  return (NULL);
5901  }
5902  cur = xmlDocGetRootElement(doc);
5903  if (cur == NULL) {
5904  fprintf(stderr,"empty document\n");
5905  xmlFreeDoc(doc);
5906  return (NULL);
5907  }
5908  if (xmlStrcmp(cur->name, (const xmlChar *) "ZoneList")) {
5909  fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
5910  xmlFreeDoc(doc);
5911  return (NULL);
5912  }
5913  newzonenode = xmlNewTextChild(cur, NULL, (const xmlChar *)"Zone", NULL);
5914  (void) xmlNewProp(newzonenode, (const xmlChar *)"name", (const xmlChar *)zone_name);
5915 
5916  (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"Policy", (const xmlChar *)policy_name);
5917 
5918  (void) xmlNewTextChild (newzonenode, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)sig_conf_name);
5919 
5920  newadaptnode = xmlNewChild (newzonenode, NULL, (const xmlChar *)"Adapters", NULL);
5921 
5922  newinputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Input", NULL);
5923 
5924  (void) xmlNewTextChild (newinputnode, NULL, (const xmlChar *)"File", (const xmlChar *)input_name);
5925 
5926  newoutputnode = xmlNewChild (newadaptnode, NULL, (const xmlChar *)"Output", NULL);
5927 
5928  (void) xmlNewTextChild (newoutputnode, NULL, (const xmlChar *)"File", (const xmlChar *)output_name);
5929 
5930  return(doc);
5931 }
5932 
5933 xmlDocPtr del_zone_node(const char *docname,
5934  const char *zone_name)
5935 {
5936  xmlDocPtr doc;
5937  xmlNodePtr root;
5938  xmlNodePtr cur;
5939 
5940  doc = xmlParseFile(docname);
5941  if (doc == NULL ) {
5942  fprintf(stderr,"Document not parsed successfully. \n");
5943  return (NULL);
5944  }
5945  root = xmlDocGetRootElement(doc);
5946  if (root == NULL) {
5947  fprintf(stderr,"empty document\n");
5948  xmlFreeDoc(doc);
5949  return (NULL);
5950  }
5951  if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
5952  fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
5953  xmlFreeDoc(doc);
5954  return (NULL);
5955  }
5956 
5957  /* If we are removing all zones then just replace the root node with an empty one */
5958  if (all_flag == 1) {
5959  cur = root->children;
5960  while (cur != NULL)
5961  {
5962  xmlUnlinkNode(cur);
5963  xmlFreeNode(cur);
5964 
5965  cur = root->children;
5966  }
5967  }
5968  else {
5969 
5970  /* Zone nodes are children of the root */
5971  for(cur = root->children; cur != NULL; cur = cur->next)
5972  {
5973  /* is this the zone we are looking for? */
5974  if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) zone_name) == 0)
5975  {
5976  xmlUnlinkNode(cur);
5977 
5978  cur = root->children; /* May pass through multiple times, but will remove all instances of the zone */
5979  }
5980  }
5981  xmlFreeNode(cur);
5982  }
5983 
5984  return(doc);
5985 }
5986 
5987 void list_zone_node(const char *docname, int *zone_ids)
5988 {
5989  xmlDocPtr doc;
5990  xmlNodePtr root;
5991  xmlNodePtr cur;
5992  xmlNodePtr pol;
5993  xmlChar *polChar = NULL;
5994  xmlChar *propChar = NULL;
5995 
5996  int temp_id;
5997  int i = 0;
5998  int status = 0;
5999 
6000  doc = xmlParseFile(docname);
6001  if (doc == NULL ) {
6002  fprintf(stderr,"Document not parsed successfully. \n");
6003  return;
6004  }
6005  root = xmlDocGetRootElement(doc);
6006  if (root == NULL) {
6007  fprintf(stderr,"empty document\n");
6008  xmlFreeDoc(doc);
6009  return;
6010  }
6011  if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
6012  fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
6013  xmlFreeDoc(doc);
6014  return;
6015  }
6016 
6017  /* Zone nodes are children of the root */
6018  for(cur = root->children; cur != NULL; cur = cur->next)
6019  {
6020  if (xmlStrcmp( cur->name, (const xmlChar *)"Zone") == 0) {
6021  propChar = xmlGetProp(cur, (xmlChar *) "name");
6022  printf("Found Zone: %s", propChar);
6023 
6024  /* make a note of the zone_id */
6025  status = KsmZoneIdFromName((char *) propChar, &temp_id);
6026  xmlFree(propChar);
6027  if (status != 0) {
6028  printf(" (zone not in database)");
6029  zone_ids[i] = 0;
6030  } else {
6031  zone_ids[i] = temp_id;
6032  i++;
6033  }
6034 
6035  /* Print the policy name for this zone */
6036  for(pol = cur->children; pol != NULL; pol = pol->next)
6037  {
6038  if (xmlStrcmp( pol->name, (const xmlChar *)"Policy") == 0)
6039  {
6040  polChar = xmlNodeGetContent(pol);
6041  printf("; on policy %s\n", polChar);
6042  xmlFree(polChar);
6043  }
6044  }
6045  }
6046  }
6047 
6048  xmlFreeDoc(doc);
6049 
6050  return;
6051 }
6052 
6053 /*
6054  * Given a doc that has the start of the kasp-like xml and a policy structure
6055  * create the policy tag and contents in that doc
6056  */
6057 int append_policy(xmlDocPtr doc, KSM_POLICY *policy)
6058 {
6059  xmlNodePtr root;
6060  xmlNodePtr policy_node;
6061  xmlNodePtr signatures_node;
6062  xmlNodePtr validity_node;
6063  xmlNodePtr denial_node;
6064  xmlNodePtr nsec_node;
6065  xmlNodePtr hash_node;
6066  xmlNodePtr salt_node;
6067  xmlNodePtr keys_node;
6068  xmlNodePtr ksk_node;
6069  xmlNodePtr ksk_alg_node;
6070  xmlNodePtr zsk_node;
6071  xmlNodePtr zsk_alg_node;
6072  xmlNodePtr zone_node;
6073  xmlNodePtr zone_soa_node;
6074  xmlNodePtr parent_node;
6075  xmlNodePtr parent_ds_node;
6076  xmlNodePtr parent_soa_node;
6077 
6078  char temp_time[32];
6079 
6080  root = xmlDocGetRootElement(doc);
6081  if (root == NULL) {
6082  fprintf(stderr,"empty document\n");
6083  return(1);
6084  }
6085  if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) {
6086  fprintf(stderr,"document of the wrong type, root node != %s", "KASP");
6087  return(1);
6088  }
6089 
6090  policy_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Policy", NULL);
6091  (void) xmlNewProp(policy_node, (const xmlChar *)"name", (const xmlChar *)policy->name);
6092  (void) xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Description", (const xmlChar *)policy->description);
6093 
6094  /* SIGNATURES */
6095  signatures_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Signatures", NULL);
6096  snprintf(temp_time, 32, "PT%dS", policy->signature->resign);
6097  (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Resign", (const xmlChar *)temp_time);
6098  snprintf(temp_time, 32, "PT%dS", policy->signer->refresh);
6099  (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Refresh", (const xmlChar *)temp_time);
6100  validity_node = xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Validity", NULL);
6101  snprintf(temp_time, 32, "PT%dS", policy->signature->valdefault);
6102  (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Default", (const xmlChar *)temp_time);
6103  snprintf(temp_time, 32, "PT%dS", policy->signature->valdenial);
6104  (void) xmlNewTextChild(validity_node, NULL, (const xmlChar *)"Denial", (const xmlChar *)temp_time);
6105  snprintf(temp_time, 32, "PT%dS", policy->signer->jitter);
6106  (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"Jitter", (const xmlChar *)temp_time);
6107  snprintf(temp_time, 32, "PT%dS", policy->signature->clockskew);
6108  (void) xmlNewTextChild(signatures_node, NULL, (const xmlChar *)"InceptionOffset", (const xmlChar *)temp_time);
6109 
6110  /* DENIAL */
6111  denial_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Denial", NULL);
6112  if (policy->denial->version == 1) /* NSEC */
6113  {
6114  (void) xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC", NULL);
6115  }
6116  else /* NSEC3 */
6117  {
6118  nsec_node = xmlNewTextChild(denial_node, NULL, (const xmlChar *)"NSEC3", NULL);
6119  if (policy->denial->optout == 1)
6120  {
6121  (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"OptOut", NULL);
6122  }
6123  snprintf(temp_time, 32, "PT%dS", policy->denial->resalt);
6124  (void) xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Resalt", (const xmlChar *)temp_time);
6125  hash_node = xmlNewTextChild(nsec_node, NULL, (const xmlChar *)"Hash", NULL);
6126  snprintf(temp_time, 32, "%d", policy->denial->algorithm);
6127  (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
6128  snprintf(temp_time, 32, "%d", policy->denial->iteration);
6129  (void) xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Iteration", (const xmlChar *)temp_time);
6130  snprintf(temp_time, 32, "%d", policy->denial->saltlength);
6131  salt_node = xmlNewTextChild(hash_node, NULL, (const xmlChar *)"Salt", NULL);
6132  (void) xmlNewProp(salt_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
6133  }
6134 
6135  /* KEYS */
6136  keys_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Keys", NULL);
6137  snprintf(temp_time, 32, "PT%dS", policy->keys->ttl);
6138  (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
6139  snprintf(temp_time, 32, "PT%dS", policy->keys->retire_safety);
6140  (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"RetireSafety", (const xmlChar *)temp_time);
6141  snprintf(temp_time, 32, "PT%dS", policy->keys->publish_safety);
6142  (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"PublishSafety", (const xmlChar *)temp_time);
6143  if (policy->keys->share_keys == 1)
6144  {
6145  (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ShareKeys", NULL);
6146  }
6147  if (policy->keys->purge != -1) {
6148  snprintf(temp_time, 32, "PT%dS", policy->keys->purge);
6149  (void) xmlNewTextChild(keys_node, NULL, (const xmlChar *)"Purge", (const xmlChar *)temp_time);
6150  }
6151  /*(void) xmlNewDocComment(doc, (const xmlChar *)"Parameters that are different for zsks and ksks");*/
6152  /* KSK */
6153  ksk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"KSK", NULL);
6154  snprintf(temp_time, 32, "%d", policy->ksk->algorithm);
6155  ksk_alg_node = xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
6156  snprintf(temp_time, 32, "%d", policy->ksk->bits);
6157  (void) xmlNewProp(ksk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
6158  snprintf(temp_time, 32, "PT%dS", policy->ksk->lifetime);
6159  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time);
6160  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->ksk->sm_name);
6161  snprintf(temp_time, 32, "%d", policy->ksk->standby_keys);
6162  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time);
6163  if (policy->ksk->manual_rollover == 1)
6164  {
6165  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"ManualRollover", NULL);
6166  }
6167  if (policy->ksk->rfc5011 == 1)
6168  {
6169  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RFC5011", NULL);
6170  }
6171 /* if (policy->ksk->rollover_scheme != 0)
6172  {
6173  (void) xmlNewTextChild(ksk_node, NULL, (const xmlChar *)"RolloverScheme", (const xmlChar *) KsmKeywordRollValueToName(policy->ksk->rollover_scheme));
6174  }*/
6175 
6176  /* ZSK */
6177  zsk_node = xmlNewTextChild(keys_node, NULL, (const xmlChar *)"ZSK", NULL);
6178  snprintf(temp_time, 32, "%d", policy->zsk->algorithm);
6179  zsk_alg_node = xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Algorithm", (const xmlChar *)temp_time);
6180  snprintf(temp_time, 32, "%d", policy->zsk->bits);
6181  (void) xmlNewProp(zsk_alg_node, (const xmlChar *)"length", (const xmlChar *)temp_time);
6182  snprintf(temp_time, 32, "PT%dS", policy->zsk->lifetime);
6183  (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Lifetime", (const xmlChar *)temp_time);
6184  (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Repository", (const xmlChar *)policy->zsk->sm_name);
6185  snprintf(temp_time, 32, "%d", policy->zsk->standby_keys);
6186  (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"Standby", (const xmlChar *)temp_time);
6187  if (policy->zsk->manual_rollover == 1)
6188  {
6189  (void) xmlNewTextChild(zsk_node, NULL, (const xmlChar *)"ManualRollover", NULL);
6190  }
6191 
6192  /* ZONE */
6193  zone_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Zone", NULL);
6194  snprintf(temp_time, 32, "PT%dS", policy->zone->propdelay);
6195  (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time);
6196  zone_soa_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SOA", NULL);
6197  snprintf(temp_time, 32, "PT%dS", policy->zone->soa_ttl);
6198  (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
6199  snprintf(temp_time, 32, "PT%dS", policy->zone->soa_min);
6200  (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time);
6201  (void) xmlNewTextChild(zone_soa_node, NULL, (const xmlChar *)"Serial", (const xmlChar *) KsmKeywordSerialValueToName(policy->zone->serial));
6202 
6203  /* PARENT */
6204  parent_node = xmlNewTextChild(policy_node, NULL, (const xmlChar *)"Parent", NULL);
6205  snprintf(temp_time, 32, "PT%dS", policy->parent->propdelay);
6206  (void) xmlNewTextChild(parent_node, NULL, (const xmlChar *)"PropagationDelay", (const xmlChar *)temp_time);
6207  parent_ds_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"DS", NULL);
6208  snprintf(temp_time, 32, "PT%dS", policy->parent->ds_ttl);
6209  (void) xmlNewTextChild(parent_ds_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
6210  parent_soa_node = xmlNewTextChild(parent_node, NULL, (const xmlChar *)"SOA", NULL);
6211  snprintf(temp_time, 32, "PT%dS", policy->parent->soa_ttl);
6212  (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"TTL", (const xmlChar *)temp_time);
6213  snprintf(temp_time, 32, "PT%dS", policy->parent->soa_min);
6214  (void) xmlNewTextChild(parent_soa_node, NULL, (const xmlChar *)"Minimum", (const xmlChar *)temp_time);
6215 
6216  /* AUDIT (Currently this either exists and is empty or it doesn't) */
6217  if (strncmp(policy->audit, "NULL", 4) != 0) {
6218  (void) xmlNewChild(policy_node, NULL, (const xmlChar *)"Audit", NULL);
6219  }
6220 
6221  return(0);
6222 }
6223 
6224 /*
6225  * Delete a policy node from kasp.xml
6226  */
6227 xmlDocPtr del_policy_node(const char *docname,
6228  const char *policy_name)
6229 {
6230  xmlDocPtr doc;
6231  xmlNodePtr root;
6232  xmlNodePtr cur;
6233 
6234  doc = xmlParseFile(docname);
6235  if (doc == NULL ) {
6236  fprintf(stderr,"Document not parsed successfully. \n");
6237  return (NULL);
6238  }
6239  root = xmlDocGetRootElement(doc);
6240  if (root == NULL) {
6241  fprintf(stderr,"empty document\n");
6242  xmlFreeDoc(doc);
6243  return (NULL);
6244  }
6245  if (xmlStrcmp(root->name, (const xmlChar *) "KASP")) {
6246  fprintf(stderr,"document of the wrong type, root node != %s", "KASP");
6247  xmlFreeDoc(doc);
6248  return (NULL);
6249  }
6250 
6251 
6252  /* Policy nodes are children of the root */
6253  for(cur = root->children; cur != NULL; cur = cur->next)
6254  {
6255  /* is this the zone we are looking for? */
6256  if (xmlStrcmp( xmlGetProp(cur, (xmlChar *) "name"), (const xmlChar *) policy_name) == 0)
6257  {
6258  xmlUnlinkNode(cur);
6259 
6260  cur = root->children; /* May pass through multiple times, but will remove all instances of the policy */
6261  }
6262  }
6263  xmlFreeNode(cur);
6264 
6265  return(doc);
6266 }
6267 
6268 /*
6269  * CallBack to print key info to stdout
6270  */
6271 int printKey(void* context, KSM_KEYDATA* key_data)
6272 {
6273  if (key_data->state == KSM_STATE_RETIRE && strcasecmp(key_data->retire, (char *)context) == 0) {
6274  if (key_data->keytype == KSM_TYPE_KSK)
6275  {
6276  fprintf(stdout, "KSK:");
6277  }
6278  if (key_data->keytype == KSM_TYPE_ZSK)
6279  {
6280  fprintf(stdout, "ZSK:");
6281  }
6282  fprintf(stdout, " %s Retired\n", key_data->location);
6283  }
6284 
6285  return 0;
6286 }
6287 
6288 /*
6289  * log function suitable for libksm callback
6290  */
6291  void
6292 ksm_log_msg(const char *format)
6293 {
6294  fprintf(stderr, "%s\n", format);
6295 }
6296 
6297 /*+
6298  * ListKeys - Output a list of Keys
6299  *
6300  *
6301  * Arguments:
6302  *
6303  * int zone_id
6304  * ID of the zone (-1 for all)
6305  *
6306  * Returns:
6307  * int
6308  * Status return. 0 on success.
6309  * other on fail
6310  */
6311 
6312 int ListKeys(int zone_id)
6313 {
6314  char* sql = NULL; /* SQL query */
6315  int status = 0; /* Status return */
6316  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
6317  DB_RESULT result; /* Result of the query */
6318  DB_ROW row = NULL; /* Row data */
6319  int done_row = 0; /* Have we printed a row this loop? */
6320 
6321  char* temp_zone = NULL; /* place to store zone name returned */
6322  int temp_type = 0; /* place to store key type returned */
6323  int temp_state = 0; /* place to store key state returned */
6324  char* temp_ready = NULL; /* place to store ready date returned */
6325  char* temp_active = NULL; /* place to store active date returned */
6326  char* temp_retire = NULL; /* place to store retire date returned */
6327  char* temp_dead = NULL; /* place to store dead date returned */
6328  char* temp_loc = NULL; /* place to store location returned */
6329  char* temp_hsm = NULL; /* place to store hsm returned */
6330  int temp_alg = 0; /* place to store algorithm returned */
6331 
6332  /* Key information */
6333  hsm_key_t *key = NULL;
6334  ldns_rr *dnskey_rr = NULL;
6335  hsm_sign_params_t *sign_params = NULL;
6336 
6337  if (verbose_flag) {
6338  /* connect to the HSM */
6339  status = hsm_open(config, hsm_prompt_pin, NULL);
6340  if (status) {
6341  hsm_print_error(NULL);
6342  return(-1);
6343  }
6344  }
6345 
6346  /* Select rows */
6347  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 ");
6348  if (zone_id != -1) {
6349  StrAppend(&sql, "and zone_id = ");
6350  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
6351  StrAppend(&sql, stringval);
6352  }
6353  StrAppend(&sql, " order by zone_id");
6354 
6355  DusEnd(&sql);
6356 
6357  status = DbExecuteSql(DbHandle(), sql, &result);
6358 
6359  if (status == 0) {
6360  status = DbFetchRow(result, &row);
6361  if (verbose_flag == 1) {
6362  printf("Zone: Keytype: State: Date of next transition: CKA_ID: Repository: Keytag:\n");
6363  }
6364  else {
6365  printf("Zone: Keytype: State: Date of next transition:\n");
6366  }
6367  while (status == 0) {
6368  /* Got a row, print it */
6369  DbString(row, 0, &temp_zone);
6370  DbInt(row, 1, &temp_type);
6371  DbInt(row, 2, &temp_state);
6372  DbString(row, 3, &temp_ready);
6373  DbString(row, 4, &temp_active);
6374  DbString(row, 5, &temp_retire);
6375  DbString(row, 6, &temp_dead);
6376  DbString(row, 7, &temp_loc);
6377  DbString(row, 8, &temp_hsm);
6378  DbInt(row, 9, &temp_alg);
6379  done_row = 0;
6380 
6381  if (temp_state == KSM_STATE_PUBLISH) {
6382  printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready);
6383  done_row = 1;
6384  }
6385  else if (temp_state == KSM_STATE_READY) {
6386  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");
6387  done_row = 1;
6388  }
6389  else if (temp_state == KSM_STATE_ACTIVE) {
6390  printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_retire == NULL) ? "(not scheduled)" : temp_retire);
6391  done_row = 1;
6392  }
6393  else if (temp_state == KSM_STATE_RETIRE) {
6394  printf("%-31s %-13s %-9s %-26s", temp_zone, (temp_type == KSM_TYPE_KSK) ? "KSK" : "ZSK", KsmKeywordStateValueToName(temp_state), (temp_dead == NULL) ? "(not scheduled)" : temp_dead);
6395  done_row = 1;
6396  }
6397  else if (temp_state == KSM_STATE_DSSUB) {
6398  printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "waiting for ds-seen");
6399  done_row = 1;
6400  }
6401  else if (temp_state == KSM_STATE_DSPUBLISH) {
6402  printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_ready == NULL) ? "(not scheduled)" : temp_ready);
6403  done_row = 1;
6404  }
6405  else if (temp_state == KSM_STATE_DSREADY) {
6406  printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), "When required");
6407  done_row = 1;
6408  }
6409  else if (temp_state == KSM_STATE_KEYPUBLISH) {
6410  printf("%-31s %-13s %-9s %-26s", temp_zone, "KSK", KsmKeywordStateValueToName(temp_state), (temp_active == NULL) ? "(not scheduled)" : temp_active);
6411  done_row = 1;
6412  }
6413 
6414  if (done_row == 1 && verbose_flag == 1) {
6415  key = hsm_find_key_by_id(NULL, temp_loc);
6416  if (!key) {
6417  printf("%-33s %s NOT IN repository\n", temp_loc, temp_hsm);
6418  } else {
6419  sign_params = hsm_sign_params_new();
6420  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, temp_zone);
6421  sign_params->algorithm = temp_alg;
6422  sign_params->flags = LDNS_KEY_ZONE_KEY;
6423  if (temp_type == KSM_TYPE_KSK) {
6424  sign_params->flags += LDNS_KEY_SEP_KEY;
6425  }
6426  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
6427  sign_params->keytag = ldns_calc_keytag(dnskey_rr);
6428 
6429  printf("%-33s %-33s %d\n", temp_loc, temp_hsm, sign_params->keytag);
6430 
6431  hsm_sign_params_free(sign_params);
6432  hsm_key_free(key);
6433  }
6434  }
6435  else if (done_row == 1) {
6436  printf("\n");
6437  }
6438 
6439  status = DbFetchRow(result, &row);
6440  }
6441 
6442  /* Convert EOF status to success */
6443 
6444  if (status == -1) {
6445  status = 0;
6446  }
6447 
6448  DbFreeResult(result);
6449  }
6450 
6451  DusFree(sql);
6452  DbFreeRow(row);
6453 
6454  DbStringFree(temp_zone);
6455  DbStringFree(temp_ready);
6456  DbStringFree(temp_active);
6457  DbStringFree(temp_retire);
6458  DbStringFree(temp_dead);
6459  DbStringFree(temp_loc);
6460  DbStringFree(temp_hsm);
6461 
6462  if (dnskey_rr != NULL) {
6463  ldns_rr_free(dnskey_rr);
6464  }
6465 
6466  if (verbose_flag) {
6467  hsm_close();
6468  }
6469 
6470  return status;
6471 }
6472 
6473 /*+
6474  * PurgeKeys - Purge dead Keys
6475  *
6476  *
6477  * Arguments:
6478  *
6479  * int zone_id
6480  * ID of the zone
6481  *
6482  * int policy_id
6483  * ID of the policy
6484  *
6485  * N.B. Only one of the arguments should be set, the other should be -1
6486  *
6487  * Returns:
6488  * int
6489  * Status return. 0 on success.
6490  * other on fail
6491  */
6492 
6493 int PurgeKeys(int zone_id, int policy_id)
6494 {
6495  char* sql = NULL; /* SQL query */
6496  char* sql1 = NULL; /* SQL query */
6497  char* sql2 = NULL; /* SQL query */
6498  char* sql3 = NULL; /* SQL query */
6499  int status = 0; /* Status return */
6500  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
6501  DB_RESULT result; /* Result of the query */
6502  DB_ROW row = NULL; /* Row data */
6503 
6504  int temp_id = -1; /* place to store the key id returned */
6505  char* temp_loc = NULL; /* place to store location returned */
6506  int count = 0; /* How many keys don't match the purge */
6507 
6508  int done_something = 0; /* have we done anything? */
6509 
6510  /* Key information */
6511  hsm_key_t *key = NULL;
6512 
6513  if ((zone_id == -1 && policy_id == -1) ||
6514  (zone_id != -1 && policy_id != -1)){
6515  printf("Please provide either a zone OR a policy to key purge\n");
6516  usage_keypurge();
6517  return(1);
6518  }
6519 
6520  /* connect to the HSM */
6521  status = hsm_open(config, hsm_prompt_pin, NULL);
6522  if (status) {
6523  hsm_print_error(NULL);
6524  return(-1);
6525  }
6526 
6527  /* Select rows */
6528  StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 ");
6529  if (zone_id != -1) {
6530  StrAppend(&sql, "and zone_id = ");
6531  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
6532  StrAppend(&sql, stringval);
6533  }
6534  if (policy_id != -1) {
6535  StrAppend(&sql, "and policy_id = ");
6536  snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id);
6537  StrAppend(&sql, stringval);
6538  }
6539  DusEnd(&sql);
6540 
6541  status = DbExecuteSql(DbHandle(), sql, &result);
6542 
6543  if (status == 0) {
6544  status = DbFetchRow(result, &row);
6545  while (status == 0) {
6546  /* Got a row, check it */
6547  DbInt(row, 0, &temp_id);
6548  DbString(row, 1, &temp_loc);
6549 
6550  sql1 = DqsCountInit("dnsseckeys");
6551  DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
6552  DdsConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1);
6553  DqsEnd(&sql1);
6554 
6555  status = DbIntQuery(DbHandle(), &count, sql1);
6556  DqsFree(sql1);
6557 
6558  if (status != 0) {
6559  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
6560  DbStringFree(temp_loc);
6561  DbFreeRow(row);
6562  hsm_close();
6563  return status;
6564  }
6565 
6566  /* If the count is zero then there is no reason not to purge this key */
6567  if (count == 0) {
6568 
6569  done_something = 1;
6570 
6571  /* Delete from dnsseckeys */
6572  sql2 = DdsInit("dnsseckeys");
6573  DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
6574  DdsEnd(&sql);
6575 
6576  status = DbExecuteSqlNoResult(DbHandle(), sql2);
6577  DdsFree(sql2);
6578  if (status != 0)
6579  {
6580  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
6581  DbStringFree(temp_loc);
6582  DbFreeRow(row);
6583  hsm_close();
6584  return status;
6585  }
6586 
6587  /* Delete from keypairs */
6588  sql3 = DdsInit("keypairs");
6589  DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0);
6590  DdsEnd(&sql);
6591 
6592  status = DbExecuteSqlNoResult(DbHandle(), sql3);
6593  DdsFree(sql3);
6594  if (status != 0)
6595  {
6596  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
6597  DbStringFree(temp_loc);
6598  DbFreeRow(row);
6599  hsm_close();
6600  return status;
6601  }
6602 
6603  /* Delete from the HSM */
6604  key = hsm_find_key_by_id(NULL, temp_loc);
6605 
6606  if (!key) {
6607  printf("Key not found: %s\n", temp_loc);
6608  DbStringFree(temp_loc);
6609  DbFreeRow(row);
6610  hsm_close();
6611  return -1;
6612  }
6613 
6614  status = hsm_remove_key(NULL, key);
6615 
6616  hsm_key_free(key);
6617 
6618  if (!status) {
6619  printf("Key remove successful.\n");
6620  } else {
6621  printf("Key remove failed.\n");
6622  DbStringFree(temp_loc);
6623  DbFreeRow(row);
6624  hsm_close();
6625  return -1;
6626  }
6627  }
6628 
6629  /* NEXT! */
6630  status = DbFetchRow(result, &row);
6631  }
6632 
6633  /* Convert EOF status to success */
6634 
6635  if (status == -1) {
6636  status = 0;
6637  }
6638 
6639  DbFreeResult(result);
6640  }
6641 
6642  if (done_something == 0) {
6643  printf("No keys to purge.\n");
6644  }
6645 
6646  DusFree(sql);
6647  DbFreeRow(row);
6648 
6649  DbStringFree(temp_loc);
6650 
6651  hsm_close();
6652 
6653  return status;
6654 }
6655 
6657 {
6658  int status = 0;
6659 
6660  int interval = -1;
6661 
6662  KSM_POLICY* policy;
6663  hsm_ctx_t *ctx = NULL;
6664 
6665  char *rightnow;
6666  int i = 0;
6667  char *id;
6668  hsm_key_t *key = NULL;
6669  char *hsm_error_message = NULL;
6670  DB_ID ignore = 0;
6671  int ksks_needed = 0; /* Total No of ksks needed before next generation run */
6672  int zsks_needed = 0; /* Total No of zsks needed before next generation run */
6673  int keys_in_queue = 0; /* number of unused keys */
6674  int new_keys = 0; /* number of keys required */
6675  unsigned int current_count = 0; /* number of keys already in HSM */
6676 
6677  DB_RESULT result;
6678  int zone_count = 0; /* Number of zones on policy */
6679 
6680  int same_keys = 0; /* Do ksks and zsks look the same ? */
6681  int ksks_created = 0; /* Were any KSKs created? */
6682 
6683  /* Database connection details */
6684  DB_HANDLE dbhandle;
6685  FILE* lock_fd = NULL; /* This is the lock file descriptor for a SQLite DB */
6686 
6687  /* try to connect to the database */
6688  status = db_connect(&dbhandle, &lock_fd, 1);
6689  if (status != 0) {
6690  printf("Failed to connect to database\n");
6691  db_disconnect(lock_fd);
6692  return(1);
6693  }
6694 
6695  policy = KsmPolicyAlloc();
6696  if (policy == NULL) {
6697  printf("Malloc for policy struct failed\n");
6698  db_disconnect(lock_fd);
6699  exit(1);
6700  }
6701 
6702  if (o_policy == NULL) {
6703  printf("Please provide a policy name with the --policy option\n");
6704  db_disconnect(lock_fd);
6705  KsmPolicyFree(policy);
6706  return(1);
6707  }
6708  if (o_interval == NULL) {
6709  printf("Please provide an interval with the --interval option\n");
6710  db_disconnect(lock_fd);
6711  KsmPolicyFree(policy);
6712  return(1);
6713  }
6714 
6715  SetPolicyDefaults(policy, o_policy);
6716 
6717  status = KsmPolicyExists(o_policy);
6718  if (status == 0) {
6719  /* Policy exists */
6720  status = KsmPolicyRead(policy);
6721  if(status != 0) {
6722  printf("Error: unable to read policy %s from database\n", o_policy);
6723  db_disconnect(lock_fd);
6724  KsmPolicyFree(policy);
6725  return status;
6726  }
6727  } else {
6728  printf("Error: policy %s doesn't exist in database\n", o_policy);
6729  db_disconnect(lock_fd);
6730  KsmPolicyFree(policy);
6731  return status;
6732  }
6733 
6734  if (policy->shared_keys == 1 ) {
6735  printf("Key sharing is On\n");
6736  } else {
6737  printf("Key sharing is Off\n");
6738  }
6739 
6740  status = DtXMLIntervalSeconds(o_interval, &interval);
6741  if (status > 0) {
6742  printf("Error: unable to convert Interval %s to seconds, error: ", o_interval);
6743  switch (status) {
6744  case 1: /* This has gone away, will now return 2 */
6745  printf("invalid interval-type.\n");
6746  break;
6747  case 2:
6748  printf("unable to translate string.\n");
6749  break;
6750  case 3:
6751  printf("interval too long to be an int. E.g. Maximum is ~68 years on a system with 32-bit integers.\n");
6752  break;
6753  case 4:
6754  printf("invalid pointers or text string NULL.\n");
6755  break;
6756  default:
6757  printf("unknown\n");
6758  }
6759  db_disconnect(lock_fd);
6760  KsmPolicyFree(policy);
6761  return status;
6762  }
6763  else if (status == -1) {
6764  printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", o_interval);
6765  }
6766 
6767  /* Connect to the hsm */
6768  status = hsm_open(config, hsm_prompt_pin, NULL);
6769  if (status) {
6770  hsm_error_message = hsm_get_error(ctx);
6771  if (hsm_error_message) {
6772  printf("%s\n", hsm_error_message);
6773  free(hsm_error_message);
6774  } else {
6775  /* decode the error code ourselves
6776  TODO find if there is a better way to do this (and can all of these be returned? are there others?) */
6777  switch (status) {
6778  case HSM_ERROR:
6779  printf("hsm_open() result: HSM error\n");
6780  break;
6781  case HSM_PIN_INCORRECT:
6782  printf("hsm_open() result: incorrect PIN\n");
6783  break;
6784  case HSM_CONFIG_FILE_ERROR:
6785  printf("hsm_open() result: config file error\n");
6786  break;
6787  case HSM_REPOSITORY_NOT_FOUND:
6788  printf("hsm_open() result: repository not found\n");
6789  break;
6790  case HSM_NO_REPOSITORIES:
6791  printf("hsm_open() result: no repositories\n");
6792  break;
6793  default:
6794  printf("hsm_open() result: %d", status);
6795  }
6796  }
6797  db_disconnect(lock_fd);
6798  KsmPolicyFree(policy);
6799  exit(1);
6800  }
6801  printf("HSM opened successfully.\n");
6802  ctx = hsm_create_context();
6803 
6804  rightnow = DtParseDateTimeString("now");
6805 
6806  /* Check datetime in case it came back NULL */
6807  if (rightnow == NULL) {
6808  printf("Couldn't turn \"now\" into a date, quitting...\n");
6809  db_disconnect(lock_fd);
6810  KsmPolicyFree(policy);
6811  hsm_close();
6812  exit(1);
6813  }
6814 
6815  if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) {
6816  same_keys = 1;
6817  } else {
6818  same_keys = 0;
6819  }
6820 
6821  /* How many zones on this policy */
6822  status = KsmZoneCountInit(&result, policy->id);
6823  if (status == 0) {
6824  status = KsmZoneCount(result, &zone_count);
6825  }
6826  DbFreeResult(result);
6827 
6828  if (status != 0) {
6829  printf("Could not count zones on policy %s\n", policy->name);
6830  db_disconnect(lock_fd);
6831  if (ctx) {
6832  hsm_destroy_context(ctx);
6833  }
6834  hsm_close();
6835  KsmPolicyFree(policy);
6836  return status;
6837  }
6838  printf("Info: %d zone(s) found on policy \"%s\"\n", zone_count, policy->name);
6839 
6840  /* If the zone total has been specified manually then use this
6841  instead but report how it differs from the actual number of zones*/
6842  if (o_zonetotal) {
6843  /* Check the value is numeric*/
6844  if (StrIsDigits(o_zonetotal)) {
6845  status = StrStrtoi(o_zonetotal, &zone_count);
6846  if (status != 0) {
6847  printf("Error: Unable to convert zonetotal \"%s\"; to an integer\n", o_zonetotal);
6848  db_disconnect(lock_fd);
6849  KsmPolicyFree(policy);
6850  hsm_close();
6851  exit(1);
6852  }
6853  } else {
6854  printf("Error: zonetotal \"%s\"; should be numeric only\n", o_zonetotal);
6855  db_disconnect(lock_fd);
6856  KsmPolicyFree(policy);
6857  hsm_close();
6858  exit(1);
6859  }
6860  /* Check the value is greater than 0*/
6861  if (zone_count < 1) {
6862  printf("Error: zonetotal parameter value of %d is invalid - the value must be greater than 0\n", zone_count);
6863  db_disconnect(lock_fd);
6864  KsmPolicyFree(policy);
6865  hsm_close();
6866  exit(1);
6867  }
6868  printf("Info: Keys will actually be generated for a total of %d zone(s) as specified by zone total parameter\n", zone_count);
6869  }
6870  else {
6871  /* make sure that we have at least one zone */
6872  if (zone_count == 0) {
6873  printf("No zones on policy %s, skipping...\n", policy->name);
6874  db_disconnect(lock_fd);
6875  if (ctx) {
6876  hsm_destroy_context(ctx);
6877  }
6878  hsm_close();
6879  KsmPolicyFree(policy);
6880  return status;
6881  }
6882  }
6883 
6884  /* Find out how many ksk keys are needed for the POLICY */
6885  status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count);
6886  if (status != 0) {
6887  printf("Could not predict ksk requirement for next interval for %s\n", policy->name);
6888  hsm_close();
6889  db_disconnect(lock_fd);
6890  KsmPolicyFree(policy);
6891  return(1);
6892  }
6893  /* Find out how many suitable keys we have */
6894  status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_KSK);
6895  if (status != 0) {
6896  printf("Could not count current ksk numbers for policy %s\n", policy->name);
6897  hsm_close();
6898  db_disconnect(lock_fd);
6899  KsmPolicyFree(policy);
6900  return(1);
6901  }
6902  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
6903  new_keys = ksks_needed - keys_in_queue;
6904  /* fprintf(stderr, "keygen(ksk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, ksks_needed, keys_in_queue); */
6905 
6906  /* Check capacity of HSM will not be exceeded */
6907  if (policy->ksk->sm_capacity != 0 && new_keys > 0) {
6908  current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name);
6909  if (current_count >= policy->ksk->sm_capacity) {
6910  printf("Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name);
6911  new_keys = 0;
6912  }
6913  else if (current_count + new_keys > policy->ksk->sm_capacity) {
6914  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);
6915  new_keys = policy->ksk->sm_capacity - current_count;
6916  }
6917  }
6918 
6919  if (new_keys <= 0 ) {
6920  printf("No new KSKs need to be created.\n");
6921  }
6922  else {
6923  printf("%d new KSK(s) (%d bits) need to be created.\n", new_keys, policy->ksk->bits);
6924  }
6925 
6926  /* Create the required keys */
6927  for (i=new_keys ; i > 0 ; i--){
6928  if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) {
6929  /* NOTE: for now we know that libhsm only supports RSA keys */
6930  key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits);
6931  if (key) {
6932  if (verbose_flag) {
6933  printf("Created key in repository %s\n", policy->ksk->sm_name);
6934  }
6935  } else {
6936  printf("Error creating key in repository %s\n", policy->ksk->sm_name);
6937  hsm_error_message = hsm_get_error(ctx);
6938  if (hsm_error_message) {
6939  printf("%s\n", hsm_error_message);
6940  free(hsm_error_message);
6941  }
6942  db_disconnect(lock_fd);
6943  KsmPolicyFree(policy);
6944  hsm_close();
6945  exit(1);
6946  }
6947  id = hsm_get_key_id(ctx, key);
6948  hsm_key_free(key);
6949  status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore);
6950  if (status != 0) {
6951  printf("Error creating key in Database\n");
6952  hsm_error_message = hsm_get_error(ctx);
6953  if (hsm_error_message) {
6954  printf("%s\n", hsm_error_message);
6955  free(hsm_error_message);
6956  }
6957  db_disconnect(lock_fd);
6958  KsmPolicyFree(policy);
6959  hsm_close();
6960  exit(1);
6961  }
6962  printf("Created KSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->ksk->bits,
6963  policy->ksk->algorithm, id, policy->ksk->sm_name);
6964  free(id);
6965  } else {
6966  printf("Key algorithm %d unsupported by libhsm.\n", policy->ksk->algorithm);
6967  db_disconnect(lock_fd);
6968  KsmPolicyFree(policy);
6969  hsm_close();
6970  exit(1);
6971  }
6972  }
6973  ksks_created = new_keys;
6974 
6975  /* Find out how many zsk keys are needed */
6976  keys_in_queue = 0;
6977  new_keys = 0;
6978  current_count = 0;
6979 
6980  /* Find out how many zsk keys are needed for the POLICY */
6981  status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, interval, &zsks_needed, 0, zone_count);
6982  if (status != 0) {
6983  printf("Could not predict zsk requirement for next interval for %s\n", policy->name);
6984  /* TODO exit? continue with next policy? */
6985  }
6986  /* Find out how many suitable keys we have */
6987  status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK);
6988  if (status != 0) {
6989  printf("Could not count current zsk numbers for policy %s\n", policy->name);
6990  /* TODO exit? continue with next policy? */
6991  }
6992  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
6993  /* Might have to account for ksks */
6994  if (same_keys) {
6995  /* fprintf(stderr, "SAME KEY TYPE: adjusting for ksks on queue. Keys actually in queue now(%d), ksks_needed(%d)\n", keys_in_queue, ksks_needed); */
6996  keys_in_queue -= ksks_needed;
6997  }
6998 
6999  new_keys = zsks_needed - keys_in_queue;
7000  /* fprintf(stderr, "keygen(zsk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, zsks_needed, keys_in_queue); */
7001 
7002  /* Check capacity of HSM will not be exceeded */
7003  if (policy->zsk->sm_capacity != 0 && new_keys > 0) {
7004  current_count = hsm_count_keys_repository(ctx, policy->zsk->sm_name);
7005  if (current_count >= policy->zsk->sm_capacity) {
7006  printf("Repository %s is full, cannot create more ZSKs for policy %s\n", policy->zsk->sm_name, policy->name);
7007  new_keys = 0;
7008  }
7009  else if (current_count + new_keys > policy->zsk->sm_capacity) {
7010  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);
7011  new_keys = policy->zsk->sm_capacity - current_count;
7012  }
7013  }
7014 
7015  if (new_keys <= 0 ) {
7016  /* Don't exit here, just fall through to the end */
7017  printf("No new ZSKs need to be created.\n");
7018  }
7019  else {
7020  printf("%d new ZSK(s) (%d bits) need to be created.\n", new_keys, policy->zsk->bits);
7021  }
7022 
7023  /* Create the required keys */
7024  for (i = new_keys ; i > 0 ; i--) {
7025  if (hsm_supported_algorithm(policy->zsk->algorithm) == 0) {
7026  /* NOTE: for now we know that libhsm only supports RSA keys */
7027  key = hsm_generate_rsa_key(ctx, policy->zsk->sm_name, policy->zsk->bits);
7028  if (key) {
7029  if (verbose_flag) {
7030  printf("Created key in repository %s\n", policy->zsk->sm_name);
7031  }
7032  } else {
7033  printf("Error creating key in repository %s\n", policy->zsk->sm_name);
7034  hsm_error_message = hsm_get_error(ctx);
7035  if (hsm_error_message) {
7036  printf("%s\n", hsm_error_message);
7037  free(hsm_error_message);
7038  }
7039  db_disconnect(lock_fd);
7040  KsmPolicyFree(policy);
7041  hsm_close();
7042  exit(1);
7043  }
7044  id = hsm_get_key_id(ctx, key);
7045  hsm_key_free(key);
7046  status = KsmKeyPairCreate(policy->id, id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, rightnow, &ignore);
7047  if (status != 0) {
7048  printf("Error creating key in Database\n");
7049  hsm_error_message = hsm_get_error(ctx);
7050  if (hsm_error_message) {
7051  printf("%s\n", hsm_error_message);
7052  free(hsm_error_message);
7053  }
7054  db_disconnect(lock_fd);
7055  KsmPolicyFree(policy);
7056  hsm_close();
7057  exit(1);
7058  }
7059  printf("Created ZSK size: %i, alg: %i with id: %s in repository: %s and database.\n", policy->zsk->bits,
7060  policy->zsk->algorithm, id, policy->zsk->sm_name);
7061  free(id);
7062  } else {
7063  printf("Key algorithm %d unsupported by libhsm.\n", policy->zsk->algorithm);
7064  db_disconnect(lock_fd);
7065  KsmPolicyFree(policy);
7066  hsm_close();
7067  exit(1);
7068  }
7069  }
7070  StrFree(rightnow);
7071 
7072  /* Log if a backup needs to be run for these keys */
7073  if (ksks_created && policy->ksk->require_backup) {
7074  printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->ksk->sm_name);
7075  }
7076  if (new_keys && policy->zsk->require_backup && (policy->zsk->sm != policy->ksk->sm)) {
7077  printf("NOTE: keys generated in repository %s will not become active until they have been backed up\n", policy->zsk->sm_name);
7078  }
7079 
7080  /*
7081  * Destroy HSM context
7082  */
7083  if (ctx) {
7084  hsm_destroy_context(ctx);
7085  }
7086  status = hsm_close();
7087  printf("all done! hsm_close result: %d\n", status);
7088 
7089  KsmPolicyFree(policy);
7090 
7091  /* Release sqlite lock file (if we have it) */
7092  db_disconnect(lock_fd);
7093 
7094  return status;
7095 }
7096 
7097 /* Make sure (if we can) that the permissions on a file are correct for the user/group in conf.xml */
7098 
7099 int fix_file_perms(const char *dbschema)
7100 {
7101  struct stat stat_ret;
7102 
7103  int status = 0;
7104 
7105  xmlDocPtr doc = NULL;
7106  xmlDocPtr rngdoc = NULL;
7107  xmlXPathContextPtr xpathCtx = NULL;
7108  xmlXPathObjectPtr xpathObj = NULL;
7109  xmlRelaxNGParserCtxtPtr rngpctx = NULL;
7110  xmlRelaxNGValidCtxtPtr rngctx = NULL;
7111  xmlRelaxNGPtr schema = NULL;
7112  xmlChar *user_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/User";
7113  xmlChar *group_expr = (unsigned char*) "//Configuration/Enforcer/Privileges/Group";
7114 
7115  char* filename = OPENDNSSEC_CONFIG_FILE;
7116  char* rngfilename = OPENDNSSEC_SCHEMA_DIR "/conf.rng";
7117  char* temp_char = NULL;
7118 
7119  struct passwd *pwd;
7120  struct group *grp;
7121 
7122  int uid = -1;
7123  int gid = -1;
7124  char *username = NULL;
7125  char *groupname = NULL;
7126 
7127  printf("fixing permissions on file %s\n", dbschema);
7128  /* First see if we are running as root, if not then return */
7129  if (geteuid() != 0) {
7130  return 0;
7131  }
7132 
7133  /* Now see if the file exists, if it does not then return */
7134  if (stat(dbschema, &stat_ret) != 0) {
7135  printf("cannot stat file %s: %s", dbschema, strerror(errno));
7136  return -1;
7137  }
7138 
7139  /* OKAY... read conf.xml for the user and group */
7140  /* Load XML document */
7141  doc = xmlParseFile(filename);
7142  if (doc == NULL) {
7143  printf("Error: unable to parse file \"%s\"", filename);
7144  return(-1);
7145  }
7146 
7147  /* Load rng document */
7148  rngdoc = xmlParseFile(rngfilename);
7149  if (rngdoc == NULL) {
7150  printf("Error: unable to parse file \"%s\"", rngfilename);
7151  return(-1);
7152  }
7153 
7154  /* Create an XML RelaxNGs parser context for the relax-ng document. */
7155  rngpctx = xmlRelaxNGNewDocParserCtxt(rngdoc);
7156  if (rngpctx == NULL) {
7157  printf("Error: unable to create XML RelaxNGs parser context");
7158  return(-1);
7159  }
7160 
7161  /* parse a schema definition resource and build an internal XML Shema struture which can be used to validate instances. */
7162  schema = xmlRelaxNGParse(rngpctx);
7163  if (schema == NULL) {
7164  printf("Error: unable to parse a schema definition resource");
7165  return(-1);
7166  }
7167 
7168  /* Create an XML RelaxNGs validation context based on the given schema */
7169  rngctx = xmlRelaxNGNewValidCtxt(schema);
7170  if (rngctx == NULL) {
7171  printf("Error: unable to create RelaxNGs validation context based on the schema");
7172  return(-1);
7173  }
7174 
7175  /* Validate a document tree in memory. */
7176  status = xmlRelaxNGValidateDoc(rngctx,doc);
7177  if (status != 0) {
7178  printf("Error validating file \"%s\"", filename);
7179  return(-1);
7180  }
7181 
7182  /* Now parse a value out of the conf */
7183  /* Create xpath evaluation context */
7184  xpathCtx = xmlXPathNewContext(doc);
7185  if(xpathCtx == NULL) {
7186  printf("Error: unable to create new XPath context");
7187  xmlFreeDoc(doc);
7188  return(-1);
7189  }
7190 
7191  /* Set the group if specified */
7192  xpathObj = xmlXPathEvalExpression(group_expr, xpathCtx);
7193  if(xpathObj == NULL) {
7194  printf("Error: unable to evaluate xpath expression: %s", group_expr);
7195  xmlXPathFreeContext(xpathCtx);
7196  xmlFreeDoc(doc);
7197  return(-1);
7198  }
7199  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
7200  temp_char = (char*) xmlXPathCastToString(xpathObj);
7201  StrAppend(&groupname, temp_char);
7202  StrFree(temp_char);
7203  xmlXPathFreeObject(xpathObj);
7204  } else {
7205  groupname = NULL;
7206  }
7207 
7208  /* Set the user to drop to if specified */
7209  xpathObj = xmlXPathEvalExpression(user_expr, xpathCtx);
7210  if(xpathObj == NULL) {
7211  printf("Error: unable to evaluate xpath expression: %s", user_expr);
7212  xmlXPathFreeContext(xpathCtx);
7213  xmlFreeDoc(doc);
7214  return(-1);
7215  }
7216  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
7217  temp_char = (char*) xmlXPathCastToString(xpathObj);
7218  StrAppend(&username, temp_char);
7219  StrFree(temp_char);
7220  xmlXPathFreeObject(xpathObj);
7221  } else {
7222  username = NULL;
7223  }
7224 
7225  /* Free up the xml stuff, we are done with it */
7226  xmlXPathFreeContext(xpathCtx);
7227  xmlRelaxNGFree(schema);
7228  xmlRelaxNGFreeValidCtxt(rngctx);
7229  xmlRelaxNGFreeParserCtxt(rngpctx);
7230  xmlFreeDoc(doc);
7231  xmlFreeDoc(rngdoc);
7232 
7233  /* Set uid and gid if required */
7234  if (username != NULL) {
7235  /* Lookup the user id in /etc/passwd */
7236  if ((pwd = getpwnam(username)) == NULL) {
7237  printf("user '%s' does not exist. cannot chown %s...\n", username, dbschema);
7238  return(1);
7239  } else {
7240  uid = pwd->pw_uid;
7241  }
7242  endpwent();
7243  }
7244  if (groupname) {
7245  /* Lookup the group id in /etc/groups */
7246  if ((grp = getgrnam(groupname)) == NULL) {
7247  printf("group '%s' does not exist. cannot chown %s...\n", groupname, dbschema);
7248  exit(1);
7249  } else {
7250  gid = grp->gr_gid;
7251  }
7252  endgrent();
7253  }
7254 
7255  /* Change ownership of the db file */
7256  if (chown(dbschema, uid, gid) == -1) {
7257  printf("cannot chown(%u,%u) %s: %s",
7258  (unsigned) uid, (unsigned) gid, dbschema, strerror(errno));
7259  return -1;
7260  }
7261 
7262  /* and change ownership of the lock file */
7263  temp_char = NULL;
7264  StrAppend(&temp_char, dbschema);
7265  StrAppend(&temp_char, ".our_lock");
7266 
7267  if (chown(temp_char, uid, gid) == -1) {
7268  printf("cannot chown(%u,%u) %s: %s",
7269  (unsigned) uid, (unsigned) gid, temp_char, strerror(errno));
7270  StrFree(temp_char);
7271  return -1;
7272  }
7273 
7274  StrFree(temp_char);
7275 
7276  return 0;
7277 }
7278 
7279 /*+
7280  * CountKeys - Find how many Keys match our criteria
7281  *
7282  *
7283  * Arguments:
7284  *
7285  * int zone_id
7286  * ID of the zone (-1 for all)
7287  *
7288  * int keytag
7289  * keytag provided (-1 if not specified)
7290  *
7291  * const char * cka_id
7292  * cka_id provided (NULL if not)
7293  *
7294  * int * key_count (returned)
7295  * count of keys matching the information specified
7296  *
7297  * char ** temp_cka_id (returned)
7298  * cka_id of key found
7299  *
7300  * int * temp_key_state (returned)
7301  * What state is the key in (only used if _one_ key returned)
7302  *
7303  * int * temp_keypair_id (returned)
7304  * ID of the key found (only used if _one_ key returned)
7305  * Returns:
7306  * int
7307  * Status return. 0 on success.
7308  * other on fail
7309  */
7310 
7311 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)
7312 {
7313  char* sql = NULL; /* SQL query */
7314  int status = 0; /* Status return */
7315  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
7316  DB_RESULT result; /* Result of the query */
7317  DB_ROW row = NULL; /* Row data */
7318 
7319  char buffer[256]; /* For constructing part of the command */
7320  size_t nchar; /* Number of characters written */
7321 
7322  int done_row = 0; /* Have we found a key this loop? */
7323 
7324  int temp_zone_id = 0; /* place to store zone_id returned */
7325  char* temp_loc = NULL; /* place to store location returned */
7326  int temp_alg = 0; /* place to store algorithm returned */
7327  int temp_state = 0; /* place to store state returned */
7328  int temp_keypair = 0; /* place to store id returned */
7329 
7330  int temp_count = 0; /* Count of keys found */
7331 
7332  /* Key information */
7333  hsm_key_t *key = NULL;
7334  ldns_rr *dnskey_rr = NULL;
7335  hsm_sign_params_t *sign_params = NULL;
7336 
7337  /* connect to the HSM */
7338  status = hsm_open(config, hsm_prompt_pin, NULL);
7339  if (status) {
7340  hsm_print_error(NULL);
7341  return(-1);
7342  }
7343 
7344  /* Select rows */
7345  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d)",
7347  if (nchar >= sizeof(buffer)) {
7348  printf("Error: Overran buffer in CountKeys\n");
7349  hsm_close();
7350  return(-1);
7351  }
7352 
7353  /* TODO do I need to use the view */
7354  StrAppend(&sql, "select k.zone_id, k.location, k.algorithm, k.state, k.id from KEYDATA_VIEW k where state in ");
7355  StrAppend(&sql, buffer);
7356  StrAppend(&sql, " and zone_id is not null and k.keytype = 257");
7357 
7358  if (*zone_id != -1) {
7359  StrAppend(&sql, " and zone_id = ");
7360  snprintf(stringval, KSM_INT_STR_SIZE, "%d", *zone_id);
7361  StrAppend(&sql, stringval);
7362  }
7363  if (cka_id != NULL) {
7364  StrAppend(&sql, " and k.location = '");
7365  StrAppend(&sql, cka_id);
7366  StrAppend(&sql, "'");
7367  }
7368  /* where location is unique? */
7369  StrAppend(&sql, " group by location");
7370 
7371  DusEnd(&sql);
7372 
7373  status = DbExecuteSql(DbHandle(), sql, &result);
7374 
7375  /* loop round printing out the cka_id of any key that matches
7376  * if only one does then we are good, if not then we will write a
7377  * message asking for further clarification */
7378  /* Note that we only need to do each key, not each instance of a key */
7379  if (status == 0) {
7380  status = DbFetchRow(result, &row);
7381  while (status == 0) {
7382  /* Got a row, process it */
7383  DbInt(row, 0, &temp_zone_id);
7384  DbString(row, 1, &temp_loc);
7385  DbInt(row, 2, &temp_alg);
7386  DbInt(row, 3, &temp_state);
7387  DbInt(row, 4, &temp_keypair);
7388 
7389  done_row = 0;
7390 
7391  if (keytag == -1 && cka_id == NULL)
7392  {
7393  *temp_key_state = temp_state;
7394  }
7395 
7396  key = hsm_find_key_by_id(NULL, temp_loc);
7397  if (!key) {
7398  printf("cka_id %-33s in DB but NOT IN repository\n", temp_loc);
7399  } else if (keytag != -1) {
7400  sign_params = hsm_sign_params_new();
7401  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, "temp_zone");
7402  sign_params->algorithm = temp_alg;
7403  sign_params->flags = LDNS_KEY_ZONE_KEY;
7404  sign_params->flags += LDNS_KEY_SEP_KEY;
7405 
7406  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
7407  sign_params->keytag = ldns_calc_keytag(dnskey_rr);
7408 
7409  /* Have we matched our keytag? */
7410  if (keytag == sign_params->keytag) {
7411  temp_count++;
7412  done_row = 1;
7413  *temp_cka_id = NULL;
7414  StrAppend(temp_cka_id, temp_loc);
7415  *zone_id = temp_zone_id;
7416  *temp_key_state = temp_state;
7417  *temp_keypair_id = temp_keypair;
7418  printf("Found key with CKA_ID %s\n", temp_loc);
7419  }
7420 
7421  hsm_sign_params_free(sign_params);
7422  }
7423  if (key && cka_id != NULL && strncmp(cka_id, temp_loc, strlen(temp_loc)) == 0) {
7424  /* Or have we matched a provided cka_id */
7425  if (done_row == 0) {
7426  temp_count++;
7427  *temp_cka_id = NULL;
7428  StrAppend(temp_cka_id, temp_loc);
7429  *zone_id = temp_zone_id;
7430  *temp_key_state = temp_state;
7431  *temp_keypair_id = temp_keypair;
7432  printf("Found key with CKA_ID %s\n", temp_loc);
7433  }
7434  }
7435 
7436  if (key) {
7437  hsm_key_free(key);
7438  }
7439 
7440  status = DbFetchRow(result, &row);
7441  }
7442 
7443  /* Convert EOF status to success */
7444 
7445  if (status == -1) {
7446  status = 0;
7447  }
7448 
7449  DbFreeResult(result);
7450  }
7451 
7452  *key_count = temp_count;
7453 
7454  DusFree(sql);
7455  DbFreeRow(row);
7456 
7457  DbStringFree(temp_loc);
7458 
7459  if (dnskey_rr != NULL) {
7460  ldns_rr_free(dnskey_rr);
7461  }
7462 
7463  hsm_close();
7464 
7465  return status;
7466 }
7467 
7468 /*+
7469  * MarkDSSeen - Indicate that the DS record has been observed:
7470  * Change the state of the key to ACTIVE
7471  *
7472  * Arguments:
7473  *
7474  * const char * cka_id
7475  * cka_id of key to make active
7476  *
7477  * int zone_id
7478  * ID of the zone
7479  *
7480  * int policy_id
7481  * ID of the policy
7482  *
7483  * const char * datetime
7484  * when this is happening
7485  *
7486  * int key_state
7487  * state that the key is in
7488  *
7489  * Returns:
7490  * int
7491  * Status return. 0 on success.
7492  * other on fail
7493  */
7494 
7495 int MarkDSSeen(int keypair_id, int zone_id, int policy_id, const char *datetime, int key_state)
7496 {
7497  char* sql1 = NULL; /* SQL query */
7498  int status = 0; /* Status return */
7499 
7500  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
7501  unsigned int nchar; /* Number of characters converted */
7502 
7503  KSM_PARCOLL collection; /* Collection of parameters for zone */
7504  int deltat; /* Time interval */
7505 
7506  (void) zone_id;
7507 
7508  /* Set collection defaults */
7509  KsmCollectionInit(&collection);
7510 
7511  /* Get the values of the parameters */
7512  status = KsmParameterCollection(&collection, policy_id);
7513  if (status != 0) {
7514  printf("Error: failed to read policy\n");
7515  return status;
7516  }
7517 
7518 /* 0) Start a transaction */
7519  status = DbBeginTransaction();
7520  if (status != 0) {
7521  /* Something went wrong */
7522 
7524  return status;
7525  }
7526 
7527  /* 1) Change the state of the selected Key */
7528  if (key_state == KSM_STATE_READY) {
7529  /* We are making a key active */
7530 
7531  /* Set the interval until Retire */
7532  deltat = collection.ksklife;
7533 
7534 #ifdef USE_MYSQL
7535  nchar = snprintf(buffer, sizeof(buffer),
7536  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
7537 #else
7538  nchar = snprintf(buffer, sizeof(buffer),
7539  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
7540 #endif /* USE_MYSQL */
7541 
7542  if (nchar >= sizeof(buffer)) {
7543  status = -1;
7544  printf("Error: failed to create SQL statement\n");
7545  return status;
7546  }
7547 
7548  sql1 = DusInit("dnsseckeys");
7549  DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0);
7551  StrAppend(&sql1, ", RETIRE = ");
7552  StrAppend(&sql1, buffer);
7553 
7554  DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
7555  DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
7556  DusEnd(&sql1);
7557  }
7558  else {
7559  /* We are making a standby key DSpublish */
7560 
7561  /* Set the interval until DSReady */
7562  deltat = collection.kskttl + collection.kskpropdelay +
7563  collection.pub_safety;
7564 
7565 #ifdef USE_MYSQL
7566  nchar = snprintf(buffer, sizeof(buffer),
7567  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
7568 #else
7569  nchar = snprintf(buffer, sizeof(buffer),
7570  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
7571 #endif /* USE_MYSQL */
7572 
7573  if (nchar >= sizeof(buffer)) {
7574  status = -1;
7575  printf("Error: failed to create SQL statement\n");
7576  return status;
7577  }
7578 
7579  sql1 = DusInit("dnsseckeys");
7580  DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0);
7582  StrAppend(&sql1, ", READY = ");
7583  StrAppend(&sql1, buffer);
7584 
7585  DusConditionInt(&sql1, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
7586  DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
7587  DusEnd(&sql1);
7588  }
7589 
7590  status = DbExecuteSqlNoResult(DbHandle(), sql1);
7591  DusFree(sql1);
7592 
7593  /* Report any errors */
7594  if (status != 0) {
7595  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
7596  DbRollback();
7597  return status;
7598  }
7599 
7600  /* 3) Commit or Rollback */
7601  if (status == 0) { /* It actually can't be anything else */
7602  /* Everything worked by the looks of it */
7603  DbCommit();
7604  } else {
7605  /* Whatever happened, it was not good */
7606  DbRollback();
7607  }
7608 
7609  return status;
7610 }
7611 
7612 /*+
7613  * RetireOldKey - Retire the old KSK
7614  *
7615  *
7616  * Arguments:
7617  *
7618  * int zone_id
7619  * ID of the zone
7620  *
7621  * int policy_id
7622  * ID of the policy
7623  *
7624  * const char * datetime
7625  * when this is happening
7626  *
7627  * Returns:
7628  * int
7629  * Status return. 0 on success.
7630  * other on fail
7631  */
7632 
7633 int RetireOldKey(int zone_id, int policy_id, const char *datetime)
7634 {
7635  char* sql2 = NULL; /* SQL query */
7636  int status = 0; /* Status return */
7637  char* where_clause = NULL;
7638  int id = -1; /* ID of key to retire */
7639 
7640  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
7641  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
7642  unsigned int nchar; /* Number of characters converted */
7643 
7644  KSM_PARCOLL collection; /* Collection of parameters for zone */
7645  int deltat; /* Time interval */
7646 
7647  /* Set collection defaults */
7648  KsmCollectionInit(&collection);
7649 
7650  /* Get the values of the parameters */
7651  status = KsmParameterCollection(&collection, policy_id);
7652  if (status != 0) {
7653  printf("Error: failed to read policy\n");
7654  return status;
7655  }
7656 
7657 /* 0) Start a transaction */
7658  status = DbBeginTransaction();
7659  if (status != 0) {
7660  /* Something went wrong */
7661 
7663  return status;
7664  }
7665 
7666  /* 1) Retire the oldest active key, and set its deadtime */
7667  /* work out which key */
7668  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
7669  StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
7670  StrAppend(&where_clause, stringval);
7671  StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
7672  StrAppend(&where_clause, stringval);
7673  StrAppend(&where_clause, ")");
7674 
7675  /* Execute query and free up the query string */
7676  status = DbIntQuery(DbHandle(), &id, where_clause);
7677  StrFree(where_clause);
7678  if (status != 0)
7679  {
7680  printf("Error: failed to find ID of key to retire\n");
7681  DbRollback();
7682  return status;
7683  }
7684 
7685  /* work out what its deadtime should become */
7686  deltat = collection.dsttl + collection.kskpropdelay + collection.ret_safety;
7687 
7688 #ifdef USE_MYSQL
7689  nchar = snprintf(buffer, sizeof(buffer),
7690  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
7691 #else
7692  nchar = snprintf(buffer, sizeof(buffer),
7693  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
7694 #endif /* USE_MYSQL */
7695 
7696  if (nchar >= sizeof(buffer)) {
7697  status = -1;
7698  printf("Error: failed to create SQL statement\n");
7699  return status;
7700  }
7701 
7702  sql2 = DusInit("dnsseckeys");
7703  DusSetInt(&sql2, "STATE", KSM_STATE_RETIRE, 0);
7705  StrAppend(&sql2, ", DEAD = ");
7706  StrAppend(&sql2, buffer);
7707  DusConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, id, 0);
7708  DusConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
7709 
7710  status = DbExecuteSqlNoResult(DbHandle(), sql2);
7711  DusFree(sql2);
7712 
7713  /* Report any errors */
7714  if (status != 0) {
7715  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
7716  DbRollback();
7717  return status;
7718  }
7719 
7720  /* 2) Commit or Rollback */
7721  if (status == 0) { /* It actually can't be anything else */
7722  /* Everything worked by the looks of it */
7723  DbCommit();
7724  } else {
7725  /* Whatever happened, it was not good */
7726  DbRollback();
7727  }
7728 
7729  return status;
7730 }
7731 
7732 /*
7733  * CountKeysInState - Count Keys in given state
7734  *
7735  * Description:
7736  * Counts the number of keys in the given state.
7737  *
7738  * Arguments:
7739  * int keytype
7740  * Either KSK or ZSK, depending on the key type
7741  *
7742  * int keystate
7743  * State of keys to count
7744  *
7745  * int* count
7746  * Number of keys meeting the condition.
7747  *
7748  * int zone_id
7749  * ID of zone that we are looking at (-1 == all zones)
7750  *
7751  * Returns:
7752  * int
7753  * Status return. 0 => success, Other => error, in which case a message
7754  * will have been output.
7755 -*/
7756 
7757 int CountKeysInState(int keytype, int keystate, int* count, int zone_id)
7758 {
7759  int clause = 0; /* Clause counter */
7760  char* sql = NULL; /* SQL command */
7761  int status; /* Status return */
7762 
7763  sql = DqsCountInit("KEYDATA_VIEW");
7764  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
7765  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, keystate, clause++);
7766  if (zone_id != -1) {
7767  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
7768  }
7769  DqsEnd(&sql);
7770 
7771  status = DbIntQuery(DbHandle(), count, sql);
7772  DqsFree(sql);
7773 
7774  if (status != 0) {
7775  printf("Error in CountKeysInState\n");
7776  }
7777 
7778  return status;
7779 }
7780 
7781 /*+
7782  * ChangeKeyState - Change the state of the specified key
7783  *
7784  * Arguments:
7785  *
7786  * int keytype
7787  * type of key we are dealing with
7788  *
7789  * const char * cka_id
7790  * cka_id of key to change
7791  *
7792  * int zone_id
7793  * ID of the zone
7794  *
7795  * int policy_id
7796  * ID of the policy
7797  *
7798  * const char * datetime
7799  * when this is happening
7800  *
7801  * int keystate
7802  * state that the key should be moved to
7803  *
7804  * Returns:
7805  * int
7806  * Status return. 0 on success.
7807  * other on fail
7808  *
7809  * TODO take keytimings out of here
7810  */
7811 
7812 int ChangeKeyState(int keytype, const char *cka_id, int zone_id, int policy_id, const char *datetime, int keystate)
7813 {
7814  char* sql1 = NULL; /* SQL query */
7815  int status = 0; /* Status return */
7816 
7817  int count = 0; /* Count of keys whose date will be set */
7818  char* sql = NULL; /* For creating the SQL command */
7819  int where = 0; /* For the SQL selection */
7820  int i = 0; /* A counter */
7821  int j = 0; /* Another counter */
7822  char* insql = NULL; /* SQL "IN" clause */
7823  int* keyids; /* List of IDs of keys to promote */
7824  DB_RESULT result; /* List result set */
7825  KSM_KEYDATA data; /* Data for this key */
7826 
7827  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
7828  unsigned int nchar; /* Number of characters converted */
7829 
7830  KSM_PARCOLL collection; /* Collection of parameters for zone */
7831  int deltat = 0; /* Time interval */
7832 
7833  (void) zone_id;
7834 
7835  /* Set collection defaults */
7836  KsmCollectionInit(&collection);
7837 
7838  /* Get the values of the parameters */
7839  status = KsmParameterCollection(&collection, policy_id);
7840  if (status != 0) {
7841  printf("Error: failed to read policy\n");
7842  return status;
7843  }
7844 
7845  /* Count how many keys will have their state changed */
7846 
7847  sql = DqsCountInit("KEYDATA_VIEW");
7848  DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++);
7849  if (zone_id != -1) {
7850  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
7851  }
7852  DqsEnd(&sql);
7853 
7854  status = DbIntQuery(DbHandle(), &count, sql);
7855  DqsFree(sql);
7856 
7857  if (status != 0) {
7858  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
7859  return status;
7860  }
7861 
7862  if (count == 0) {
7863  /* Nothing to do, error? */
7864  return status;
7865  }
7866 
7867  /* Allocate space for the list of key IDs */
7868  keyids = MemMalloc(count * sizeof(int));
7869 
7870  /* Get the list of IDs */
7871 
7872  where = 0;
7873  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
7874  DqsConditionString(&sql, "location", DQS_COMPARE_EQ, cka_id, where++);
7875  if (zone_id != -1) {
7876  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
7877  }
7878  DqsEnd(&sql);
7879 
7880  status = KsmKeyInitSql(&result, sql);
7881  DqsFree(sql);
7882 
7883  if (status == 0) {
7884  while (status == 0) {
7885  status = KsmKey(result, &data);
7886  if (status == 0) {
7887  keyids[i] = data.keypair_id;
7888  i++;
7889  }
7890  }
7891 
7892  /* Convert EOF status to success */
7893 
7894  if (status == -1) {
7895  status = 0;
7896  } else {
7897  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
7898  StrFree(keyids);
7899  return status;
7900  }
7901 
7902  KsmKeyEnd(result);
7903 
7904  } else {
7905  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
7906  StrFree(keyids);
7907  return status;
7908  }
7909 
7910  /*
7911  * Now construct the "IN" statement listing the IDs of the keys we
7912  * are planning to change the state of.
7913  */
7914 
7915  StrAppend(&insql, "(");
7916  for (j = 0; j < i; ++j) {
7917  if (j != 0) {
7918  StrAppend(&insql, ",");
7919  }
7920  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
7921  StrAppend(&insql, buffer);
7922  }
7923  StrAppend(&insql, ")");
7924 
7925 /* 0) Start a transaction */
7926  status = DbBeginTransaction();
7927  if (status != 0) {
7928  /* Something went wrong */
7929 
7931  StrFree(keyids);
7932  return status;
7933  }
7934 
7935  /* 1) Change the state of the selected Key */
7936  if (keystate == KSM_STATE_ACTIVE) {
7937  /* We are making a key active */
7938 
7939  /* Set the interval until Retire */
7940  deltat = collection.ksklife;
7941 
7942 #ifdef USE_MYSQL
7943  nchar = snprintf(buffer, sizeof(buffer),
7944  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
7945 #else
7946  nchar = snprintf(buffer, sizeof(buffer),
7947  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
7948 #endif /* USE_MYSQL */
7949 
7950  if (nchar >= sizeof(buffer)) {
7951  status = -1;
7952  printf("Error: failed to create SQL statement\n");
7953  return status;
7954  }
7955 
7956  sql1 = DusInit("dnsseckeys");
7957  DusSetInt(&sql1, "STATE", KSM_STATE_ACTIVE, 0);
7959  StrAppend(&sql1, ", RETIRE = ");
7960  StrAppend(&sql1, buffer);
7961 
7962  DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
7963  if (zone_id != -1) {
7964  DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
7965  }
7966  DusEnd(&sql1);
7967  }
7968  else if (keystate == KSM_STATE_RETIRE) {
7969  /* We are making a key retired */
7970 
7971  /* Set the interval until Dead */
7972  if (keytype == KSM_TYPE_ZSK) {
7973  deltat = collection.zsksiglife + collection.propdelay + collection.ret_safety;
7974  }
7975  else if (keytype == KSM_TYPE_KSK) {
7976  deltat = collection.kskttl + collection.kskpropdelay +
7977  collection.ret_safety; /* Ipp */
7978  }
7979 
7980 #ifdef USE_MYSQL
7981  nchar = snprintf(buffer, sizeof(buffer),
7982  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
7983 #else
7984  nchar = snprintf(buffer, sizeof(buffer),
7985  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
7986 #endif /* USE_MYSQL */
7987 
7988  if (nchar >= sizeof(buffer)) {
7989  status = -1;
7990  printf("Error: failed to create SQL statement\n");
7991  return status;
7992  }
7993 
7994  sql1 = DusInit("dnsseckeys");
7995  DusSetInt(&sql1, "STATE", KSM_STATE_RETIRE, 0);
7997  StrAppend(&sql1, ", DEAD = ");
7998  StrAppend(&sql1, buffer);
7999 
8000  DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
8001  if (zone_id != -1) {
8002  DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
8003  }
8004  DusEnd(&sql1);
8005  }
8006  else if (keystate == KSM_STATE_DSPUBLISH) {
8007  /* Set the interval until DSReady */
8008  deltat = collection.kskttl + collection.kskpropdelay +
8009  collection.pub_safety;
8010 
8011 #ifdef USE_MYSQL
8012  nchar = snprintf(buffer, sizeof(buffer),
8013  "DATE_ADD('%s', INTERVAL %d SECOND) ", datetime, deltat);
8014 #else
8015  nchar = snprintf(buffer, sizeof(buffer),
8016  "DATETIME('%s', '+%d SECONDS') ", datetime, deltat);
8017 #endif /* USE_MYSQL */
8018 
8019  if (nchar >= sizeof(buffer)) {
8020  status = -1;
8021  printf("Error: failed to create SQL statement\n");
8022  return status;
8023  }
8024 
8025  sql1 = DusInit("dnsseckeys");
8026  DusSetInt(&sql1, "STATE", KSM_STATE_DSPUBLISH, 0);
8028  StrAppend(&sql1, ", READY = ");
8029  StrAppend(&sql1, buffer);
8030 
8031  DusConditionKeyword(&sql1, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
8032  if (zone_id != -1) {
8033  DusConditionInt(&sql1, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
8034  }
8035  DusEnd(&sql1);
8036  }
8037  else {
8038  printf("Moving to keystate %s not implemented yet\n", KsmKeywordStateValueToName(keystate));
8039  StrFree(keyids);
8040  return -1;
8041  }
8042 
8043  status = DbExecuteSqlNoResult(DbHandle(), sql1);
8044  DusFree(sql1);
8045 
8046  StrFree(keyids);
8047 
8048  /* Report any errors */
8049  if (status != 0) {
8050  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
8051  DbRollback();
8052  return status;
8053  }
8054 
8055  /* 3) Commit or Rollback */
8056  if (status == 0) { /* It actually can't be anything else */
8057  /* Everything worked by the looks of it */
8058  DbCommit();
8059  } else {
8060  /* Whatever happened, it was not good */
8061  DbRollback();
8062  }
8063 
8064  return status;
8065 }
8066 
8067 static int restart_enforcerd()
8068 {
8069  /* ToDo: This should really be rewritten so that it will read
8070  OPENDNSSEC_ENFORCER_PIDFILE and send a SIGHUP itself */
8071  return system(ODS_EN_NOTIFY);
8072 }
8073 
8074 /*
8075  * Read the conf.xml file, we will not validate as that was done as we read the database.
8076  * Instead we just extract the RepositoryList into the database and also learn the
8077  * location of the zonelist.
8078  */
8079 int get_conf_key_info(int* interval, int* man_key_gen)
8080 {
8081  int status = 0;
8082  int mysec = 0;
8083  xmlDocPtr doc = NULL;
8084  xmlXPathContextPtr xpathCtx = NULL;
8085  xmlXPathObjectPtr xpathObj = NULL;
8086  char* temp_char = NULL;
8087 
8088  xmlChar *iv_expr = (unsigned char*) "//Configuration/Enforcer/Interval";
8089  xmlChar *mk_expr = (unsigned char*) "//Configuration/Enforcer/ManualKeyGeneration";
8090 
8091  /* Load XML document */
8092  doc = xmlParseFile(config);
8093  if (doc == NULL) {
8094  printf("Error: unable to parse file \"%s\"\n", config);
8095  return(-1);
8096  }
8097 
8098  /* Create xpath evaluation context */
8099  xpathCtx = xmlXPathNewContext(doc);
8100  if(xpathCtx == NULL) {
8101  printf("Error: unable to create new XPath context\n");
8102  xmlFreeDoc(doc);
8103  return(-1);
8104  }
8105 
8106  /* Evaluate xpath expression for interval */
8107  xpathObj = xmlXPathEvalExpression(iv_expr, xpathCtx);
8108  if(xpathObj == NULL) {
8109  printf("Error: unable to evaluate xpath expression: %s", iv_expr);
8110  xmlXPathFreeContext(xpathCtx);
8111  xmlFreeDoc(doc);
8112  return(-1);
8113  }
8114 
8115  temp_char = (char *)xmlXPathCastToString(xpathObj);
8116  status = DtXMLIntervalSeconds(temp_char, &mysec);
8117  if (status > 0) {
8118  printf("Error: unable to convert Interval %s to seconds, error: %i\n", temp_char, status);
8119  StrFree(temp_char);
8120  return status;
8121  }
8122  else if (status == -1) {
8123  printf("Info: converting %s to seconds; M interpreted as 31 days, Y interpreted as 365 days\n", temp_char);
8124  }
8125  *interval = mysec;
8126  StrFree(temp_char);
8127  xmlXPathFreeObject(xpathObj);
8128 
8129  /* Evaluate xpath expression for Manual key generation */
8130  xpathObj = xmlXPathEvalExpression(mk_expr, xpathCtx);
8131  if(xpathObj == NULL) {
8132  printf("Error: unable to evaluate xpath expression: %s\n", mk_expr);
8133  xmlXPathFreeContext(xpathCtx);
8134  xmlFreeDoc(doc);
8135  return(-1);
8136  }
8137 
8138  if (xpathObj->nodesetval != NULL && xpathObj->nodesetval->nodeNr > 0) {
8139  /* Manual key generation tag is present */
8140  *man_key_gen = 1;
8141  }
8142  else {
8143  /* Tag absent */
8144  *man_key_gen = 0;
8145  }
8146  xmlXPathFreeObject(xpathObj);
8147 
8148  if (xpathCtx) {
8149  xmlXPathFreeContext(xpathCtx);
8150  }
8151  if (doc) {
8152  xmlFreeDoc(doc);
8153  }
8154 
8155  return 0;
8156 }
8157 
8158 /* TODO put this fn and the one below somewhere that we can call it from here and the enforcer */
8159  /*+
8160  * LinkKeys - Create required entries in Dnsseckeys table for zones added to policies
8161  * (i.e. when keysharing is turned on)
8162  *
8163  * Description:
8164  * Allocates a key in the database.
8165  *
8166  * Arguments:
8167  * const char* zone_name
8168  * name of zone
8169  *
8170  * int policy_id
8171  * ID of policy which the zone is on
8172  *
8173  * int interval
8174  * Enforcer run interval
8175  *
8176  * int man_key_gen
8177  * Manual Key Generation flag
8178  *
8179  * Returns:
8180  * int
8181  * Status return. 0=> Success, non-zero => error.
8182 -*/
8183 
8184 int LinkKeys(const char* zone_name, int policy_id)
8185 {
8186  int status = 0;
8187 
8188  int interval = -1; /* Enforcer interval */
8189  int man_key_gen = -1; /* Manual key generation flag */
8190 
8191  int zone_id = 0; /* id of zone supplied */
8192  KSM_POLICY* policy;
8193 
8194  /* Unused parameter */
8195  (void)policy_id;
8196 
8197  /* Get some info from conf.xml */
8198  status = get_conf_key_info(&interval, &man_key_gen);
8199  if (status != 0) {
8200  printf("Failed to Link Keys to zone\n");
8201  return(1);
8202  }
8203 
8204  status = KsmZoneIdFromName(zone_name, &zone_id);
8205  if (status != 0) {
8206  return(status);
8207  }
8208 
8209  policy = KsmPolicyAlloc();
8210  if (policy == NULL) {
8211  printf("Malloc for policy struct failed\n");
8212  exit(1);
8213  }
8214  SetPolicyDefaults(policy, o_policy);
8215 
8216  status = KsmPolicyExists(o_policy);
8217  if (status == 0) {
8218  /* Policy exists */
8219  status = KsmPolicyRead(policy);
8220  if(status != 0) {
8221  printf("Error: unable to read policy %s from database\n", o_policy);
8222  KsmPolicyFree(policy);
8223  return status;
8224  }
8225  } else {
8226  printf("Error: policy %s doesn't exist in database\n", o_policy);
8227  KsmPolicyFree(policy);
8228  return status;
8229  }
8230 
8231  /* Make sure that enough keys are allocated to this zone */
8232  status = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, interval, zone_name, man_key_gen, 0);
8233  if (status != 0) {
8234  printf("Error allocating zsks to zone %s", zone_name);
8235  KsmPolicyFree(policy);
8236  return(status);
8237  }
8238  status = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, interval, zone_name, man_key_gen, policy->ksk->rollover_scheme);
8239  if (status != 0) {
8240  printf("Error allocating ksks to zone %s", zone_name);
8241  KsmPolicyFree(policy);
8242  return(status);
8243  }
8244 
8245  KsmPolicyFree(policy);
8246  return 0;
8247 }
8248 
8249 /* allocateKeysToZone
8250  *
8251  * Description:
8252  * Allocates existing keys to zones
8253  *
8254  * Arguments:
8255  * policy
8256  * policy that the keys were created for
8257  * key_type
8258  * KSK or ZSK
8259  * zone_id
8260  * ID of zone in question
8261  * interval
8262  * time before next run
8263  * zone_name
8264  * just in case we need to log something
8265  * man_key_gen
8266  * lack of keys may be an issue for the user to fix
8267  * int rollover_scheme
8268  * KSK rollover scheme in use
8269  *
8270  * Returns:
8271  * int
8272  * Status return. 0=> Success, non-zero => error.
8273  * 1 == error with input
8274  * 2 == not enough keys to satisfy policy
8275  * 3 == database error
8276  -*/
8277 
8278 
8279 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)
8280 {
8281  int status = 0;
8282  int keys_needed = 0;
8283  int keys_in_queue = 0;
8284  int keys_pending_retirement = 0;
8285  int new_keys = 0;
8286  int key_pair_id = 0;
8287  int i = 0;
8288  DB_ID ignore = 0;
8289  KSM_PARCOLL collection; /* Parameters collection */
8290  char* datetime = DtParseDateTimeString("now");
8291 
8292  /* Check datetime in case it came back NULL */
8293  if (datetime == NULL) {
8294  printf("Couldn't turn \"now\" into a date, quitting...");
8295  exit(1);
8296  }
8297 
8298  if (policy == NULL) {
8299  printf("NULL policy sent to allocateKeysToZone");
8300  StrFree(datetime);
8301  return 1;
8302  }
8303 
8304  if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) {
8305  printf("Unknown keytype: %i in allocateKeysToZone", key_type);
8306  StrFree(datetime);
8307  return 1;
8308  }
8309 
8310  /* Get list of parameters */
8311  status = KsmParameterCollection(&collection, policy->id);
8312  if (status != 0) {
8313  StrFree(datetime);
8314  return status;
8315  }
8316 
8317  /* Make sure that enough keys are allocated to this zone */
8318  /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */
8319  status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1);
8320  if (status != 0) {
8321  printf("Could not predict key requirement for next interval for %s", zone_name);
8322  StrFree(datetime);
8323  return 3;
8324  }
8325 
8326  /* How many do we have ? TODO should this include the currently active key?*/
8327  status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id);
8328  if (status != 0) {
8329  printf("Could not count current key numbers for zone %s", zone_name);
8330  StrFree(datetime);
8331  return 3;
8332  }
8333 
8334  /* or about to retire */
8335  status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval);
8336  if (status != 0) {
8337  printf("Could not count keys which may retire before the next run (for zone %s)", zone_name);
8338  StrFree(datetime);
8339  return 3;
8340  }
8341 
8342  StrFree(datetime);
8343  new_keys = keys_needed - (keys_in_queue - keys_pending_retirement);
8344 
8345  /* 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); */
8346 
8347  /* Allocate keys */
8348  for (i=0 ; i < new_keys ; i++){
8349  key_pair_id = 0;
8350  if (key_type == KSM_TYPE_KSK) {
8351  status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
8352  if (status == -1 || key_pair_id == 0) {
8353  if (man_key_gen == 0) {
8354  printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name);
8355  printf("ods-enforcerd will create some more keys on its next run");
8356  }
8357  else {
8358  printf("Not enough keys to satisfy ksk policy for zone: %s", zone_name);
8359  printf("please use \"ods-ksmutil key generate\" to create some more keys.");
8360  }
8361  return 2;
8362  }
8363  else if (status != 0) {
8364  printf("Could not get an unallocated ksk for zone: %s", zone_name);
8365  return 3;
8366  }
8367  } else {
8368  status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
8369  if (status == -1 || key_pair_id == 0) {
8370  if (man_key_gen == 0) {
8371  printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name);
8372  printf("ods-enforcerd will create some more keys on its next run");
8373  }
8374  else {
8375  printf("Not enough keys to satisfy zsk policy for zone: %s", zone_name);
8376  printf("please use \"ods-ksmutil key generate\" to create some more keys.");
8377  }
8378  return 2;
8379  }
8380  else if (status != 0) {
8381  printf("Could not get an unallocated zsk for zone: %s", zone_name);
8382  return 3;
8383  }
8384  }
8385  if(key_pair_id > 0) {
8386  status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, NULL, &ignore);
8387  /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */
8388  } else {
8389  /* This shouldn't happen */
8390  printf("KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name);
8391  exit(1);
8392  }
8393 
8394  }
8395 
8396  return status;
8397 }
8398 
8399 
8400 /* keyRoll
8401  *
8402  * Description:
8403  * Rolls keys far enough for the enforcer to take over
8404  *
8405  * Arguments:
8406  * zone_id
8407  * ID of zone in question (-1 == all)
8408  * policy_id
8409  * policy that should be rolled (-1 == all)
8410  * key_type
8411  * KSK or ZSK (-1 == all)
8412  *
8413  * Returns:
8414  * int
8415  * Status return. 0=> Success, non-zero => error.
8416  -*/
8417 
8418 int keyRoll(int zone_id, int policy_id, int key_type)
8419 {
8420 
8421  int status = 0;
8422  int size = -1;
8423 
8424  char* sql = NULL; /* SQL query */
8425  char* sql1 = NULL; /* SQL query */
8426  char sql2[KSM_SQL_SIZE];
8427  DB_RESULT result1; /* Result of the query */
8428  DB_ROW row = NULL; /* Row data */
8429  int temp_id = -1; /* place to store the key id returned */
8430  int temp_type = -1; /* place to store the key type returned */
8431  int temp_zone_id = -1; /* place to store the zone id returned */
8432  int where = 0;
8433  int j = 0;
8434  DB_RESULT result2; /* Result of the query */
8435  DB_RESULT result3; /* Result of the query */
8436  DB_ROW row2 = NULL; /* Row data */
8437  char* insql1 = NULL; /* SQL query */
8438  char* insql2 = NULL; /* SQL query */
8439  char buffer[32]; /* For integer conversion */
8440 
8441  char* datetime = DtParseDateTimeString("now");
8442 
8443  /* Check datetime in case it came back NULL */
8444  if (datetime == NULL) {
8445  printf("Couldn't turn \"now\" into a date, quitting...\n");
8446  StrFree(datetime);
8447  exit(1);
8448  }
8449 
8450  /* retire the active key(s) */
8451  /* Find the key ID */
8452  sql = DqsSpecifyInit("KEYDATA_VIEW","id, keytype");
8453  if (zone_id != -1) {
8454  DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, where++);
8455  }
8456  if (policy_id != -1) {
8457  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
8458  }
8459  DqsConditionInt(&sql, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
8460  if (key_type != -1) {
8461  DqsConditionInt(&sql, "keytype", DQS_COMPARE_EQ, key_type, where++);
8462  }
8463  DqsEnd(&sql);
8464 
8465  status = DbExecuteSql(DbHandle(), sql, &result1);
8466 
8467  if (status == 0) {
8468  status = DbFetchRow(result1, &row);
8469  while (status == 0) {
8470  /* Got a row, deal with it */
8471  DbInt(row, 0, &temp_id);
8472  DbInt(row, 1, &temp_type);
8473 
8474  sql1 = DusInit("keypairs");
8475  DusSetInt(&sql1, "fixedDate", 1, 0);
8476  DusSetInt(&sql1, "compromisedflag", 1, 1);
8477 
8478  DusConditionInt(&sql1, "id", DQS_COMPARE_EQ, temp_id, 0);
8479  DusEnd(&sql1);
8480  status = DbExecuteSqlNoResult(DbHandle(), sql1);
8481  DusFree(sql1);
8482 
8483  /* Report any errors */
8484  if (status != 0) {
8485  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8486  DbFreeRow(row);
8487  return status;
8488  }
8489 
8490  /* Loop over instances of this key: */
8491  /* active-> set retire time */
8492  sql1 = DusInit("dnsseckeys");
8493  DusSetString(&sql1, "RETIRE", datetime, 0);
8494 
8495  DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
8496  DusConditionInt(&sql1, "state", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, 1);
8497  DusEnd(&sql1);
8498  status = DbExecuteSqlNoResult(DbHandle(), sql1);
8499  DusFree(sql1);
8500 
8501  /* Report any errors */
8502  if (status != 0) {
8503  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8504  DbFreeRow(row);
8505  return status;
8506  }
8507 
8508  /* other-> move to dead */
8509  sql1 = DusInit("dnsseckeys");
8510  DusSetString(&sql1, "DEAD", datetime, 0);
8511  DusSetInt(&sql1, "state", KSM_STATE_DEAD, 1);
8512 
8513  DusConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
8514  DusConditionInt(&sql1, "state", DQS_COMPARE_NE, KSM_STATE_ACTIVE, 1);
8515  DusEnd(&sql1);
8516  status = DbExecuteSqlNoResult(DbHandle(), sql1);
8517  DusFree(sql1);
8518 
8519  /* Report any errors */
8520  if (status != 0) {
8521  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8522  DbFreeRow(row);
8523  return status;
8524  }
8525 
8526  /* Promote any standby keys if we need to, i.e. we retired a KSK
8527  and there is nothing able to take over from it */
8528  if (temp_type == KSM_TYPE_KSK) {
8529  /* find each zone in turn */
8530  /* Depressingly MySQL can't run the following sql; so we need
8531  to build it by parts... There has to be a better way to do
8532  this.
8533  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); */
8534 
8535  /* First INSQL: select zone_id from dnsseckeys where retire = "DATETIME" and keypair_id = temp_id*/
8536 
8537  size = snprintf(sql2, KSM_SQL_SIZE, "select zone_id from dnsseckeys where retire = \"%s\" and keypair_id = %d", datetime, temp_id);
8538  status = DbExecuteSql(DbHandle(), sql2, &result2);
8539  if (status == 0) {
8540  status = DbFetchRow(result2, &row2);
8541  while (status == 0) {
8542  /* Got a row, print it */
8543  DbInt(row2, 0, &temp_zone_id);
8544 
8545  if (j != 0) {
8546  StrAppend(&insql1, ",");
8547  }
8548  snprintf(buffer, sizeof(buffer), "%d", temp_zone_id);
8549  StrAppend(&insql1, buffer);
8550  j++;
8551 
8552  status = DbFetchRow(result2, &row2);
8553  }
8554 
8555  /* Convert EOF status to success */
8556 
8557  if (status == -1) {
8558  status = 0;
8559  }
8560 
8561  DbFreeResult(result2);
8562  }
8563 
8564  /* Second INSQL: select zone_id from KEYDATA_VIEW where policy_id = policy_id and keytype = KSK and state in (publish,ready) */
8565 
8566  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);
8567  j=0;
8568  status = DbExecuteSql(DbHandle(), sql2, &result3);
8569  if (status == 0) {
8570  status = DbFetchRow(result3, &row2);
8571  while (status == 0) {
8572  /* Got a row, print it */
8573  DbInt(row2, 0, &temp_zone_id);
8574 
8575  if (j != 0) {
8576  StrAppend(&insql2, ",");
8577  }
8578  snprintf(buffer, sizeof(buffer), "%d", temp_zone_id);
8579  StrAppend(&insql2, buffer);
8580  j++;
8581 
8582  status = DbFetchRow(result3, &row2);
8583  }
8584 
8585  /* Convert EOF status to success */
8586 
8587  if (status == -1) {
8588  status = 0;
8589  }
8590 
8591  DbFreeResult(result3);
8592  }
8593  DbFreeRow(row2);
8594 
8595  /* Finally we can do the update */
8596  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);
8597 
8598  /* Quick check that we didn't run out of space */
8599  if (size < 0 || size >= KSM_SQL_SIZE) {
8600  printf("Couldn't construct SQL to promote standby key\n");
8601  DbFreeRow(row);
8602  return -1;
8603  }
8604 
8605  status = DbExecuteSqlNoResult(DbHandle(), sql2);
8606 
8607  /* Report any errors */
8608  if (status != 0) {
8609  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8610  DbFreeRow(row);
8611  return status;
8612  }
8613  }
8614 
8615  /* NEXT KEY */
8616  status = DbFetchRow(result1, &row);
8617  }
8618 
8619  /* Convert EOF status to success */
8620  if (status == -1) {
8621  status = 0;
8622  }
8623  DbFreeResult(result1);
8624  }
8625  DqsFree(sql);
8626  DbFreeRow(row);
8627 
8628  StrFree(datetime);
8629 
8630  return status;
8631 }
8632 
8634 {
8635  int where = 0; /* WHERE clause value */
8636  char* sql = NULL; /* SQL query */
8637  DB_RESULT result; /* Handle converted to a result object */
8638  DB_ROW row = NULL; /* Row data */
8639  int status = 0; /* Status return */
8640 
8641  /* Construct the query */
8642 
8643  sql = DqsSpecifyInit("policies","id, name");
8644  DqsConditionInt(&sql, "ID", DQS_COMPARE_EQ, zone->policy_id, where++);
8645  DqsOrderBy(&sql, "id");
8646 
8647  /* Execute query and free up the query string */
8648  status = DbExecuteSql(DbHandle(), sql, &result);
8649  DqsFree(sql);
8650 
8651  if (status != 0)
8652  {
8653  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8654  DbFreeResult(result);
8655  return status;
8656  }
8657 
8658  /* Get the next row from the data */
8659  status = DbFetchRow(result, &row);
8660  if (status == 0) {
8661  DbStringBuffer(row, DB_POLICY_NAME, zone->policy_name, KSM_NAME_LENGTH*sizeof(char));
8662  }
8663  else if (status == -1) {}
8664  /* No rows to return (but no error) */
8665  else {
8666  printf("SQL failed: %s\n", DbErrmsg(DbHandle()));
8667  return status;
8668  }
8669 
8670  DbFreeRow(row);
8671  DbFreeResult(result);
8672  return status;
8673 }
8674 
8675 int append_zone(xmlDocPtr doc, KSM_ZONE *zone)
8676 {
8677  xmlNodePtr root;
8678  xmlNodePtr zone_node;
8679  xmlNodePtr adapters_node;
8680  xmlNodePtr input_node;
8681  xmlNodePtr output_node;
8682 
8683  root = xmlDocGetRootElement(doc);
8684  if (root == NULL) {
8685  fprintf(stderr,"empty document\n");
8686  return(1);
8687  }
8688  if (xmlStrcmp(root->name, (const xmlChar *) "ZoneList")) {
8689  fprintf(stderr,"document of the wrong type, root node != %s", "ZoneList");
8690  return(1);
8691  }
8692 
8693  zone_node = xmlNewTextChild(root, NULL, (const xmlChar *)"Zone", NULL);
8694  (void) xmlNewProp(zone_node, (const xmlChar *)"name", (const xmlChar *)zone->name);
8695 
8696  /* Policy */
8697  (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Policy", (const xmlChar *)zone->policy_name);
8698 
8699  /* SignConf */
8700  (void) xmlNewTextChild(zone_node, NULL, (const xmlChar *)"SignerConfiguration", (const xmlChar *)zone->signconf);
8701 
8702  /* Adapters */
8703  adapters_node = xmlNewTextChild(zone_node, NULL, (const xmlChar *)"Adapters", NULL);
8704  /* Input */
8705  input_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Input", NULL);
8706  (void) xmlNewTextChild(input_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->input);
8707  /* Output */
8708  output_node = xmlNewTextChild(adapters_node, NULL, (const xmlChar *)"Output", NULL);
8709  (void) xmlNewTextChild(output_node, NULL, (const xmlChar *)"File", (const xmlChar *)zone->output);
8710 
8711 
8712  return(0);
8713 }
8714 
8715 int ShellQuoteString(const char* string, char* buffer, size_t buflen)
8716 {
8717  size_t i; /* Loop counter */
8718  size_t j = 0; /* Counter for new string */
8719 
8720  size_t len = strlen(string);
8721 
8722  if (string) {
8723  for (i = 0; i < len; ++i) {
8724  if (string[i] == '\'') {
8725  buffer[j++] = '\'';
8726  buffer[j++] = '\\';
8727  buffer[j++] = '\'';
8728  }
8729  buffer[j++] = string[i];
8730  }
8731  }
8732  buffer[j] = '\0';
8733  return ( (j <= buflen) ? 0 : 1);
8734 }
8735 
8736 int rename_signconf(const char* zonelist_filename, const char* o_zone) {
8737  int status = 0;
8738  char* signconf = NULL;
8739  char* moved_signconf = NULL;
8740  char* zone_name = NULL;
8741  int i = 0;
8742 
8743  /* All of the XML stuff */
8744  xmlDocPtr doc = NULL;
8745  xmlNode *curNode;
8746  xmlXPathContextPtr xpathCtx = NULL;
8747  xmlXPathObjectPtr xpathObj = NULL;
8748 
8749  xmlChar *node_expr = (unsigned char*) "//Zone";
8750 /* Load XML document */
8751  doc = xmlParseFile(zonelist_filename);
8752  if (doc == NULL) {
8753  printf("Error: unable to parse file \"%s\"\n", zonelist_filename);
8754  return(-1);
8755  }
8756 /* Create xpath evaluation context */
8757  xpathCtx = xmlXPathNewContext(doc);
8758  if(xpathCtx == NULL) {
8759  xmlFreeDoc(doc);
8760  return(1);
8761  }
8762 
8763  /* Evaluate xpath expression */
8764  xpathObj = xmlXPathEvalExpression(node_expr, xpathCtx);
8765  if(xpathObj == NULL) {
8766  xmlXPathFreeContext(xpathCtx);
8767  xmlFreeDoc(doc);
8768  return(1);
8769  }
8770 
8771  if (xpathObj->nodesetval) {
8772  for (i = 0; i < xpathObj->nodesetval->nodeNr; i++) {
8773 
8774  curNode = xpathObj->nodesetval->nodeTab[i]->xmlChildrenNode;
8775  zone_name = (char *) xmlGetProp(xpathObj->nodesetval->nodeTab[i], (const xmlChar *)"name");
8776 
8777  if (all_flag || (strlen(zone_name) == strlen(o_zone) &&
8778  strncmp(zone_name, o_zone, strlen(zone_name)) == 0)) {
8779 
8780  while (curNode) {
8781 
8782  if (xmlStrEqual(curNode->name, (const xmlChar *)"SignerConfiguration")) {
8783  StrAppend(&signconf, (char *) xmlNodeGetContent(curNode));
8784  StrAppend(&moved_signconf, signconf);
8785  StrAppend(&moved_signconf, ".ZONE_DELETED");
8786  /* Do the move */
8787  status = rename(signconf, moved_signconf);
8788  if (status != 0 && errno != ENOENT)
8789  {
8790  /* cope with initial condition of files not existing */
8791  printf("Could not rename: %s -> %s", signconf, moved_signconf);
8792  StrFree(signconf);
8793  StrFree(moved_signconf);
8794  return(1);
8795  }
8796  StrFree(signconf);
8797  StrFree(moved_signconf);
8798 
8799  break;
8800  }
8801 
8802  curNode = curNode->next;
8803  }
8804 
8805  if (!all_flag) {
8806  break;
8807  }
8808  }
8809  }
8810  }
8811 
8812  return 0;
8813 }
8814