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