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