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