OpenDNSSEC-enforcer  1.4.3
enforcer.c
Go to the documentation of this file.
1 /*
2  * $Id: enforcer.c 7401 2013-11-14 15:46:25Z 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 
29 /*
30  * enforcer.c code implements the server_main
31  * function needed by daemon.c
32  *
33  * The bit that makes the daemon do something useful
34  */
35 
36 #include "config.h"
37 
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <string.h>
41 #include <stdio.h>
42 #include <syslog.h>
43 #include <sys/stat.h>
44 
45 #include <libxml/xmlreader.h>
46 #include <libxml/xpath.h>
47 
48 #include "daemon.h"
49 #include "daemon_util.h"
50 #include "enforcer.h"
51 #include "kaspaccess.h"
52 
53 #include "ksm/ksm.h"
54 #include "ksm/memory.h"
55 #include "ksm/string_util.h"
56 #include "ksm/string_util2.h"
57 #include "ksm/datetime.h"
58 #include "ksm/db_fields.h"
59 
60 #include "libhsm.h"
61 #include "libhsmdns.h"
62 
63 int
65 {
66  if (config == NULL) {
67  log_msg(NULL, LOG_ERR, "Error in server_init, no config provided");
68  exit(1);
69  }
70 
71  /* set the default pidfile if nothing was provided on the command line*/
72  if (config->pidfile == NULL) {
73  config->pidfile = OPENDNSSEC_ENFORCER_PIDFILE;
74  }
75 
76  return 0;
77 }
78 
79 /*
80  * Main loop of enforcerd server
81  */
82 void
84 {
85  DB_RESULT handle;
86  DB_HANDLE dbhandle;
87  int status = 0;
88  struct timeval tv;
89  KSM_POLICY *policy;
90  int result;
91  hsm_ctx_t *ctx = NULL;
92  char *hsm_error_message = NULL;
93 
94  FILE *lock_fd = NULL; /* for sqlite file locking */
95  char *lock_filename = NULL;
96 
97  if (config == NULL) {
98  log_msg(NULL, LOG_ERR, "Error in server_main, no config provided");
99  exit(1);
100  }
101 
102  policy = KsmPolicyAlloc();
103  if (policy == NULL) {
104  log_msg(config, LOG_ERR, "Malloc for policy struct failed");
105  exit(1);
106  }
107  kaspSetPolicyDefaults(policy, NULL);
108 
109  /* Read the config file */
110  status = ReadConfig(config , 0);
111  if (status != 0) {
112  log_msg(config, LOG_ERR, "Error reading config");
113  exit(1);
114  }
115 
116  /* If we are doing key generation then connect to the hsm */
117 /* if (config->manualKeyGeneration == 0) {*/
118  /* We keep the HSM connection open for the lifetime of the daemon */
119  if (config->configfile != NULL) {
120  result = hsm_open(config->configfile, hsm_check_pin);
121  } else {
122  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_check_pin);
123  }
124  if (result) {
125  hsm_error_message = hsm_get_error(ctx);
126  if (hsm_error_message) {
127  log_msg(config, LOG_ERR, "%s", hsm_error_message);
128  free(hsm_error_message);
129  } else {
130  /* decode the error code ourselves
131  TODO find if there is a better way to do this (and can all of these be returned? are there others?) */
132  switch (result) {
133  case HSM_ERROR:
134  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
135  break;
136  case HSM_PIN_INCORRECT:
137  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
138  break;
139  case HSM_CONFIG_FILE_ERROR:
140  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
141  break;
142  case HSM_REPOSITORY_NOT_FOUND:
143  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
144  break;
145  case HSM_NO_REPOSITORIES:
146  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
147  break;
148  default:
149  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
150  }
151  }
152  exit(1);
153  }
154  log_msg(config, LOG_INFO, "HSM opened successfully.");
155  ctx = hsm_create_context();
156  /*}*/
157 
158  log_msg(config, LOG_INFO, "Checking database connection...");
159  if (kaspTryConnect(config, &dbhandle)) {
160  log_msg(config, LOG_ERR, "Database connection failed");
161  exit(1);
162  }
163  log_msg(config, LOG_INFO, "Database connection ok.");
164 
165  /* Create pidfile as late as possible to report start up error */
166  if (writepid(config) == -1) {
167  log_msg(config, LOG_ERR, "cannot write the pidfile %s: %s",
168  config->pidfile, strerror(errno));
169  exit(1);
170  }
171 
172  while (1) {
173 
174  /* Read the config file */
175  status = ReadConfig(config, 1);
176  if (status != 0) {
177  log_msg(config, LOG_ERR, "Error reading config");
178  unlink(config->pidfile);
179  exit(1);
180  }
181  /* If we are in sqlite mode then take a lock out on a file to
182  prevent multiple access (not sure that we can be sure that sqlite is
183  safe for multiple processes to access). */
184  if (DbFlavour() == SQLITE_DB) {
185 
186  /* set up lock filename (it may have changed?) */
187  lock_filename = NULL;
188  StrAppend(&lock_filename, (char *)config->schema);
189  StrAppend(&lock_filename, ".our_lock");
190 
191  lock_fd = fopen(lock_filename, "w");
192  status = get_lite_lock(lock_filename, lock_fd);
193  StrFree(lock_filename);
194  if (status != 0) {
195  log_msg(config, LOG_ERR, "Error getting db lock");
196  unlink(config->pidfile);
197  exit(1);
198  }
199  }
200 
201  log_msg(config, LOG_INFO, "Connecting to Database...");
202  kaspConnect(config, &dbhandle);
203 
204  /* check if any specific policy was passed as an arg */
205  if (config->policy != NULL) {
206  log_msg(config, LOG_INFO, "Will only process policy \"%s\" as specified on the command line with the --policy option.", config->policy);
207  status = KsmPolicyExists(config->policy);
208  if (status != 0) {
209  log_msg(config, LOG_ERR, "Policy \"%s\" not found. Exiting.", config->policy);
210  unlink(config->pidfile);
211  exit(1);
212  }
213  }
214  /* Read all policies.
215  If config->policy is NULL this will return all the policies, if not NULL then just that policy */
216  status = KsmPolicyInit(&handle, config->policy);
217  if (status == 0) {
218  /* get the first policy */
219  status = KsmPolicy(handle, policy);
220  while (status == 0) {
221  log_msg(config, LOG_INFO, "Policy %s found.", policy->name);
222  /* Clear the policy struct */
223  kaspSetPolicyDefaults(policy, NULL);
224 
225  /* Read the parameters for that policy */
226  status = kaspReadPolicy(policy);
227 
228  /* Update the salt if it is not up to date */
229  if (policy->denial->version == 3)
230  {
231  status = KsmPolicyUpdateSalt(policy);
232  if (status != 0) {
233  /* Don't return? */
234  log_msg(config, LOG_ERR, "Error (%d) updating salt for %s", status, policy->name);
235  }
236  }
237 
238  /* Do keygen stuff if required */
239  if (config->manualKeyGeneration == 0) {
240  status = do_keygen(config, policy, ctx);
241  }
242 
243  /* TODO move communicated stuff here eventually */
244  /* Find all zones and do communication stuff */
245 
246  /* Purge dead keys if we are asked to in this policy */
247  if (policy->keys->purge != -1) {
248  status = do_purge(policy->keys->purge, policy->id);
249  }
250 
251  /* get next policy */
252  status = KsmPolicy(handle, policy);
253  }
254  } else {
255  log_msg(config, LOG_ERR, "Error querying KASP DB for policies.");
256  unlink(config->pidfile);
257  exit(1);
258  }
259 
260  /* Communicate zones to the signer */
261  KsmParameterCollectionCache(1); /* Enable caching of policy parameters while in do_communication() */
262  /* If config->policy is NULL then we were not passed a policy on the cmd line and all the policies
263  should be processed. However if we have a specific policy, then the 'policy' parameter will be
264  already set to that when we call do_communiciation and only that policy will be processed. */
265  do_communication(config, policy, (config->policy == NULL));
267 
268  DbFreeResult(handle);
269 
270  /* Disconnect from DB in case we are asleep for a long time */
271  log_msg(config, LOG_INFO, "Disconnecting from Database...");
272  kaspDisconnect(&dbhandle);
273 
274  /* Release sqlite lock file (if we have it) */
275  if (DbFlavour() == SQLITE_DB) {
276  status = release_lite_lock(lock_fd);
277  if (status != 0) {
278  log_msg(config, LOG_ERR, "Error releasing db lock");
279  unlink(config->pidfile);
280  exit(1);
281  }
282  fclose(lock_fd);
283  }
284 
285  if (config->once == true ){
286  log_msg(config, LOG_INFO, "Running once only, exiting...");
287  break;
288  }
289 
290  /* If we have been sent a SIGTERM then it is time to exit */
291  if (config->term == 1 ){
292  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
293  break;
294  }
295  /* Or SIGINT */
296  if (config->term == 2 ){
297  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
298  break;
299  }
300 
301  /* sleep for the interval */
302  tv.tv_sec = config->interval;
303  tv.tv_usec = 0;
304  log_msg(config, LOG_INFO, "Sleeping for %i seconds.",config->interval);
305  select(0, NULL, NULL, NULL, &tv);
306 
307  /* If we have been sent a SIGTERM then it is time to exit */
308  if (config->term == 1 ){
309  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
310  break;
311  }
312  /* Or SIGINT */
313  if (config->term == 2 ){
314  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
315  break;
316  }
317 
318  /* Make sure that we can still talk to the HSM; this call exits if
319  we can not (after trying to reconnect) */
320  check_hsm_connection(&ctx, config);
321  }
322 
323  /*
324  * Destroy HSM context
325  */
326  if (ctx) {
327  hsm_destroy_context(ctx);
328  }
329 
330  result = hsm_close();
331  log_msg(config, LOG_INFO, "all done! hsm_close result: %d", result);
332 
333  KsmPolicyFree(policy);
334 
335  if (unlink(config->pidfile) == -1) {
336  log_msg(config, LOG_ERR, "unlink pidfile %s failed: %s",
337  config->pidfile?config->pidfile:"(null)",
338  strerror(errno));
339  }
340 
341  xmlCleanupParser();
342 
343 }
344 
345 int do_keygen(DAEMONCONFIG *config, KSM_POLICY* policy, hsm_ctx_t *ctx)
346 {
347  int status = 0;
348 
349  char *rightnow;
350  int i = 0;
351  char *id;
352  hsm_key_t *key = NULL;
353  char *hsm_error_message = NULL;
354  DB_ID ignore = 0;
355  int ksks_needed = 0; /* Total No of ksks needed before next generation run */
356  int zsks_needed = 0; /* Total No of zsks needed before next generation run */
357  int keys_in_queue = 0; /* number of unused keys */
358  int new_keys = 0; /* number of keys required */
359  unsigned int current_count = 0; /* number of keys already in HSM */
360 
361  int same_keys = 0; /* Do ksks and zsks look the same ? */
362  int ksks_created = 0; /* Were any KSKs created? */
363 
364  DB_RESULT result;
365  int zone_count = 0; /* Number of zones on policy */
366 
367  if (policy->shared_keys == 1 ) {
368  log_msg(config, LOG_INFO, "Key sharing is On");
369  } else {
370  log_msg(config, LOG_INFO, "Key sharing is Off.");
371  }
372 
373  rightnow = DtParseDateTimeString("now");
374 
375  /* Check datetime in case it came back NULL */
376  if (rightnow == NULL) {
377  log_msg(config, LOG_ERR, "Couldn't turn \"now\" into a date, quitting...");
378  exit(1);
379  }
380 
381  /* See if our ZSKs and KSKs look the same */
382  if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) {
383  same_keys = 1;
384  } else {
385  same_keys = 0;
386  }
387 
388  /* How many zones on this policy */
389  status = KsmZoneCountInit(&result, policy->id);
390  if (status == 0) {
391  status = KsmZoneCount(result, &zone_count);
392  }
393  DbFreeResult(result);
394 
395  if (status == 0) {
396  /* make sure that we have at least one zone */
397  if (zone_count == 0) {
398  log_msg(config, LOG_INFO, "No zones on policy %s, skipping...", policy->name);
399  StrFree(rightnow);
400  return status;
401  }
402  } else {
403  log_msg(NULL, LOG_ERR, "Could not count zones on policy %s", policy->name);
404  StrFree(rightnow);
405  return status;
406  }
407  log_msg(config, LOG_INFO, "%d zone(s) found on policy \"%s\"\n", zone_count, policy->name);
408 
409  /* Find out how many ksk keys are needed for the POLICY */
410  status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, config->interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count);
411  if (status != 0) {
412  log_msg(NULL, LOG_ERR, "Could not predict ksk requirement for next interval for %s", policy->name);
413  /* TODO exit? continue with next policy? */
414  }
415  /* Find out how many suitable keys we have */
416  status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_KSK);
417  if (status != 0) {
418  log_msg(NULL, LOG_ERR, "Could not count current ksk numbers for policy %s", policy->name);
419  /* TODO exit? continue with next policy? */
420  }
421  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
422 
423  new_keys = ksks_needed - keys_in_queue;
424  /* fprintf(stderr, "keygen(ksk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, ksks_needed, keys_in_queue); */
425 
426  /* Check capacity of HSM will not be exceeded */
427  if (policy->ksk->sm_capacity != 0 && new_keys >= 0) {
428  current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name);
429  if (current_count >= policy->ksk->sm_capacity) {
430  log_msg(config, LOG_ERR, "Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name);
431  new_keys = 0;
432  }
433  else if (current_count + new_keys > policy->ksk->sm_capacity) {
434  log_msg(config, LOG_WARNING, "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);
435  new_keys = policy->ksk->sm_capacity - current_count;
436  }
437  }
438  if (new_keys <= 0 ) {
439  log_msg(config, LOG_INFO,"No new KSKs need to be created.\n");
440  }
441  else {
442  log_msg(config, LOG_INFO,"%d new KSK(s) (%d bits) need to be created.\n", new_keys, policy->ksk->bits);
443  }
444 
445  /* Create the required keys */
446  for (i=new_keys ; i > 0 ; i--){
447  if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) {
448  /* NOTE: for now we know that libhsm only supports RSA keys */
449  key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits);
450  if (key) {
451  log_msg(config, LOG_DEBUG, "Created key in repository %s", policy->ksk->sm_name);
452  } else {
453  log_msg(config, LOG_ERR, "Error creating key in repository %s", policy->ksk->sm_name);
454  hsm_error_message = hsm_get_error(ctx);
455  if (hsm_error_message) {
456  log_msg(config, LOG_ERR, "%s", hsm_error_message);
457  free(hsm_error_message);
458  }
459  unlink(config->pidfile);
460  exit(1);
461  }
462  id = hsm_get_key_id(ctx, key);
463  hsm_key_free(key);
464  status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore);
465  if (status != 0) {
466  log_msg(config, LOG_ERR,"Error creating key in Database");
467  hsm_error_message = hsm_get_error(ctx);
468  if (hsm_error_message) {
469  log_msg(config, LOG_ERR, "%s", hsm_error_message);
470  free(hsm_error_message);
471  }
472  unlink(config->pidfile);
473  exit(1);
474  }
475  log_msg(config, LOG_INFO, "Created KSK size: %i, alg: %i with id: %s in repository: %s and database.", policy->ksk->bits,
476  policy->ksk->algorithm, id, policy->ksk->sm_name);
477  free(id);
478  } else {
479  log_msg(config, LOG_ERR, "Key algorithm %d unsupported by libhsm, exiting...", policy->ksk->algorithm);
480  unlink(config->pidfile);
481  exit(1);
482  }
483  }
484  ksks_created = new_keys;
485 
486  /* Find out how many zsk keys are needed */
487  keys_in_queue = 0;
488  new_keys = 0;
489  current_count = 0;
490 
491  /* Find out how many zsk keys are needed for the POLICY */
492  status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, config->interval, &zsks_needed, 0, zone_count);
493  if (status != 0) {
494  log_msg(NULL, LOG_ERR, "Could not predict zsk requirement for next intervalfor %s", policy->name);
495  /* TODO exit? continue with next policy? */
496  }
497  /* Find out how many suitable keys we have */
498  status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK);
499  if (status != 0) {
500  log_msg(NULL, LOG_ERR, "Could not count current zsk numbers for policy %s", policy->name);
501  /* TODO exit? continue with next policy? */
502  }
503  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
504  /* Might have to account for ksks */
505  if (same_keys) {
506  keys_in_queue -= ksks_needed;
507  }
508 
509  new_keys = zsks_needed - keys_in_queue;
510  /* fprintf(stderr, "keygen(zsk): new_keys(%d) = keys_needed(%d) - keys_in_queue(%d)\n", new_keys, zsks_needed, keys_in_queue); */
511 
512  /* Check capacity of HSM will not be exceeded */
513  if (policy->zsk->sm_capacity != 0 && new_keys >= 0) {
514  current_count = hsm_count_keys_repository(ctx, policy->zsk->sm_name);
515  if (current_count >= policy->zsk->sm_capacity) {
516  log_msg(config, LOG_ERR, "Repository %s is full, cannot create more ZSKs for policy %s\n", policy->zsk->sm_name, policy->name);
517  new_keys = 0;
518  }
519  else if (current_count + new_keys > policy->zsk->sm_capacity) {
520  log_msg(config, LOG_WARNING, "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);
521  new_keys = policy->zsk->sm_capacity - current_count;
522  }
523  }
524 
525  if (new_keys <= 0 ) {
526  /* Don't exit here, just fall through to the end */
527  log_msg(config, LOG_INFO, "No new ZSKs need to be created.\n");
528  }
529  else {
530  log_msg(config, LOG_INFO, "%d new ZSK(s) (%d bits) need to be created.\n", new_keys, policy->zsk->bits);
531  }
532 
533  /* Create the required keys */
534  for (i = new_keys ; i > 0 ; i--) {
535  if (hsm_supported_algorithm(policy->zsk->algorithm) == 0) {
536  /* NOTE: for now we know that libhsm only supports RSA keys */
537  key = hsm_generate_rsa_key(ctx, policy->zsk->sm_name, policy->zsk->bits);
538  if (key) {
539  log_msg(config, LOG_DEBUG, "Created key in repository %s", policy->zsk->sm_name);
540  } else {
541  log_msg(config, LOG_ERR, "Error creating key in repository %s", policy->zsk->sm_name);
542  hsm_error_message = hsm_get_error(ctx);
543  if (hsm_error_message) {
544  log_msg(config, LOG_ERR, "%s", hsm_error_message);
545  free(hsm_error_message);
546  }
547  unlink(config->pidfile);
548  hsm_key_free(key);
549  exit(1);
550  }
551  id = hsm_get_key_id(ctx, key);
552  hsm_key_free(key);
553  status = KsmKeyPairCreate(policy->id, id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, rightnow, &ignore);
554  if (status != 0) {
555  log_msg(config, LOG_ERR,"Error creating key in Database");
556  hsm_error_message = hsm_get_error(ctx);
557  if (hsm_error_message) {
558  log_msg(config, LOG_ERR, "%s", hsm_error_message);
559  free(hsm_error_message);
560  }
561  unlink(config->pidfile);
562  exit(1);
563  }
564  log_msg(config, LOG_INFO, "Created ZSK size: %i, alg: %i with id: %s in repository: %s and database.", policy->zsk->bits,
565  policy->zsk->algorithm, id, policy->zsk->sm_name);
566  free(id);
567  } else {
568  log_msg(config, LOG_ERR, "Key algorithm %d unsupported by libhsm, exiting...", policy->zsk->algorithm);
569  unlink(config->pidfile);
570  exit(1);
571  }
572  }
573  StrFree(rightnow);
574 
575  /* Log if a backup needs to be run for these keys */
576  if (ksks_created && policy->ksk->require_backup) {
577  log_msg(config, LOG_INFO, "NOTE: keys generated in repository %s will not become active until they have been backed up", policy->ksk->sm_name);
578  }
579  if (new_keys && policy->zsk->require_backup && (policy->zsk->sm != policy->ksk->sm)) {
580  log_msg(config, LOG_INFO, "NOTE: keys generated in repository %s will not become active until they have been backed up", policy->zsk->sm_name);
581  }
582 
583  return status;
584 }
585 
586 int do_communication(DAEMONCONFIG *config, KSM_POLICY* policy, bool all_policies)
587 {
588  int status = 0;
589  int status2 = 0;
590 
591  xmlTextReaderPtr reader = NULL;
592  xmlDocPtr doc = NULL;
593  xmlXPathContextPtr xpathCtx = NULL;
594  xmlXPathObjectPtr xpathObj = NULL;
595 
596  int ret = 0; /* status of the XML parsing */
597  char* zonelist_filename = NULL;
598  char* zone_name;
599  char* current_policy;
600  char* current_filename;
601  char *tag_name = NULL;
602  int zone_id = -1;
603  int signer_flag = 1; /* Is the signer responding? (1 == yes) */
604  char* ksk_expected = NULL; /* When is the next ksk rollover expected? */
605 
606  xmlChar *name_expr = (unsigned char*) "name";
607  xmlChar *policy_expr = (unsigned char*) "//Zone/Policy";
608  xmlChar *filename_expr = (unsigned char*) "//Zone/SignerConfiguration";
609 
610  char* temp_char = NULL;
611 
612  /* Stuff to see if we need to log an "impending rollover" warning */
613  char* datetime = NULL;
614  int roll_time = 0;
615 
616  /* Let's find our zonelist from the conf.xml */
617  if (config->configfile != NULL) {
618  status = read_zonelist_filename(config->configfile, &zonelist_filename);
619  } else {
620  status = read_zonelist_filename(OPENDNSSEC_CONFIG_FILE, &zonelist_filename);
621  }
622 
623  if (status != 0) {
624  log_msg(NULL, LOG_ERR, "couldn't read zonelist filename");
625  unlink(config->pidfile);
626  exit(1);
627  }
628 
629  /* In case zonelist is huge use the XmlTextReader API so that we don't hold the whole file in memory */
630  reader = xmlNewTextReaderFilename(zonelist_filename);
631  if (reader != NULL) {
632  ret = xmlTextReaderRead(reader);
633  while (ret == 1) {
634  tag_name = (char*) xmlTextReaderLocalName(reader);
635  /* Found <Zone> */
636  if (strncmp(tag_name, "Zone", 4) == 0
637  && strncmp(tag_name, "ZoneList", 8) != 0
638  && xmlTextReaderNodeType(reader) == 1) {
639  /* Get the zone name (TODO what if this is null?) */
640  zone_name = NULL;
641  temp_char = (char*) xmlTextReaderGetAttribute(reader, name_expr);
642  StrAppend(&zone_name, temp_char);
643  StrFree(temp_char);
644  /* Make sure that we got something */
645  if (zone_name == NULL) {
646  /* error */
647  log_msg(NULL, LOG_ERR, "Error extracting zone name from %s", zonelist_filename);
648  /* Don't return? try to parse the rest of the zones? */
649  ret = xmlTextReaderRead(reader);
650  StrFree(tag_name);
651  continue;
652  }
653 
654 
655  log_msg(config, LOG_INFO, "Zone %s found.", zone_name);
656 
657  /* Get zone ID from name (or skip if it doesn't exist) */
658  status = KsmZoneIdFromName(zone_name, &zone_id);
659  if (status != 0 || zone_id == -1)
660  {
661  /* error */
662  log_msg(NULL, LOG_ERR, "Error looking up zone \"%s\" in database (please make sure that the zonelist file is up to date)", zone_name);
663  /* Don't return? try to parse the rest of the zones? */
664  ret = xmlTextReaderRead(reader);
665  StrFree(tag_name);
666  StrFree(zone_name);
667  continue;
668  }
669 
670  /* Expand this node and get the rest of the info with XPath */
671  xmlTextReaderExpand(reader);
672  doc = xmlTextReaderCurrentDoc(reader);
673  if (doc == NULL) {
674  log_msg(config, LOG_ERR, "Error: can not read zone \"%s\"; skipping", zone_name);
675  /* Don't return? try to parse the rest of the zones? */
676  ret = xmlTextReaderRead(reader);
677  StrFree(tag_name);
678  StrFree(zone_name);
679  continue;
680  }
681 
682  /* TODO should we validate here? Or should we validate the whole document? */
683 
684  xpathCtx = xmlXPathNewContext(doc);
685  if(xpathCtx == NULL) {
686  log_msg(config, LOG_ERR,"Error: can not create XPath context for \"%s\"; skipping zone", zone_name);
687  /* Don't return? try to parse the rest of the zones? */
688  ret = xmlTextReaderRead(reader);
689  StrFree(tag_name);
690  StrFree(zone_name);
691  continue;
692  }
693 
694  /* Extract the Policy name and signer configuration filename for this zone */
695  /* Evaluate xpath expression for policy */
696  xpathObj = xmlXPathEvalExpression(policy_expr, xpathCtx);
697  if(xpathObj == NULL) {
698  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s; skipping zone", policy_expr);
699  /* Don't return? try to parse the rest of the zones? */
700  ret = xmlTextReaderRead(reader);
701  StrFree(tag_name);
702  StrFree(zone_name);
703  continue;
704  }
705  current_policy = NULL;
706  temp_char = (char*) xmlXPathCastToString(xpathObj);
707  StrAppend(&current_policy, temp_char);
708  StrFree(temp_char);
709  log_msg(config, LOG_INFO, "Policy for %s set to %s.", zone_name, current_policy);
710  xmlXPathFreeObject(xpathObj);
711 
712  if (strcmp(current_policy, policy->name) != 0) {
713  if ( !all_policies ) {
714  /*Only process zones on the policy we have */
715  log_msg(config, LOG_INFO, "Skipping zone %s as not on specified policy \"%s\".", zone_name, policy->name);
716  /* Move onto the next zone*/
717  ret = xmlTextReaderRead(reader);
718  StrFree(tag_name);
719  StrFree(zone_name);
720  continue;
721  }
722 
723  /* Read new Policy */
724  kaspSetPolicyDefaults(policy, current_policy);
725 
726  status2 = KsmPolicyRead(policy);
727  if (status2 != 0) {
728  /* Don't return? try to parse the rest of the zones? */
729  log_msg(config, LOG_ERR, "Error reading policy");
730  ret = xmlTextReaderRead(reader);
731  StrFree(tag_name);
732  StrFree(zone_name);
733  continue;
734  }
735  log_msg(config, LOG_INFO, "Policy %s found in DB.", policy->name);
736 
737  } /* else */
738  /* Policy is same as previous zone, do not re-read */
739 
740  StrFree(current_policy);
741 
742  /* Evaluate xpath expression for signer configuration filename */
743  xpathObj = xmlXPathEvalExpression(filename_expr, xpathCtx);
744  xmlXPathFreeContext(xpathCtx);
745 
746  if(xpathObj == NULL) {
747  log_msg(config, LOG_ERR, "Error: unable to evaluate xpath expression: %s; skipping zone", filename_expr);
748  /* Don't return? try to parse the rest of the zones? */
749  ret = xmlTextReaderRead(reader);
750  StrFree(tag_name);
751  StrFree(zone_name);
752  continue;
753  }
754  current_filename = NULL;
755  temp_char = (char*)xmlXPathCastToString(xpathObj);
756  StrAppend(&current_filename, temp_char);
757  StrFree(temp_char);
758  log_msg(config, LOG_INFO, "Config will be output to %s.", current_filename);
759  xmlXPathFreeObject(xpathObj);
760  /* TODO should we check that we have not written to this file in this run?*/
761  /* Make sure that enough keys are allocated to this zone */
762 
763  status2 = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, 0);
764  if (status2 != 0) {
765  log_msg(config, LOG_ERR, "Error allocating zsks to zone %s", zone_name);
766  /* Don't return? try to parse the rest of the zones? */
767  ret = xmlTextReaderRead(reader);
768  StrFree(tag_name);
769  StrFree(zone_name);
770  StrFree(current_filename);
771  continue;
772  }
773  status2 = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, policy->ksk->rollover_scheme);
774  if (status2 != 0) {
775  log_msg(config, LOG_ERR, "Error allocating ksks to zone %s", zone_name);
776  /* Don't return? try to parse the rest of the zones? */
777  ret = xmlTextReaderRead(reader);
778  StrFree(tag_name);
779  StrFree(zone_name);
780  StrFree(current_filename);
781  continue;
782  }
783 
784  /* turn this zone and policy into a file */
785  status2 = commGenSignConf(zone_name, zone_id, current_filename, policy, &signer_flag, config->interval, config->manualKeyGeneration, config->DSSubmitCmd, config->DSSubCKA_ID);
786  if (status2 == -2) {
787  log_msg(config, LOG_ERR, "Signconf not written for %s", zone_name);
788  /* Don't return? try to parse the rest of the zones? */
789  ret = xmlTextReaderRead(reader);
790  StrFree(tag_name);
791  StrFree(zone_name);
792  StrFree(current_filename);
793  continue;
794  }
795  else if (status2 != 0) {
796  log_msg(config, LOG_ERR, "Error writing signconf for %s", zone_name);
797  /* Don't return? try to parse the rest of the zones? */
798  ret = xmlTextReaderRead(reader);
799  StrFree(tag_name);
800  StrFree(zone_name);
801  StrFree(current_filename);
802  continue;
803  }
804 
805  /* See if we need to send a warning about an impending rollover */
806  if (config->rolloverNotify != -1) {
807  datetime = DtParseDateTimeString("now");
808 
809  /* Check datetime in case it came back NULL */
810  if (datetime == NULL) {
811  log_msg(config, LOG_ERR, "Couldn't turn \"now\" into a date, quiting...");
812  unlink(config->pidfile);
813  exit(1);
814  }
815 
816  /* First the KSK */
817  status2 = KsmCheckNextRollover(KSM_TYPE_KSK, zone_id, &ksk_expected);
818  if (status2 == -1) {
819  log_msg(config, LOG_INFO, "No active KSKs yet for zone %s, can't check for impending rollover", zone_name);
820  }
821  else if (status2 != 0) {
822  log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name);
823  /* TODO should we quit or continue? */
824  } else {
825  status2 = DtDateDiff(ksk_expected, datetime, &roll_time);
826  if (status2 != 0) {
827  log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name);
828  } else {
829 
830  if (roll_time <= config->rolloverNotify) {
831  log_msg(config, LOG_INFO, "Rollover of KSK expected at %s for %s", ksk_expected, zone_name);
832  }
833  }
834  StrFree(ksk_expected);
835  }
836  StrFree(datetime);
837  }
838 
839  StrFree(current_filename);
840  StrFree(zone_name);
841  }
842  /* Read the next line */
843  ret = xmlTextReaderRead(reader);
844  StrFree(tag_name);
845  }
846  xmlFreeTextReader(reader);
847  if (ret != 0) {
848  log_msg(config, LOG_ERR, "%s : failed to parse", zonelist_filename);
849  }
850  } else {
851  log_msg(config, LOG_ERR, "Unable to open %s", zonelist_filename);
852  }
853 
854  xmlFreeDoc(doc);
855  StrFree(zonelist_filename);
856 
857  return status;
858 }
859 
860 /*
861  * generate the configuration file for the signer
862 
863  * returns 0 on success and -1 if something went wrong
864  * -2 if the RequestKeys call failed
865  */
866 int commGenSignConf(char* zone_name, int zone_id, char* current_filename, KSM_POLICY *policy, int* signer_flag, int run_interval, int man_key_gen, const char* DSSubmitCmd, int DSSubCKA_ID)
867 {
868  int status = 0;
869  int status2 = 0;
870  FILE *file, *file2;
871  int char1, char2; /* for the comparison between 2 files */
872  int same = 0;
873  char *temp_filename; /* In case this fails we write to a temp file and only overwrite
874  the current file when we are finished */
875  char *old_filename; /* Keep a copy of the previous version, just in case! (Also gets
876  round potentially different behaviour of rename over existing
877  file.) */
878  int gencnt; /* Number of keys in generate state */
879  char *signer_command; /* how we will call the signer */
880  int NewDS = 0; /* Did we change the DS Set in any way? */
881  char* datetime = DtParseDateTimeString("now");
882 
883  /* Check datetime in case it came back NULL */
884  if (datetime == NULL) {
885  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
886  return -1;
887  }
888 
889  if (zone_name == NULL || current_filename == NULL || policy == NULL)
890  {
891  /* error */
892  log_msg(NULL, LOG_ERR, "commGenSignConf, NULL policy or zone provided");
893  MemFree(datetime);
894  return -1;
895  }
896 
897  old_filename = NULL;
898  StrAppend(&old_filename, current_filename);
899  StrAppend(&old_filename, ".OLD");
900 
901  temp_filename = NULL;
902  StrAppend(&temp_filename, current_filename);
903  StrAppend(&temp_filename, ".tmp");
904 
905  file = fopen(temp_filename, "w");
906 
907  if (file == NULL)
908  {
909  /* error */
910  log_msg(NULL, LOG_ERR, "Could not open: %s (%s)", temp_filename,
911  strerror(errno));
912  MemFree(datetime);
913  StrFree(temp_filename);
914  StrFree(old_filename);
915  return -1;
916  }
917 
918  fprintf(file, "<SignerConfiguration>\n");
919  fprintf(file, "\t<Zone name=\"%s\">\n", zone_name);
920 
921  fprintf(file, "\t\t<Signatures>\n");
922  fprintf(file, "\t\t\t<Resign>PT%dS</Resign>\n", policy->signature->resign);
923  fprintf(file, "\t\t\t<Refresh>PT%dS</Refresh>\n", policy->signer->refresh);
924  fprintf(file, "\t\t\t<Validity>\n");
925  fprintf(file, "\t\t\t\t<Default>PT%dS</Default>\n", policy->signature->valdefault);
926  fprintf(file, "\t\t\t\t<Denial>PT%dS</Denial>\n", policy->signature->valdenial);
927  fprintf(file, "\t\t\t</Validity>\n");
928  fprintf(file, "\t\t\t<Jitter>PT%dS</Jitter>\n", policy->signer->jitter);
929  fprintf(file, "\t\t\t<InceptionOffset>PT%dS</InceptionOffset>\n", policy->signature->clockskew);
930  fprintf(file, "\t\t</Signatures>\n");
931 
932  fprintf(file, "\n");
933 
934  fprintf(file, "\t\t<Denial>\n");
935  if (policy->denial->version == 3)
936  {
937  fprintf(file, "\t\t\t<NSEC3>\n");
938  if (policy->denial->ttl != 0) {
939  fprintf(file, "\t\t\t\t<TTL>PT%dS</TTL>\n", policy->denial->ttl);
940  }
941  if (policy->denial->optout == 1)
942  {
943  fprintf(file, "\t\t\t\t<OptOut />\n");
944  }
945  fprintf(file, "\t\t\t\t<Hash>\n");
946  fprintf(file, "\t\t\t\t\t<Algorithm>%d</Algorithm>\n", policy->denial->algorithm);
947  fprintf(file, "\t\t\t\t\t<Iterations>%d</Iterations>\n", policy->denial->iteration);
948  if (policy->denial->salt[0] == '\0') {
949  fprintf(file, "\t\t\t\t\t<Salt>-</Salt>\n");
950  } else {
951  fprintf(file, "\t\t\t\t\t<Salt>%s</Salt>\n", policy->denial->salt);
952  }
953  fprintf(file, "\t\t\t\t</Hash>\n");
954  fprintf(file, "\t\t\t</NSEC3>\n");
955  } else {
956  fprintf(file, "\t\t\t<NSEC />\n");
957  }
958 
959  fprintf(file, "\t\t</Denial>\n");
960 
961  fprintf(file, "\n");
962 
963  /* start of keys section */
964  fprintf(file, "\t\t<Keys>\n");
965  fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->ksk->ttl);
966 
967  /* get new keys _only_ if we don't have them from before */
968  status = KsmRequestKeys(0, 0, datetime, commKeyConfig, file, policy->id, zone_id, run_interval, &NewDS);
969  if (status != 0) {
970  /*
971  * Something went wrong (it should have been logged) stop this zone.
972  * Clean up the files, don't call the signer and move on to the next zone.
973  */
974  log_msg(NULL, LOG_ERR, "KsmRequestKeys returned: %d", status);
975 
976  /* check for the specific case of not having any keys
977  TODO check that this code can ever be executed after the restructure */
978  if (status == -1) {
979  status2 = KsmRequestGenerateCount(KSM_TYPE_KSK, &gencnt, zone_id);
980  if (status2 == 0 && gencnt == 0) {
981  if(man_key_gen == 1) {
982  log_msg(NULL, LOG_ERR, "There are no KSKs in the generate state; please use \"ods-ksmutil key generate\" to create some.");
983  } else {
984  log_msg(NULL, LOG_WARNING, "There are no KSKs in the generate state; ods-enforcerd will create some on its next run.");
985  }
986  }
987  else if (status2 == 0) {
988  status2 = KsmRequestGenerateCount(KSM_TYPE_ZSK, &gencnt, zone_id);
989  if (status2 == 0 && gencnt == 0) {
990  if(man_key_gen == 1) {
991  log_msg(NULL, LOG_ERR, "There are no ZSKs in the generate state; please use \"ods-ksmutil key generate\" to create some.");
992  } else {
993  log_msg(NULL, LOG_WARNING, "There are no ZSKs in the generate state; ods-enforcerd will create some on its next run.");
994  }
995  }
996  }
997  else {
998  log_msg(NULL, LOG_ERR, "KsmRequestGenerateCount returned: %d", status2);
999  }
1000  }
1001 
1002  status = fclose(file);
1003  unlink(temp_filename);
1004  MemFree(datetime);
1005  StrFree(temp_filename);
1006  StrFree(old_filename);
1007 
1008  return -2;
1009  }
1010 
1011  fprintf(file, "\t\t</Keys>\n");
1012 
1013  fprintf(file, "\n");
1014 
1015  fprintf(file, "\t\t<SOA>\n");
1016  fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->signer->soattl);
1017  fprintf(file, "\t\t\t<Minimum>PT%dS</Minimum>\n", policy->signer->soamin);
1018  fprintf(file, "\t\t\t<Serial>%s</Serial>\n", KsmKeywordSerialValueToName( policy->signer->serial) );
1019  fprintf(file, "\t\t</SOA>\n");
1020 
1021  fprintf(file, "\t</Zone>\n");
1022  fprintf(file, "</SignerConfiguration>\n");
1023 
1024  /* Force flush of stream to disc cache and then onto disc proper
1025  * Do we need to do this? It might be significant on ext4
1026  * NOTE though that there may be a significant overhead associated with it
1027  * ALSO, if we do lose power maybe we should disregard any files when we come
1028  * back as we won't know if they are now too old? */
1029  /*
1030  if (fflush(file) != 0) {
1031  MemFree(datetime);
1032  return -1;
1033  }
1034 
1035  if (fsync(fileno(file)) != 0) {
1036  MemFree(datetime);
1037  return -1;
1038  }
1039  */
1040 
1041  status = fclose(file);
1042  MemFree(datetime);
1043 
1044  if (status == EOF) /* close failed... do something? */
1045  {
1046  log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename);
1047  StrFree(temp_filename);
1048  StrFree(old_filename);
1049  return -1;
1050  }
1051 
1052  /* compare our temp file with the current one (if it exists) */
1053  file = fopen(temp_filename, "rb");
1054  if (file == NULL)
1055  {
1056  /* error */
1057  log_msg(NULL, LOG_ERR, "Could not reopen: %s", temp_filename);
1058  StrFree(temp_filename);
1059  StrFree(old_filename);
1060  return -1;
1061  }
1062 
1063  file2 = fopen(current_filename, "rb"); /* Might not exist */
1064 
1065  /* If current_filename exists then compare its contents to temp_filename */
1066  if (file2 != NULL) {
1067  same = 1;
1068  while(!feof(file)) {
1069  char1 = fgetc(file);
1070  if(ferror(file)) {
1071  log_msg(NULL, LOG_ERR, "Could not read: %s", temp_filename);
1072  fclose(file);
1073  fclose(file2);
1074  StrFree(temp_filename);
1075  StrFree(old_filename);
1076  return -1;
1077  }
1078  char2 = fgetc(file2);
1079  if(ferror(file2)) {
1080  log_msg(NULL, LOG_ERR, "Could not read: %s", current_filename);
1081  fclose(file);
1082  fclose(file2);
1083  StrFree(temp_filename);
1084  StrFree(old_filename);
1085  return -1;
1086  }
1087  if(char1 != char2) {
1088  same = 0;
1089  break;
1090  }
1091  }
1092 
1093  status = fclose(file2);
1094  if (status == EOF) /* close failed... do something? */
1095  {
1096  log_msg(NULL, LOG_ERR, "Could not close: %s", current_filename);
1097  fclose(file);
1098  StrFree(temp_filename);
1099  StrFree(old_filename);
1100  return -1;
1101  }
1102  }
1103 
1104  status = fclose(file);
1105  if (status == EOF) /* close failed... do something? */
1106  {
1107  log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename);
1108  StrFree(temp_filename);
1109  StrFree(old_filename);
1110  return -1;
1111  }
1112 
1113  /* If either current_filename does not exist, or if it is different to temp then same will == 0 */
1114 
1115  if (same == 0) {
1116 
1117  /* we now have a complete xml file. First move the old one out of the way */
1118  status = rename(current_filename, old_filename);
1119  if (status != 0 && status != -1)
1120  {
1121  /* cope with initial condition of files not existing */
1122  log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", current_filename, old_filename);
1123  StrFree(old_filename);
1124  StrFree(temp_filename);
1125  return -1;
1126  }
1127 
1128  /* Then copy our temp into place */
1129  if (rename(temp_filename, current_filename) != 0)
1130  {
1131  log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", temp_filename, current_filename);
1132  StrFree(old_filename);
1133  StrFree(temp_filename);
1134  return -1;
1135  }
1136 
1137  if (*signer_flag == 1) {
1138  /* call the signer engine to tell it that something changed */
1139  /* TODO for beta version connect straight to the socket
1140  should we make a blocking call on this?
1141  should we call it here or after we have written all of the files?
1142  have timeout if call is blocking */
1143  signer_command = NULL;
1144  StrAppend(&signer_command, SIGNER_CLI_UPDATE);
1145  StrAppend(&signer_command, " ");
1146  StrAppend(&signer_command, zone_name);
1147 
1148  status = system(signer_command);
1149  if (status != 0)
1150  {
1151  log_msg(NULL, LOG_ERR, "Could not call signer engine");
1152  log_msg(NULL, LOG_INFO, "Will continue: call '%s' to manually update the zone", signer_command);
1153  *signer_flag = 0;
1154  }
1155  else {
1156  log_msg(NULL, LOG_INFO, "Called signer engine: %s", signer_command);
1157  }
1158 
1159  StrFree(signer_command);
1160  }
1161  }
1162  else {
1163  log_msg(NULL, LOG_INFO, "No change to: %s", current_filename);
1164  if (remove(temp_filename) != 0)
1165  {
1166  log_msg(NULL, LOG_ERR, "Could not remove: %s", temp_filename);
1167  StrFree(old_filename);
1168  StrFree(temp_filename);
1169  return -1;
1170  }
1171  }
1172 
1173  /* If the DS set changed then log/do something about it */
1174  if (NewDS == 1) {
1175  log_msg(NULL, LOG_INFO, "DSChanged");
1176  status = NewDSSet(zone_id, zone_name, DSSubmitCmd, DSSubCKA_ID);
1177  }
1178 
1179  StrFree(old_filename);
1180  StrFree(temp_filename);
1181 
1182  return 0;
1183 }
1184 
1185 /*
1186  * CallBack to print key info in signerConfiguration
1187  */
1188 
1189 int commKeyConfig(void* context, KSM_KEYDATA* key_data)
1190 {
1191  FILE *file = (FILE *)context;
1192 
1193  fprintf(file, "\t\t\t<Key>\n");
1194  fprintf(file, "\t\t\t\t<Flags>%d</Flags>\n", key_data->keytype);
1195  fprintf(file, "\t\t\t\t<Algorithm>%d</Algorithm>\n", key_data->algorithm);
1196  fprintf(file, "\t\t\t\t<Locator>%s</Locator>\n", key_data->location);
1197 
1198  if (key_data->keytype == KSM_TYPE_KSK)
1199  {
1200  fprintf(file, "\t\t\t\t<KSK />\n");
1201  }
1202  if (key_data->keytype == KSM_TYPE_ZSK && key_data->state == KSM_STATE_ACTIVE)
1203  {
1204  fprintf(file, "\t\t\t\t<ZSK />\n");
1205  }
1206  if ((key_data->state > KSM_STATE_GENERATE && key_data->state < KSM_STATE_DEAD) || key_data->state == KSM_STATE_KEYPUBLISH)
1207  {
1208  fprintf(file, "\t\t\t\t<Publish />\n");
1209  }
1210  fprintf(file, "\t\t\t</Key>\n");
1211  fprintf(file, "\n");
1212 
1213  return 0;
1214 }
1215 
1216 /* allocateKeysToZone
1217  *
1218  * Description:
1219  * Allocates existing keys to zones
1220  *
1221  * Arguments:
1222  * policy
1223  * policy that the keys were created for
1224  * key_type
1225  * KSK or ZSK
1226  * zone_id
1227  * ID of zone in question
1228  * interval
1229  * time before next run
1230  * zone_name
1231  * just in case we need to log something
1232  * man_key_gen
1233  * lack of keys may be an issue for the user to fix
1234  * int rollover_scheme
1235  * KSK rollover scheme in use
1236  *
1237  * Returns:
1238  * int
1239  * Status return. 0=> Success, non-zero => error.
1240  * 1 == error with input
1241  * 2 == not enough keys to satisfy policy
1242  * 3 == database error
1243  -*/
1244 
1245 
1246 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)
1247 {
1248  int status = 0;
1249  int keys_needed = 0;
1250  int keys_in_queue = 0;
1251  int keys_pending_retirement = 0;
1252  int new_keys = 0;
1253  int key_pair_id = 0;
1254  int i = 0;
1255  DB_ID ignore = 0;
1256  KSM_PARCOLL collection; /* Parameters collection */
1257  char* datetime = DtParseDateTimeString("now");
1258 
1259  /* Check datetime in case it came back NULL */
1260  if (datetime == NULL) {
1261  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
1262  return -1;
1263  }
1264 
1265  if (policy == NULL) {
1266  log_msg(NULL, LOG_ERR, "NULL policy sent to allocateKeysToZone");
1267  StrFree(datetime);
1268  return 1;
1269  }
1270 
1271  if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) {
1272  log_msg(NULL, LOG_ERR, "Unknown keytype: %i in allocateKeysToZone", key_type);
1273  StrFree(datetime);
1274  return 1;
1275  }
1276 
1277  /* Get list of parameters */
1278  status = KsmParameterCollection(&collection, policy->id);
1279  if (status != 0) {
1280  StrFree(datetime);
1281  return status;
1282  }
1283 
1284  /* Make sure that enough keys are allocated to this zone */
1285  /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */
1286  status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1);
1287  if (status != 0) {
1288  log_msg(NULL, LOG_ERR, "Could not predict key requirement for next interval for %s", zone_name);
1289  StrFree(datetime);
1290  return 3;
1291  }
1292 
1293  /* How many do we have ? TODO should this include the currently active key?*/
1294  status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id);
1295  if (status != 0) {
1296  log_msg(NULL, LOG_ERR, "Could not count current key numbers for zone %s", zone_name);
1297  StrFree(datetime);
1298  return 3;
1299  }
1300 
1301  /* or about to retire */
1302  status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval);
1303  if (status != 0) {
1304  log_msg(NULL, LOG_ERR, "Could not count keys which may retire before the next run (for zone %s)", zone_name);
1305  StrFree(datetime);
1306  return 3;
1307  }
1308 
1309  StrFree(datetime);
1310  new_keys = keys_needed - (keys_in_queue - keys_pending_retirement);
1311 
1312  /* 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); */
1313 
1314  /* Allocate keys */
1315  for (i=0 ; i < new_keys ; i++){
1316  key_pair_id = 0;
1317  if (key_type == KSM_TYPE_KSK) {
1318  status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1319  if (status == -1 || key_pair_id == 0) {
1320  if (man_key_gen == 0) {
1321  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy ksk policy for zone: %s", zone_name);
1322  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1323  }
1324  else {
1325  log_msg(NULL, LOG_ERR, "Not enough keys to satisfy ksk policy for zone: %s", zone_name);
1326  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1327  }
1328  return 2;
1329  }
1330  else if (status != 0) {
1331  log_msg(NULL, LOG_ERR, "Could not get an unallocated ksk for zone: %s", zone_name);
1332  return 3;
1333  }
1334  } else {
1335  status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1336  if (status == -1 || key_pair_id == 0) {
1337  if (man_key_gen == 0) {
1338  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy zsk policy for zone: %s", zone_name);
1339  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1340  }
1341  else {
1342  log_msg(NULL, LOG_ERR, "Not enough keys to satisfy zsk policy for zone: %s", zone_name);
1343  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1344  }
1345  return 2;
1346  }
1347  else if (status != 0) {
1348  log_msg(NULL, LOG_ERR, "Could not get an unallocated zsk for zone: %s", zone_name);
1349  return 3;
1350  }
1351  }
1352  if(key_pair_id > 0) {
1353  status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, NULL, &ignore);
1354  /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */
1355  } else {
1356  /* This shouldn't happen */
1357  log_msg(NULL, LOG_ERR, "KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name);
1358  return -1;
1359  }
1360 
1361  }
1362 
1363  return status;
1364 }
1365 
1366 /*
1367  * Read the conf.xml file, extract the location of the zonelist.
1368  */
1369 int read_zonelist_filename(const char* filename, char** zone_list_filename)
1370 {
1371  xmlTextReaderPtr reader = NULL;
1372  xmlDocPtr doc = NULL;
1373  xmlXPathContextPtr xpathCtx = NULL;
1374  xmlXPathObjectPtr xpathObj = NULL;
1375  int ret = 0; /* status of the XML parsing */
1376  char* temp_char = NULL;
1377  char* tag_name = NULL;
1378 
1379  xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
1380 
1381  /* Start reading the file; we will be looking for "Common" tags */
1382  reader = xmlNewTextReaderFilename(filename);
1383  if (reader != NULL) {
1384  ret = xmlTextReaderRead(reader);
1385  while (ret == 1) {
1386  tag_name = (char*) xmlTextReaderLocalName(reader);
1387  /* Found <Common> */
1388  if (strncmp(tag_name, "Common", 6) == 0
1389  && xmlTextReaderNodeType(reader) == 1) {
1390 
1391  /* Expand this node and get the rest of the info with XPath */
1392  xmlTextReaderExpand(reader);
1393  doc = xmlTextReaderCurrentDoc(reader);
1394  if (doc == NULL) {
1395  log_msg(NULL, LOG_ERR, "Error: can not read Common section of %s", filename);
1396  /* Don't return? try to parse the rest of the file? */
1397  ret = xmlTextReaderRead(reader);
1398  continue;
1399  }
1400 
1401  xpathCtx = xmlXPathNewContext(doc);
1402  if(xpathCtx == NULL) {
1403  log_msg(NULL, LOG_ERR, "Error: can not create XPath context for Common section");
1404  /* Don't return? try to parse the rest of the file? */
1405  ret = xmlTextReaderRead(reader);
1406  continue;
1407  }
1408 
1409  /* Evaluate xpath expression for ZoneListFile */
1410  xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
1411  if(xpathObj == NULL) {
1412  log_msg(NULL, LOG_ERR, "Error: unable to evaluate xpath expression: %s", zonelist_expr);
1413  /* Don't return? try to parse the rest of the file? */
1414  ret = xmlTextReaderRead(reader);
1415  continue;
1416  }
1417  *zone_list_filename = NULL;
1418  temp_char = (char *)xmlXPathCastToString(xpathObj);
1419  StrAppend(zone_list_filename, temp_char);
1420  StrFree(temp_char);
1421  xmlXPathFreeObject(xpathObj);
1422  log_msg(NULL, LOG_INFO, "zonelist filename set to %s.", *zone_list_filename);
1423  }
1424  /* Read the next line */
1425  ret = xmlTextReaderRead(reader);
1426  StrFree(tag_name);
1427  }
1428  xmlFreeTextReader(reader);
1429  if (ret != 0) {
1430  log_msg(NULL, LOG_ERR, "%s : failed to parse", filename);
1431  return(1);
1432  }
1433  } else {
1434  log_msg(NULL, LOG_ERR, "Unable to open %s", filename);
1435  return(1);
1436  }
1437  if (xpathCtx) {
1438  xmlXPathFreeContext(xpathCtx);
1439  }
1440  if (doc) {
1441  xmlFreeDoc(doc);
1442  }
1443 
1444  return 0;
1445 }
1446 
1447 /*+
1448  * do_purge - Purge dead Keys
1449  *
1450  *
1451  * Arguments:
1452  *
1453  * int interval
1454  * how long a key needs to have been dead for before we purge it
1455  *
1456  * int policy_id
1457  * ID of the policy
1458  *
1459  * Returns:
1460  * int
1461  * Status return. 0 on success.
1462  * other on fail
1463  */
1464 
1465 int do_purge(int interval, int policy_id)
1466 {
1467  char* sql = NULL; /* SQL query */
1468  char* sql1 = NULL; /* SQL query */
1469  char* sql2 = NULL; /* SQL query */
1470  char* sql3 = NULL; /* SQL query */
1471  int status = 0; /* Status return */
1472  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
1473  DB_RESULT result; /* Result of the query */
1474  DB_ROW row = NULL; /* Row data */
1475 
1476  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
1477 
1478  int temp_id = -1; /* place to store the key id returned */
1479  char* temp_loc = NULL; /* place to store location returned */
1480  int count = 0; /* How many keys don't match the purge */
1481 
1482  char *rightnow;
1483 
1484  /* Key information */
1485  hsm_key_t *key = NULL;
1486 
1487  log_msg(NULL, LOG_DEBUG, "Purging keys...");
1488 
1489  rightnow = DtParseDateTimeString("now");
1490 
1491  /* Check datetime in case it came back NULL */
1492  if (rightnow == NULL) {
1493  log_msg(NULL, LOG_ERR, "Couldn't turn \"now\" into a date, quitting...");
1494  exit(1);
1495  }
1496 
1497  /* Select rows */
1498  StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 ");
1499 
1500  if (policy_id != -1) {
1501  StrAppend(&sql, "and policy_id = ");
1502  snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id);
1503  StrAppend(&sql, stringval);
1504  }
1505 
1506  DusEnd(&sql);
1507 
1508  status = DbExecuteSql(DbHandle(), sql, &result);
1509 
1510  if (status == 0) {
1511  status = DbFetchRow(result, &row);
1512  while (status == 0) {
1513  /* Got a row, check it */
1514  DbInt(row, 0, &temp_id);
1515  DbString(row, 1, &temp_loc);
1516 
1517  sql1 = DqsCountInit("dnsseckeys");
1518  DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1519  DdsConditionInt(&sql1, "(state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1);
1520 
1521  status = DbDateDiff(rightnow, interval, -1, buffer, KSM_SQL_SIZE);
1522  if (status != 0) {
1523  log_msg(NULL, LOG_ERR, "DbDateDiff failed\n");
1524  DbStringFree(temp_loc);
1525  DbFreeRow(row);
1526  StrFree(rightnow);
1527  DusFree(sql);
1528  DqsFree(sql1);
1529  return status;
1530  }
1531 
1532  StrAppend(&sql1, " or state = 6 and DEAD > ");
1533  StrAppend(&sql1, buffer);
1534  StrAppend(&sql1, ")");
1535  DqsEnd(&sql1);
1536 
1537  status = DbIntQuery(DbHandle(), &count, sql1);
1538  DqsFree(sql1);
1539 
1540  if (status != 0) {
1541  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1542  DbStringFree(temp_loc);
1543  DbFreeRow(row);
1544  StrFree(rightnow);
1545  DusFree(sql);
1546  return status;
1547  }
1548 
1549  /* If the count is zero then there is no reason not to purge this key */
1550  if (count == 0) {
1551 
1552  /* Delete from dnsseckeys */
1553  sql2 = DdsInit("dnsseckeys");
1554  DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1555  DdsEnd(&sql2);
1556 
1557  status = DbExecuteSqlNoResult(DbHandle(), sql2);
1558  DdsFree(sql2);
1559  if (status != 0)
1560  {
1561  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1562  DbStringFree(temp_loc);
1563  DbFreeRow(row);
1564  StrFree(rightnow);
1565  DusFree(sql);
1566  return status;
1567  }
1568 
1569  /* Delete from keypairs */
1570  sql3 = DdsInit("keypairs");
1571  DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0);
1572  DdsEnd(&sql);
1573 
1574  status = DbExecuteSqlNoResult(DbHandle(), sql3);
1575  DdsFree(sql3);
1576  if (status != 0)
1577  {
1578  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1579  DbStringFree(temp_loc);
1580  DbFreeRow(row);
1581  StrFree(rightnow);
1582  DusFree(sql);
1583  return status;
1584  }
1585 
1586  /* Delete from the HSM */
1587  key = hsm_find_key_by_id(NULL, temp_loc);
1588 
1589  if (!key) {
1590  log_msg(NULL, LOG_ERR, "Key not found: %s\n", temp_loc);
1591  DbStringFree(temp_loc);
1592  DbFreeRow(row);
1593  StrFree(rightnow);
1594  DusFree(sql);
1595  return -1;
1596  }
1597 
1598  status = hsm_remove_key(NULL, key);
1599 
1600  hsm_key_free(key);
1601 
1602  if (!status) {
1603  log_msg(NULL, LOG_INFO, "Key remove successful: %s\n", temp_loc);
1604  } else {
1605  log_msg(NULL, LOG_ERR, "Key remove failed: %s\n", temp_loc);
1606  DbStringFree(temp_loc);
1607  DbFreeRow(row);
1608  StrFree(rightnow);
1609  DusFree(sql);
1610  return -1;
1611  }
1612  }
1613 
1614  /* NEXT! */
1615  status = DbFetchRow(result, &row);
1616  }
1617 
1618  /* Convert EOF status to success */
1619 
1620  if (status == -1) {
1621  status = 0;
1622  }
1623 
1624  DbFreeResult(result);
1625  }
1626 
1627  DusFree(sql);
1628  DbFreeRow(row);
1629 
1630  DbStringFree(temp_loc);
1631  StrFree(rightnow);
1632 
1633  return status;
1634 }
1635 
1636 int NewDSSet(int zone_id, const char* zone_name, const char* DSSubmitCmd, int DSSubCKA_ID) {
1637  int where = 0; /* for the SELECT statement */
1638  char* sql = NULL; /* SQL statement (when verifying) */
1639  char* sql2 = NULL; /* SQL statement (if getting DS) */
1640  int status = 0; /* Status return */
1641  int count = 0; /* How many keys fit our select? */
1642  int i = 0; /* A counter */
1643  int j = 0; /* Another counter */
1644  char* insql = NULL; /* SQL "IN" clause */
1645  int* keyids; /* List of IDs of keys to promote */
1646  DB_RESULT result; /* List result set */
1647  KSM_KEYDATA data; /* Data for this key */
1648  size_t nchar; /* Number of characters written */
1649  char buffer[256]; /* For constructing part of the command */
1650  char* count_clause = NULL;
1651  char* where_clause = NULL;
1652  int id = -1; /* ID of key which will retire */
1653  int active_count = -1; /* Number of currently active keys */
1654 
1655  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
1656  DB_RESULT result3; /* Result of DS query */
1657  KSM_KEYDATA data3; /* DS information */
1658  char* ds_buffer = NULL; /* Contents of DS records */
1659  char* ds_seen_buffer = NULL; /* Which keys have we promoted */
1660  char* temp_char = NULL; /* Contents of DS records */
1661 
1662  /* To find the ttl of the DS */
1663  int policy_id = -1;
1664  int rrttl = -1;
1665  int param_id = -1; /* unused */
1666 
1667  /* Key information */
1668  hsm_key_t *key = NULL;
1669  ldns_rr *dnskey_rr = NULL;
1670  hsm_sign_params_t *sign_params = NULL;
1671 
1672  FILE *fp;
1673  int bytes_written = -1;
1674 
1675  struct stat stat_ret; /* we will test the DSSubmitCmd */
1676 
1677  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d, %d, %d)",
1681  if (nchar >= sizeof(buffer)) {
1682  status = -1;
1683  return status;
1684  }
1685 
1686  /* Find the oldest active key, this is the one which will be retired
1687  NOTE; this may not match any keys */
1688 
1689  count_clause = DqsCountInit("KEYDATA_VIEW");
1690  DqsConditionInt(&count_clause, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1691  DqsConditionInt(&count_clause, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
1692  if (zone_id != -1) {
1693  DqsConditionInt(&count_clause, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1694  }
1695 
1696  status = DbIntQuery(DbHandle(), &active_count, count_clause);
1697  StrFree(count_clause);
1698  if (status != 0)
1699  {
1700  log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n");
1701  return status;
1702  }
1703 
1704  if (active_count > 0) {
1705 
1706  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
1707  StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1708  StrAppend(&where_clause, stringval);
1709  StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1710  StrAppend(&where_clause, stringval);
1711  StrAppend(&where_clause, ")");
1712 
1713  /* Execute query and free up the query string */
1714  status = DbIntQuery(DbHandle(), &id, where_clause);
1715  StrFree(where_clause);
1716  if (status != 0)
1717  {
1718  log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n");
1719  return status;
1720  }
1721  }
1722 
1723  /* First up we need to count how many DSs we will have */
1724  where = 0;
1725  sql = DqsCountInit("KEYDATA_VIEW");
1726  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1727  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1728  if (zone_id != -1) {
1729  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1730  }
1731  if (id != -1) {
1732  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1733  }
1734  DqsEnd(&sql);
1735 
1736  status = DbIntQuery(DbHandle(), &count, sql);
1737  DqsFree(sql);
1738 
1739  if (status != 0) {
1740  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1741  return status;
1742  }
1743 
1744  if (count == 0) {
1745  /* No KSKs in zone? */
1746  return status;
1747  }
1748 
1749  /* Allocate space for the list of key IDs */
1750  keyids = MemMalloc(count * sizeof(int));
1751 
1752  /* Get the list of IDs */
1753 
1754  where = 0;
1755  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1756  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1757  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1758  if (zone_id != -1) {
1759  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1760  }
1761  if (id != -1) {
1762  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1763  }
1764  DqsEnd(&sql);
1765 
1766  status = KsmKeyInitSql(&result, sql);
1767  DqsFree(sql);
1768 
1769  if (status == 0) {
1770  while (status == 0) {
1771  status = KsmKey(result, &data);
1772  if (status == 0) {
1773  keyids[i] = data.keypair_id;
1774  i++;
1775  }
1776  }
1777 
1778  /* Convert EOF status to success */
1779 
1780  if (status == -1) {
1781  status = 0;
1782  } else {
1783  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1784  StrFree(keyids);
1785  return status;
1786  }
1787 
1788  KsmKeyEnd(result);
1789 
1790  } else {
1791  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1792  StrFree(keyids);
1793  return status;
1794  }
1795 
1796  /*
1797  * Now construct the "IN" statement listing the IDs of the keys we
1798  * are planning to change the state of.
1799  */
1800 
1801  StrAppend(&insql, "(");
1802  for (j = 0; j < i; ++j) {
1803  if (j != 0) {
1804  StrAppend(&insql, ",");
1805  }
1806  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
1807  StrAppend(&insql, buffer);
1808  }
1809  StrAppend(&insql, ")");
1810 
1811  StrFree(keyids);
1812 
1813  /* Indicate that the DS record should now be submitted */
1814  sql2 = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1815  DqsConditionKeyword(&sql2, "ID", DQS_COMPARE_IN, insql, 0);
1816  DqsConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
1817  DqsEnd(&sql2);
1818 
1819  log_msg(NULL, LOG_INFO, "DS Record set has changed, the current set looks like:");
1820 
1821  status = KsmKeyInitSql(&result3, sql2);
1822  DqsFree(sql2);
1823  if (status == 0) {
1824  status = KsmKey(result3, &data3);
1825  while (status == 0) {
1826 
1827  /* Code to output the DNSKEY record (stolen from hsmutil) */
1828  key = hsm_find_key_by_id(NULL, data3.location);
1829 
1830  if (!key) {
1831  log_msg(NULL, LOG_ERR, "Key %s in DB but not repository.", data3.location);
1832  StrFree(insql);
1833  return status;
1834  }
1835 
1836  StrAppend(&ds_seen_buffer, ", ");
1837  StrAppend(&ds_seen_buffer, data3.location);
1838 
1839  sign_params = hsm_sign_params_new();
1840  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name);
1841  sign_params->algorithm = data3.algorithm;
1842  sign_params->flags = LDNS_KEY_ZONE_KEY;
1843  sign_params->flags += LDNS_KEY_SEP_KEY;
1844  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
1845 
1846  /* Set TTL if we can find it; else leave it as the default */
1847  /* We need a policy id */
1848  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
1849  if (status == 0) {
1850 
1851  /* Use this to get the TTL parameter value */
1852  status = KsmParameterValue(KSM_PAR_KSKTTL_STRING, KSM_PAR_KSKTTL_CAT, &rrttl, policy_id, &param_id);
1853  if (status == 0) {
1854  ldns_rr_set_ttl(dnskey_rr, rrttl);
1855  }
1856  }
1857 
1858  temp_char = ldns_rr2str(dnskey_rr);
1859  ldns_rr_free(dnskey_rr);
1860 
1861  /* Replace tab with white-space */
1862  for (i = 0; temp_char[i]; ++i) {
1863  if (temp_char[i] == '\t') {
1864  temp_char[i] = ' ';
1865  }
1866  }
1867  log_msg(NULL, LOG_INFO, "%s", temp_char);
1868 
1869  /* We need to strip off trailing comments before we send
1870  to any clients that might be listening */
1871  for (i = 0; temp_char[i]; ++i) {
1872  if (temp_char[i] == ';') {
1873  temp_char[i] = '\n';
1874  temp_char[i+1] = '\0';
1875  break;
1876  }
1877  }
1878  StrAppend(&ds_buffer, temp_char);
1879 
1880  /* Add the CKA_ID if asked */
1881  if (DSSubCKA_ID) {
1882  StrAppend(&ds_buffer, "; {cka_id = ");
1883  StrAppend(&ds_buffer, data3.location);
1884  StrAppend(&ds_buffer, "}");
1885  }
1886 
1887  StrFree(temp_char);
1888 
1889 /* StrAppend(&ds_buffer, "\n;KSK DS record (SHA1):\n");
1890  ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
1891  temp_char = ldns_rr2str(ds_sha1_rr);
1892  StrAppend(&ds_buffer, temp_char);
1893  StrFree(temp_char);
1894 
1895  StrAppend(&ds_buffer, "\n;KSK DS record (SHA256):\n");
1896  ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
1897  temp_char = ldns_rr2str(ds_sha256_rr);
1898  StrAppend(&ds_buffer, temp_char);
1899  StrFree(temp_char);
1900 */
1901 
1902  hsm_sign_params_free(sign_params);
1903  hsm_key_free(key);
1904  status = KsmKey(result3, &data3);
1905  }
1906  /* Convert EOF status to success */
1907  if (status == -1) {
1908  status = 0;
1909  }
1910 
1911  KsmKeyEnd(result3);
1912  }
1913 
1914  if (DSSubmitCmd[0] != '\0') {
1915  /* First check that the command exists */
1916  if (stat(DSSubmitCmd, &stat_ret) != 0) {
1917  log_msg(NULL, LOG_WARNING, "Cannot stat file %s: %s", DSSubmitCmd, strerror(errno));
1918  }
1919  /* Then see if it is a regular file, then if usr, grp or all have execute set */
1920  else if (S_ISREG(stat_ret.st_mode) && !(stat_ret.st_mode & S_IXUSR || stat_ret.st_mode & S_IXGRP || stat_ret.st_mode & S_IXOTH)) {
1921  log_msg(NULL, LOG_WARNING, "File %s is not executable", DSSubmitCmd);
1922  }
1923  else {
1924 
1925  /* send records to the configured command */
1926  fp = popen(DSSubmitCmd, "w");
1927  if (fp == NULL) {
1928  log_msg(NULL, LOG_ERR, "Failed to run command: %s: %s", DSSubmitCmd, strerror(errno));
1929  StrFree(insql);
1930  return -1;
1931  }
1932  bytes_written = fprintf(fp, "%s", ds_buffer);
1933  if (bytes_written < 0) {
1934  log_msg(NULL, LOG_ERR, "Failed to write to %s: %s", DSSubmitCmd, strerror(errno));
1935  return -1;
1936  }
1937 
1938  if (pclose(fp) == -1) {
1939  log_msg(NULL, LOG_ERR, "Failed to close %s: %s", DSSubmitCmd, strerror(errno));
1940  StrFree(ds_buffer);
1941  StrFree(ds_seen_buffer);
1942  StrFree(insql);
1943  return -1;
1944  }
1945  }
1946  }
1947 
1948  StrFree(ds_buffer);
1949 
1950  log_msg(NULL, LOG_INFO, "Once the new DS records are seen in DNS please issue the ds-seen command for zone %s with the following cka_ids%s", zone_name, ds_seen_buffer);
1951 
1952  StrFree(ds_seen_buffer);
1953 
1954  StrFree(insql);
1955 
1956  return status;
1957 }
1958 
1960 {
1961  int result = 0;
1962  char *hsm_error_message = NULL;
1963 
1964  result = hsm_check_context(*ctx);
1965 
1966  /* If we didn't get HSM_OK then close and reopen HSM */
1967  if (result != HSM_OK) {
1968 
1969  if (*ctx) {
1970  hsm_destroy_context(*ctx);
1971  }
1972 
1973  result = hsm_close();
1974 
1975  if (config->configfile != NULL) {
1976  result = hsm_open(config->configfile, hsm_check_pin);
1977  } else {
1978  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_check_pin);
1979  }
1980  if (result) {
1981  hsm_error_message = hsm_get_error(*ctx);
1982  if (hsm_error_message) {
1983  log_msg(config, LOG_ERR, hsm_error_message);
1984  free(hsm_error_message);
1985  } else {
1986  /* decode the error code ourselves
1987  TODO find if there is a better way to do this (and can all
1988  of these be returned? are there others?) */
1989  switch (result) {
1990  case HSM_ERROR:
1991  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
1992  break;
1993  case HSM_PIN_INCORRECT:
1994  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
1995  break;
1996  case HSM_CONFIG_FILE_ERROR:
1997  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
1998  break;
1999  case HSM_REPOSITORY_NOT_FOUND:
2000  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
2001  break;
2002  case HSM_NO_REPOSITORIES:
2003  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
2004  break;
2005  default:
2006  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
2007  }
2008  }
2009  unlink(config->pidfile);
2010  exit(1);
2011  }
2012  log_msg(config, LOG_INFO, "HSM reopened successfully.");
2013  *ctx = hsm_create_context();
2014  } else {
2015  log_msg(config, LOG_INFO, "HSM connection open.");
2016  }
2017 
2018 }
void DbFreeResult(DB_RESULT result)
int KsmPolicyInit(DB_RESULT *handle, const char *name)
Definition: ksm_policy.c:69
unsigned char * schema
Definition: daemon.h:109
char name[KSM_NAME_LENGTH]
Definition: ksm.h:244
unsigned long sm_capacity
Definition: ksm.h:211
bool once
Definition: daemon.h:91
sqlite3 * DB_HANDLE
Definition: database.h:79
#define KSM_TYPE_ZSK
Definition: ksm.h:359
void kaspConnect(DAEMONCONFIG *config, DB_HANDLE *handle)
Definition: kaspaccess.c:129
#define StrFree(x)
Definition: string_util.h:68
void server_main(DAEMONCONFIG *config)
Definition: enforcer.c:83
char * pidfile
Definition: daemon.h:93
char * DSSubmitCmd
Definition: daemon.h:116
int DbFlavour(void)
int DbFetchRow(DB_RESULT result, DB_ROW *row)
#define KSM_STATE_DEAD
Definition: ksm.h:372
int KsmPolicy(DB_RESULT handle, KSM_POLICY *data)
Definition: ksm_policy.c:191
char * DqsSpecifyInit(const char *table, const char *fields)
Definition: dq_string.c:119
#define KSM_STATE_ACTIVE
Definition: ksm.h:368
char location[KSM_NAME_LENGTH]
Definition: ksm.h:111
int KsmKeyCountQueue(int keytype, int *count, int zone_id)
Definition: ksm_key.c:655
KSM_POLICY * KsmPolicyAlloc()
Definition: ksm_policy.c:949
#define KSM_STATE_READY
Definition: ksm.h:366
KSM_COMMON_KEY_POLICY * keys
Definition: ksm.h:249
int state
Definition: ksm.h:101
int KsmParameterCollection(KSM_PARCOLL *data, int policy_id)
void DusFree(char *sql)
Definition: du_string.c:225
int kaspTryConnect(DAEMONCONFIG *config, DB_HANDLE *handle)
Definition: kaspaccess.c:143
KSM_KEY_POLICY * zsk
Definition: ksm.h:251
void check_hsm_connection(hsm_ctx_t **ctx, DAEMONCONFIG *config)
Definition: enforcer.c:1959
int bits
Definition: ksm.h:207
uint16_t interval
Definition: daemon.h:111
void kaspDisconnect(DB_HANDLE *handle)
Definition: kaspaccess.c:157
void DqsConditionKeyword(char **query, const char *field, DQS_COMPARISON compare, const char *value, int index)
Definition: dq_string.c:253
int KsmKeyPairCreate(int policy_id, const char *HSMKeyID, int smID, int size, int alg, const char *generate, DB_ID *id)
Definition: ksm_key.c:86
int KsmZoneCount(DB_RESULT handle, int *count)
Definition: ksm_zone.c:208
char sm_name[KSM_NAME_LENGTH]
Definition: ksm.h:210
int KsmPolicyUpdateSalt(KSM_POLICY *policy)
Definition: ksm_policy.c:495
int shared_keys
Definition: ksm.h:255
int KsmPolicyRead(KSM_POLICY *policy)
Definition: ksm_policy.c:232
int rolloverNotify
Definition: daemon.h:115
char * configfile
Definition: daemon.h:105
void DqsFree(char *query)
Definition: dq_string.c:322
#define KSM_STATE_KEYPUBLISH
Definition: ksm.h:380
void DdsFree(char *query)
Definition: dd_string.c:117
int algorithm
Definition: ksm.h:206
#define MemFree(ptr)
Definition: memory.h:50
int read_zonelist_filename(const char *filename, char **zone_list_filename)
Definition: enforcer.c:1369
int commGenSignConf(char *zone_name, int zone_id, char *current_filename, KSM_POLICY *policy, int *signer_flag, int run_interval, int man_key_gen, const char *DSSubmitCmd, int DSSubCKA_ID)
Definition: enforcer.c:866
char * DqsCountInit(const char *table)
Definition: dq_string.c:92
int KsmCheckNextRollover(int keytype, int zone_id, char **datetime)
Definition: ksm_list.c:459
DB_HANDLE DbHandle(void)
int DbString(DB_ROW row, int field_index, char **result)
void DqsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dq_string.c:226
char salt[KSM_SALT_LENGTH]
Definition: ksm.h:193
void DdsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dd_string.c:90
int KsmPolicyIdFromZoneId(int zone_id, int *policy_id)
Definition: ksm_policy.c:856
char * DdsInit(const char *table)
Definition: dd_string.c:62
char * DtParseDateTimeString(const char *string)
Definition: datetime.c:617
#define KSM_STATE_DSPUBLISH
Definition: ksm.h:376
KSM_DENIAL_POLICY * denial
Definition: ksm.h:248
int KsmZoneIdFromName(const char *zone_name, int *zone_id)
Definition: ksm_zone.c:249
KSM_KEY_POLICY * ksk
Definition: ksm.h:250
int do_communication(DAEMONCONFIG *config, KSM_POLICY *policy, bool all_policies)
Definition: enforcer.c:586
unsigned long DB_ID
Definition: database.h:80
int KsmParameterValue(const char *name, const char *category, int *value, int policy_id, int *parameter_id)
int KsmKeyInitSql(DB_RESULT *result, const char *sql)
Definition: ksm_key.c:219
int manualKeyGeneration
Definition: daemon.h:114
#define SQLITE_DB
Definition: database.h:48
int do_keygen(DAEMONCONFIG *config, KSM_POLICY *policy, hsm_ctx_t *ctx)
Definition: enforcer.c:345
#define DB_KEYDATA_FIELDS
Definition: db_fields.h:58
const char * DbErrmsg(DB_HANDLE handle)
void KsmPolicyFree(KSM_POLICY *policy)
Definition: ksm_policy.c:987
void DbFreeRow(DB_ROW row)
int KsmKey(DB_RESULT result, KSM_KEYDATA *data)
Definition: ksm_key.c:368
KSM_SIGNER_POLICY * signer
Definition: ksm.h:246
int ReadConfig(DAEMONCONFIG *config, int verbose)
Definition: daemon_util.c:713
int term
Definition: daemon.h:102
int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
Definition: ksm_key.c:564
void kaspSetPolicyDefaults(KSM_POLICY *policy, char *name)
Definition: kaspaccess.c:48
const char * KsmKeywordSerialValueToName(int value)
Definition: ksm_keyword.c:254
int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, const char *time, const char *retTime, DB_ID *id)
Definition: ksm_key.c:143
int DbExecuteSql(DB_HANDLE handle, const char *stmt_str, DB_RESULT *result)
int keytype
Definition: ksm.h:102
int KsmRequestGenerateCount(int keytype, int *count, int zone_id)
Definition: ksm_request.c:1685
#define KSM_SQL_SIZE
Definition: ksm.h:65
int release_lite_lock(FILE *lock_fd)
Definition: daemon_util.c:1178
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:78
int server_init(DAEMONCONFIG *config)
Definition: enforcer.c:64
int algorithm
Definition: ksm.h:103
void DusEnd(char **sql)
Definition: du_string.c:204
int DbIntQuery(DB_HANDLE handle, int *value, const char *query)
#define KSM_PAR_KSKTTL_CAT
Definition: ksm.h:443
#define KSM_STATE_RETIRE
Definition: ksm.h:370
#define KSM_STATE_PUBLISH
Definition: ksm.h:364
int DbDateDiff(const char *start, int delta, int sign, char *buffer, size_t buflen)
void KsmParameterCollectionCache(int enable)
char * policy
Definition: daemon.h:118
DB_ID keypair_id
Definition: ksm.h:100
int sm
Definition: ksm.h:209
int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
Definition: ksm_key.c:872
int get_lite_lock(char *lock_filename, FILE *lock_fd)
Definition: daemon_util.c:1144
DAEMONCONFIG config
Definition: daemon.c:73
#define KSM_INT_STR_SIZE
Definition: ksm.h:66
int KsmPolicyExists(const char *name)
Definition: ksm_policy.c:151
int allocateKeysToZone(KSM_POLICY *policy, int key_type, int zone_id, uint16_t interval, const char *zone_name, int man_key_gen, int rollover_scheme)
Definition: enforcer.c:1246
int id
Definition: ksm.h:243
int ttl
Definition: ksm.h:214
int writepid(DAEMONCONFIG *config)
Definition: daemon_util.c:469
#define KSM_PAR_KSKTTL_STRING
Definition: ksm.h:442
int require_backup
Definition: ksm.h:212
void log_msg(DAEMONCONFIG *config, int priority, const char *format,...)
Definition: daemon_util.c:296
int KsmRequestPendingRetireCount(int keytype, const char *datetime, KSM_PARCOLL *parameters, int *count, int zone_id, int interval)
Definition: ksm_request.c:1482
#define KSM_STATE_DSSUB
Definition: ksm.h:374
int KsmZoneCountInit(DB_RESULT *handle, int id)
Definition: ksm_zone.c:109
void DdsEnd(char **query)
Definition: dd_string.c:111
#define KSM_TYPE_KSK
Definition: ksm.h:357
int DbInt(DB_ROW row, int field_index, int *value)
void * MemMalloc(size_t size)
Definition: memory.c:59
int algorithm
Definition: ksm.h:188
#define KSM_STATE_DSREADY
Definition: ksm.h:378
int NewDSSet(int zone_id, const char *zone_name, const char *DSSubmitCmd, int DSSubCKA_ID)
Definition: enforcer.c:1636
int rollover_scheme
Definition: ksm.h:219
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:471
int KsmRequestKeys(int keytype, int rollover, const char *datetime, KSM_REQUEST_CALLBACK callback, void *context, int policy_id, int zone_id, int run_interval, int *NewDS)
Definition: ksm_request.c:97
int iteration
Definition: ksm.h:189
#define KSM_STATE_GENERATE
Definition: ksm.h:362
void DqsEnd(char **query)
Definition: dq_string.c:301
int kaspReadPolicy(KSM_POLICY *policy)
Definition: kaspaccess.c:166
int DtDateDiff(const char *date1, const char *date2, int *result)
Definition: datetime.c:828
int DbExecuteSqlNoResult(DB_HANDLE handle, const char *stmt_str)
int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char *datetime, int *count, int keytype)
Definition: ksm_key.c:734
int do_purge(int interval, int policy_id)
Definition: enforcer.c:1465
int DSSubCKA_ID
Definition: daemon.h:117
KSM_SIGNATURE_POLICY * signature
Definition: ksm.h:247
int commKeyConfig(void *context, KSM_KEYDATA *key_data)
Definition: enforcer.c:1189
void DbStringFree(char *string)