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