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