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