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