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