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