OpenDNSSEC-enforcer  1.3.16
enforcer.c
Go to the documentation of this file.
1 /*
2  * $Id: enforcer.c 7421 2013-11-21 16:11:40Z sara $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
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 <stdlib.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <syslog.h>
41 
42 #include <libxml/xmlreader.h>
43 #include <libxml/xpath.h>
44 
45 #include "config.h"
46 
47 #include "daemon.h"
48 #include "daemon_util.h"
49 #include "enforcer.h"
50 #include "kaspaccess.h"
51 
52 #include "ksm/ksm.h"
53 #include "ksm/memory.h"
54 #include "ksm/string_util.h"
55 #include "ksm/string_util2.h"
56 #include "ksm/datetime.h"
57 #include "ksm/db_fields.h"
58 
59 #include "libhsm.h"
60 #include "libhsmdns.h"
61 
62  int
64 {
65  if (config == NULL) {
66  log_msg(NULL, LOG_ERR, "Error in server_init, no config provided");
67  exit(1);
68  }
69 
70  /* set the default pidfile if nothing was provided on the command line*/
71  if (config->pidfile == NULL) {
72  config->pidfile = OPENDNSSEC_ENFORCER_PIDFILE;
73  }
74 
75  return 0;
76 }
77 
78 /*
79  * Main loop of enforcerd server
80  */
81  void
83 {
84  DB_RESULT handle;
85  DB_HANDLE dbhandle;
86  int status = 0;
87  struct timeval tv;
88  KSM_POLICY *policy;
89  int result;
90  hsm_ctx_t *ctx = NULL;
91  char *hsm_error_message = NULL;
92 
93  FILE *lock_fd = NULL; /* for sqlite file locking */
94  char *lock_filename = NULL;
95 
96  if (config == NULL) {
97  log_msg(NULL, LOG_ERR, "Error in server_main, no config provided");
98  exit(1);
99  }
100 
101  policy = KsmPolicyAlloc();
102  if (policy == NULL) {
103  log_msg(config, LOG_ERR, "Malloc for policy struct failed");
104  exit(1);
105  }
106  kaspSetPolicyDefaults(policy, NULL);
107 
108  /* Read the config file */
109  status = ReadConfig(config , 0);
110  if (status != 0) {
111  log_msg(config, LOG_ERR, "Error reading config");
112  exit(1);
113  }
114 
115  /* If we are doing key generation then connect to the hsm */
116 /* if (config->manualKeyGeneration == 0) {*/
117  /* We keep the HSM connection open for the lifetime of the daemon */
118  if (config->configfile != NULL) {
119  result = hsm_open(config->configfile, hsm_prompt_pin, NULL);
120  } else {
121  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_prompt_pin, NULL);
122  }
123  if (result) {
124  hsm_error_message = hsm_get_error(ctx);
125  if (hsm_error_message) {
126  log_msg(config, LOG_ERR, "%s", hsm_error_message);
127  free(hsm_error_message);
128  } else {
129  /* decode the error code ourselves
130  TODO find if there is a better way to do this (and can all of these be returned? are there others?) */
131  switch (result) {
132  case HSM_ERROR:
133  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
134  break;
135  case HSM_PIN_INCORRECT:
136  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
137  break;
138  case HSM_CONFIG_FILE_ERROR:
139  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
140  break;
141  case HSM_REPOSITORY_NOT_FOUND:
142  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
143  break;
144  case HSM_NO_REPOSITORIES:
145  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
146  break;
147  default:
148  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
149  }
150  }
151  exit(1);
152  }
153  log_msg(config, LOG_INFO, "HSM opened successfully.");
154  ctx = hsm_create_context();
155  /*}*/
156 
157  log_msg(config, LOG_INFO, "Checking database connection...");
158  if (kaspTryConnect(config, &dbhandle)) {
159  log_msg(config, LOG_ERR, "Database connection failed");
160  exit(1);
161  }
162  log_msg(config, LOG_INFO, "Database connection ok.");
163 
164  /* Create pidfile as late as possible to report start up error */
165  if (writepid(config) == -1) {
166  log_msg(config, LOG_ERR, "cannot write the pidfile %s: %s",
167  config->pidfile, strerror(errno));
168  exit(1);
169  }
170 
171  while (1) {
172 
173  /* Read the config file */
174  status = ReadConfig(config, 1);
175  if (status != 0) {
176  log_msg(config, LOG_ERR, "Error reading config");
177  unlink(config->pidfile);
178  exit(1);
179  }
180  /* If we are in sqlite mode then take a lock out on a file to
181  prevent multiple access (not sure that we can be sure that sqlite is
182  safe for multiple processes to access). */
183  if (DbFlavour() == SQLITE_DB) {
184 
185  /* set up lock filename (it may have changed?) */
186  lock_filename = NULL;
187  StrAppend(&lock_filename, (char *)config->schema);
188  StrAppend(&lock_filename, ".our_lock");
189 
190  lock_fd = fopen(lock_filename, "w");
191  status = get_lite_lock(lock_filename, lock_fd);
192  StrFree(lock_filename);
193  if (status != 0) {
194  log_msg(config, LOG_ERR, "Error getting db lock");
195  unlink(config->pidfile);
196  exit(1);
197  }
198  }
199 
200  log_msg(config, LOG_INFO, "Connecting to Database...");
201  kaspConnect(config, &dbhandle);
202 
203  /* check if any specific policy was passed as an arg */
204  if (config->policy != NULL) {
205  log_msg(config, LOG_INFO, "Will only process policy \"%s\" as specified on the command line with the --policy option.", config->policy);
206  status = KsmPolicyExists(config->policy);
207  if (status != 0) {
208  log_msg(config, LOG_ERR, "Policy \"%s\" not found. Exiting.", config->policy);
209  unlink(config->pidfile);
210  exit(1);
211  }
212  }
213  /* Read all policies.
214  If config->policy is NULL this will return all the policies, if not NULL then just that policy */
215  status = KsmPolicyInit(&handle, config->policy);
216  if (status == 0) {
217  /* get the first policy */
218  status = KsmPolicy(handle, policy);
219  while (status == 0) {
220  log_msg(config, LOG_INFO, "Policy %s found.", policy->name);
221  /* Clear the policy struct */
222  kaspSetPolicyDefaults(policy, NULL);
223 
224  /* Read the parameters for that policy */
225  status = kaspReadPolicy(policy);
226 
227  /* Update the salt if it is not up to date */
228  if (policy->denial->version == 3)
229  {
230  status = KsmPolicyUpdateSalt(policy);
231  if (status != 0) {
232  /* Don't return? */
233  log_msg(config, LOG_ERR, "Error (%d) updating salt for %s", status, policy->name);
234  }
235  }
236 
237  /* Do keygen stuff if required */
238  if (config->manualKeyGeneration == 0) {
239  status = do_keygen(config, policy, ctx);
240  }
241 
242  /* TODO move communicated stuff here eventually */
243  /* Find all zones and do communication stuff */
244 
245  /* Purge dead keys if we are asked to in this policy */
246  if (policy->keys->purge != -1) {
247  status = do_purge(policy->keys->purge, policy->id);
248  }
249 
250  /* get next policy */
251  status = KsmPolicy(handle, policy);
252  }
253  } else {
254  log_msg(config, LOG_ERR, "Error querying KASP DB for policies.");
255  unlink(config->pidfile);
256  exit(1);
257  }
258 
259  /* Communicate zones to the signer */
260  KsmParameterCollectionCache(1); /* Enable caching of policy parameters while in do_communication() */
261  /* If config->policy is NULL then we were not passed a policy on the cmd line and all the policies
262  should be processed. However if we have a specific policy, then the 'policy' parameter will be
263  already set to that when we call do_communiciation and only that policy will be processed. */
264  do_communication(config, policy, (config->policy == NULL));
266 
267  DbFreeResult(handle);
268 
269  /* Disconnect from DB in case we are asleep for a long time */
270  log_msg(config, LOG_INFO, "Disconnecting from Database...");
271  kaspDisconnect(&dbhandle);
272 
273  /* Release sqlite lock file (if we have it) */
274  if (DbFlavour() == SQLITE_DB) {
275  status = release_lite_lock(lock_fd);
276  if (status != 0) {
277  log_msg(config, LOG_ERR, "Error releasing db lock");
278  unlink(config->pidfile);
279  exit(1);
280  }
281  fclose(lock_fd);
282  }
283 
284  if (config->once == true ){
285  log_msg(config, LOG_INFO, "Running once only, exiting...");
286  break;
287  }
288 
289  /* If we have been sent a SIGTERM then it is time to exit */
290  if (config->term == 1 ){
291  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
292  break;
293  }
294  /* Or SIGINT */
295  if (config->term == 2 ){
296  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
297  break;
298  }
299 
300  /* sleep for the interval */
301  tv.tv_sec = config->interval;
302  tv.tv_usec = 0;
303  log_msg(config, LOG_INFO, "Sleeping for %i seconds.",config->interval);
304  select(0, NULL, NULL, NULL, &tv);
305 
306  /* If we have been sent a SIGTERM then it is time to exit */
307  if (config->term == 1 ){
308  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
309  break;
310  }
311  /* Or SIGINT */
312  if (config->term == 2 ){
313  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
314  break;
315  }
316 
317  /* Make sure that we can still talk to the HSM; this call exits if
318  we can not (after trying to reconnect) */
319  check_hsm_connection(&ctx, config);
320 
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_DEBUG, "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;
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  status2 = allocateKeysToZone(policy, KSM_TYPE_ZSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, 0);
763  if (status2 != 0) {
764  log_msg(config, LOG_ERR, "Error allocating zsks to zone %s", zone_name);
765  /* Don't return? try to parse the rest of the zones? */
766  ret = xmlTextReaderRead(reader);
767  StrFree(tag_name);
768  StrFree(zone_name);
769  StrFree(current_filename);
770  continue;
771  }
772  status2 = allocateKeysToZone(policy, KSM_TYPE_KSK, zone_id, config->interval, zone_name, config->manualKeyGeneration, policy->ksk->rollover_scheme);
773  if (status2 != 0) {
774  log_msg(config, LOG_ERR, "Error allocating ksks to zone %s", zone_name);
775  /* Don't return? try to parse the rest of the zones? */
776  ret = xmlTextReaderRead(reader);
777  StrFree(tag_name);
778  StrFree(zone_name);
779  StrFree(current_filename);
780  continue;
781  }
782 
783  /* turn this zone and policy into a file */
784  status2 = commGenSignConf(zone_name, zone_id, current_filename, policy, &signer_flag, config->interval, config->manualKeyGeneration, config->DSSubmitCmd);
785  if (status2 == -2) {
786  log_msg(config, LOG_ERR, "Signconf not written for %s", zone_name);
787  /* Don't return? try to parse the rest of the zones? */
788  ret = xmlTextReaderRead(reader);
789  StrFree(tag_name);
790  StrFree(zone_name);
791  StrFree(current_filename);
792  continue;
793  }
794  else if (status2 != 0) {
795  log_msg(config, LOG_ERR, "Error writing signconf for %s", zone_name);
796  /* Don't return? try to parse the rest of the zones? */
797  ret = xmlTextReaderRead(reader);
798  StrFree(tag_name);
799  StrFree(zone_name);
800  StrFree(current_filename);
801  continue;
802  }
803 
804  /* See if we need to send a warning about an impending rollover */
805  if (config->rolloverNotify != -1) {
806  datetime = DtParseDateTimeString("now");
807 
808  /* Check datetime in case it came back NULL */
809  if (datetime == NULL) {
810  log_msg(config, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
811  unlink(config->pidfile);
812  exit(1);
813  }
814 
815  /* First the KSK */
816  status2 = KsmCheckNextRollover(KSM_TYPE_KSK, zone_id, &ksk_expected);
817  if (status2 == -1) {
818  log_msg(config, LOG_INFO, "No active KSKs yet for zone %s, can't check for impending rollover", zone_name);
819  }
820  else if (status2 != 0) {
821  log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name);
822  /* TODO should we quit or continue? */
823  } else {
824  status2 = DtDateDiff(ksk_expected, datetime, &roll_time);
825  if (status2 != 0) {
826  log_msg(config, LOG_ERR, "Error checking for impending rollover for %s", zone_name);
827  } else {
828 
829  if (roll_time <= config->rolloverNotify) {
830  log_msg(config, LOG_INFO, "Rollover of KSK expected at %s for %s", ksk_expected, zone_name);
831  }
832  StrFree(ksk_expected);
833  }
834  }
835  StrFree(datetime);
836  }
837 
838  StrFree(current_filename);
839  StrFree(zone_name);
840  }
841  /* Read the next line */
842  ret = xmlTextReaderRead(reader);
843  StrFree(tag_name);
844  }
845  xmlFreeTextReader(reader);
846  if (ret != 0) {
847  log_msg(config, LOG_ERR, "%s : failed to parse", zonelist_filename);
848  }
849  } else {
850  log_msg(config, LOG_ERR, "Unable to open %s", zonelist_filename);
851  }
852 
853  xmlFreeDoc(doc);
854  StrFree(zonelist_filename);
855 
856  return status;
857 }
858 
859 /*
860  * generate the configuration file for the signer
861 
862  * returns 0 on success and -1 if something went wrong
863  * -2 if the RequestKeys call failed
864  */
865 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)
866 {
867  int status = 0;
868  int status2 = 0;
869  FILE *file, *file2;
870  int char1, char2; /* for the comparison between 2 files */
871  int same = 0;
872  char *temp_filename; /* In case this fails we write to a temp file and only overwrite
873  the current file when we are finished */
874  char *old_filename; /* Keep a copy of the previous version, just in case! (Also gets
875  round potentially different behaviour of rename over existing
876  file.) */
877  char *signer_command; /* how we will call the signer */
878  int gencnt; /* Number of keys in generate state */
879  int NewDS = 0; /* Did we change the DS Set in any way? */
880  char* datetime = DtParseDateTimeString("now");
881 
882  /* Check datetime in case it came back NULL */
883  if (datetime == NULL) {
884  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
885  exit(1);
886  }
887 
888  if (zone_name == NULL || current_filename == NULL || policy == NULL)
889  {
890  /* error */
891  log_msg(NULL, LOG_ERR, "commGenSignConf, NULL policy or zone provided");
892  MemFree(datetime);
893  return -1;
894  }
895 
896  old_filename = NULL;
897  StrAppend(&old_filename, current_filename);
898  StrAppend(&old_filename, ".OLD");
899 
900  temp_filename = NULL;
901  StrAppend(&temp_filename, current_filename);
902  StrAppend(&temp_filename, ".tmp");
903 
904  file = fopen(temp_filename, "w");
905 
906  if (file == NULL)
907  {
908  /* error */
909  log_msg(NULL, LOG_ERR, "Could not open: %s", temp_filename);
910  MemFree(datetime);
911  StrFree(temp_filename);
912  StrFree(old_filename);
913  return -1;
914  }
915 
916  fprintf(file, "<SignerConfiguration>\n");
917  fprintf(file, "\t<Zone name=\"%s\">\n", zone_name);
918 
919  fprintf(file, "\t\t<Signatures>\n");
920  fprintf(file, "\t\t\t<Resign>PT%dS</Resign>\n", policy->signature->resign);
921  fprintf(file, "\t\t\t<Refresh>PT%dS</Refresh>\n", policy->signer->refresh);
922  fprintf(file, "\t\t\t<Validity>\n");
923  fprintf(file, "\t\t\t\t<Default>PT%dS</Default>\n", policy->signature->valdefault);
924  fprintf(file, "\t\t\t\t<Denial>PT%dS</Denial>\n", policy->signature->valdenial);
925  fprintf(file, "\t\t\t</Validity>\n");
926  fprintf(file, "\t\t\t<Jitter>PT%dS</Jitter>\n", policy->signer->jitter);
927  fprintf(file, "\t\t\t<InceptionOffset>PT%dS</InceptionOffset>\n", policy->signature->clockskew);
928  fprintf(file, "\t\t</Signatures>\n");
929 
930  fprintf(file, "\n");
931 
932  fprintf(file, "\t\t<Denial>\n");
933  if (policy->denial->version == 3)
934  {
935  fprintf(file, "\t\t\t<NSEC3>\n");
936  if (policy->denial->ttl != 0) {
937  fprintf(file, "\t\t\t\t<TTL>PT%dS</TTL>\n", policy->denial->ttl);
938  }
939  if (policy->denial->optout == 1)
940  {
941  fprintf(file, "\t\t\t\t<OptOut />\n");
942  }
943  fprintf(file, "\t\t\t\t<Hash>\n");
944  fprintf(file, "\t\t\t\t\t<Algorithm>%d</Algorithm>\n", policy->denial->algorithm);
945  fprintf(file, "\t\t\t\t\t<Iterations>%d</Iterations>\n", policy->denial->iteration);
946  if (policy->denial->salt[0] == '\0') {
947  fprintf(file, "\t\t\t\t\t<Salt>-</Salt>\n");
948  } else {
949  fprintf(file, "\t\t\t\t\t<Salt>%s</Salt>\n", policy->denial->salt);
950  }
951  fprintf(file, "\t\t\t\t</Hash>\n");
952  fprintf(file, "\t\t\t</NSEC3>\n");
953  } else {
954  fprintf(file, "\t\t\t<NSEC />\n");
955  }
956 
957  fprintf(file, "\t\t</Denial>\n");
958 
959  fprintf(file, "\n");
960 
961  /* start of keys section */
962  fprintf(file, "\t\t<Keys>\n");
963  fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->ksk->ttl);
964 
965  /* get new keys _only_ if we don't have them from before */
966  status = KsmRequestKeys(0, 0, datetime, commKeyConfig, file, policy->id, zone_id, run_interval, &NewDS);
967  if (status != 0) {
968  /*
969  * Something went wrong (it should have been logged) stop this zone.
970  * Clean up the files, don't call the signer and move on to the next zone.
971  */
972  log_msg(NULL, LOG_ERR, "KsmRequestKeys returned: %d", status);
973 
974  /* check for the specific case of not having any keys
975  TODO check that this code can ever be executed after the restructure */
976  if (status == -1) {
977  status2 = KsmRequestGenerateCount(KSM_TYPE_KSK, &gencnt, zone_id);
978  if (status2 == 0 && gencnt == 0) {
979  if(man_key_gen == 1) {
980  log_msg(NULL, LOG_ERR, "There are no KSKs in the generate state; please use \"ods-ksmutil key generate\" to create some.");
981  } else {
982  log_msg(NULL, LOG_WARNING, "There are no KSKs in the generate state; ods-enforcerd will create some on its next run.");
983  }
984  }
985  else if (status2 == 0) {
986  status2 = KsmRequestGenerateCount(KSM_TYPE_ZSK, &gencnt, zone_id);
987  if (status2 == 0 && gencnt == 0) {
988  if(man_key_gen == 1) {
989  log_msg(NULL, LOG_ERR, "There are no ZSKs in the generate state; please use \"ods-ksmutil key generate\" to create some.");
990  } else {
991  log_msg(NULL, LOG_WARNING, "There are no ZSKs in the generate state; ods-enforcerd will create some on its next run.");
992  }
993  }
994  }
995  else {
996  log_msg(NULL, LOG_ERR, "KsmRequestGenerateCount returned: %d", status2);
997  }
998  }
999 
1000  status = fclose(file);
1001  unlink(temp_filename);
1002  MemFree(datetime);
1003  StrFree(temp_filename);
1004  StrFree(old_filename);
1005 
1006  return -2;
1007  }
1008 
1009  fprintf(file, "\t\t</Keys>\n");
1010 
1011  fprintf(file, "\n");
1012 
1013  fprintf(file, "\t\t<SOA>\n");
1014  fprintf(file, "\t\t\t<TTL>PT%dS</TTL>\n", policy->signer->soattl);
1015  fprintf(file, "\t\t\t<Minimum>PT%dS</Minimum>\n", policy->signer->soamin);
1016  fprintf(file, "\t\t\t<Serial>%s</Serial>\n", KsmKeywordSerialValueToName( policy->signer->serial) );
1017  fprintf(file, "\t\t</SOA>\n");
1018 
1019  if (strncmp(policy->audit, "NULL", 4) != 0) {
1020  fprintf(file, "\n");
1021  fprintf(file, "\t\t<Audit />\n");
1022  fprintf(file, "\n");
1023  }
1024 
1025  fprintf(file, "\t</Zone>\n");
1026  fprintf(file, "</SignerConfiguration>\n");
1027 
1028  /* Force flush of stream to disc cache and then onto disc proper
1029  * Do we need to do this? It might be significant on ext4
1030  * NOTE though that there may be a significant overhead associated with it
1031  * ALSO, if we do lose power maybe we should disregard any files when we come
1032  * back as we won't know if they are now too old? */
1033  /*
1034  if (fflush(file) != 0) {
1035  MemFree(datetime);
1036  return -1;
1037  }
1038 
1039  if (fsync(fileno(file)) != 0) {
1040  MemFree(datetime);
1041  return -1;
1042  }
1043  */
1044 
1045  status = fclose(file);
1046  MemFree(datetime);
1047 
1048  if (status == EOF) /* close failed... do something? */
1049  {
1050  log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename);
1051  StrFree(temp_filename);
1052  StrFree(old_filename);
1053  return -1;
1054  }
1055 
1056  /* compare our temp file with the current one (if it exists) */
1057  file = fopen(temp_filename, "rb");
1058  if (file == NULL)
1059  {
1060  /* error */
1061  log_msg(NULL, LOG_ERR, "Could not reopen: %s", temp_filename);
1062  StrFree(temp_filename);
1063  StrFree(old_filename);
1064  return -1;
1065  }
1066 
1067  file2 = fopen(current_filename, "rb"); /* Might not exist */
1068 
1069  /* If current_filename exists then compare its contents to temp_filename */
1070  if (file2 != NULL) {
1071  same = 1;
1072  while(!feof(file)) {
1073  char1 = fgetc(file);
1074  if(ferror(file)) {
1075  log_msg(NULL, LOG_ERR, "Could not read: %s", temp_filename);
1076  fclose(file);
1077  fclose(file2);
1078  StrFree(temp_filename);
1079  StrFree(old_filename);
1080  return -1;
1081  }
1082  char2 = fgetc(file2);
1083  if(ferror(file2)) {
1084  log_msg(NULL, LOG_ERR, "Could not read: %s", current_filename);
1085  fclose(file);
1086  fclose(file2);
1087  StrFree(temp_filename);
1088  StrFree(old_filename);
1089  return -1;
1090  }
1091  if(char1 != char2) {
1092  same = 0;
1093  break;
1094  }
1095  }
1096 
1097  status = fclose(file2);
1098  if (status == EOF) /* close failed... do something? */
1099  {
1100  log_msg(NULL, LOG_ERR, "Could not close: %s", current_filename);
1101  fclose(file);
1102  StrFree(temp_filename);
1103  StrFree(old_filename);
1104  return -1;
1105  }
1106  }
1107 
1108  status = fclose(file);
1109  if (status == EOF) /* close failed... do something? */
1110  {
1111  log_msg(NULL, LOG_ERR, "Could not close: %s", temp_filename);
1112  StrFree(temp_filename);
1113  StrFree(old_filename);
1114  return -1;
1115  }
1116 
1117  /* If either current_filename does not exist, or if it is different to temp then same will == 0 */
1118 
1119  if (same == 0) {
1120 
1121  /* we now have a complete xml file. First move the old one out of the way */
1122  status = rename(current_filename, old_filename);
1123  if (status != 0 && status != -1)
1124  {
1125  /* cope with initial condition of files not existing */
1126  log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", current_filename, old_filename);
1127  StrFree(old_filename);
1128  StrFree(temp_filename);
1129  return -1;
1130  }
1131 
1132  /* Then copy our temp into place */
1133  if (rename(temp_filename, current_filename) != 0)
1134  {
1135  log_msg(NULL, LOG_ERR, "Could not rename: %s -> %s", temp_filename, current_filename);
1136  StrFree(old_filename);
1137  StrFree(temp_filename);
1138  return -1;
1139  }
1140 
1141  if (*signer_flag == 1) {
1142  /* call the signer engine to tell it that something changed */
1143  /* TODO for beta version connect straight to the socket
1144  should we make a blocking call on this?
1145  should we call it here or after we have written all of the files?
1146  have timeout if call is blocking */
1147  signer_command = NULL;
1148  StrAppend(&signer_command, SIGNER_CLI_UPDATE);
1149  StrAppend(&signer_command, " ");
1150  StrAppend(&signer_command, zone_name);
1151 
1152  status = system(signer_command);
1153  if (status != 0)
1154  {
1155  log_msg(NULL, LOG_ERR, "Could not call signer engine");
1156  log_msg(NULL, LOG_INFO, "Will continue: call 'ods-signer update' to manually update zones");
1157  *signer_flag = 0;
1158  }
1159 
1160  StrFree(signer_command);
1161  }
1162  }
1163  else {
1164  log_msg(NULL, LOG_INFO, "No change to: %s", current_filename);
1165  if (remove(temp_filename) != 0)
1166  {
1167  log_msg(NULL, LOG_ERR, "Could not remove: %s", temp_filename);
1168  StrFree(old_filename);
1169  StrFree(temp_filename);
1170  return -1;
1171  }
1172  }
1173 
1174  /* If the DS set changed then log/do something about it */
1175  if (NewDS == 1) {
1176  log_msg(NULL, LOG_INFO, "DSChanged");
1177  status = NewDSSet(zone_id, zone_name, DSSubmitCmd);
1178  }
1179 
1180  StrFree(old_filename);
1181  StrFree(temp_filename);
1182 
1183  return 0;
1184 }
1185 
1186 /*
1187  * CallBack to print key info in signerConfiguration
1188  */
1189 
1190 int commKeyConfig(void* context, KSM_KEYDATA* key_data)
1191 {
1192  FILE *file = (FILE *)context;
1193 
1194  fprintf(file, "\t\t\t<Key>\n");
1195  fprintf(file, "\t\t\t\t<Flags>%d</Flags>\n", key_data->keytype);
1196  fprintf(file, "\t\t\t\t<Algorithm>%d</Algorithm>\n", key_data->algorithm);
1197  fprintf(file, "\t\t\t\t<Locator>%s</Locator>\n", key_data->location);
1198 
1199  if (key_data->keytype == KSM_TYPE_KSK)
1200  {
1201  fprintf(file, "\t\t\t\t<KSK />\n");
1202  }
1203  if (key_data->keytype == KSM_TYPE_ZSK && key_data->state == KSM_STATE_ACTIVE)
1204  {
1205  fprintf(file, "\t\t\t\t<ZSK />\n");
1206  }
1207  if ((key_data->state > KSM_STATE_GENERATE && key_data->state < KSM_STATE_DEAD) || key_data->state == KSM_STATE_KEYPUBLISH)
1208  {
1209  fprintf(file, "\t\t\t\t<Publish />\n");
1210  }
1211  fprintf(file, "\t\t\t</Key>\n");
1212  fprintf(file, "\n");
1213 
1214  return 0;
1215 }
1216 
1217 /* allocateKeysToZone
1218  *
1219  * Description:
1220  * Allocates existing keys to zones
1221  *
1222  * Arguments:
1223  * policy
1224  * policy that the keys were created for
1225  * key_type
1226  * KSK or ZSK
1227  * zone_id
1228  * ID of zone in question
1229  * interval
1230  * time before next run
1231  * zone_name
1232  * just in case we need to log something
1233  * man_key_gen
1234  * lack of keys may be an issue for the user to fix
1235  * int rollover_scheme
1236  * KSK rollover scheme in use
1237  *
1238  * Returns:
1239  * int
1240  * Status return. 0=> Success, non-zero => error.
1241  * 1 == error with input
1242  * 2 == not enough keys to satisfy policy
1243  * 3 == database error
1244  -*/
1245 
1246 
1247 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)
1248 {
1249  int status = 0;
1250  int keys_needed = 0;
1251  int keys_in_queue = 0;
1252  int keys_pending_retirement = 0;
1253  int new_keys = 0;
1254  int key_pair_id = 0;
1255  int i = 0;
1256  DB_ID ignore = 0;
1257  KSM_PARCOLL collection; /* Parameters collection */
1258  char* datetime = DtParseDateTimeString("now");
1259 
1260  /* Check datetime in case it came back NULL */
1261  if (datetime == NULL) {
1262  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
1263  exit(1);
1264  }
1265 
1266  if (policy == NULL) {
1267  log_msg(NULL, LOG_ERR, "NULL policy sent to allocateKeysToZone");
1268  StrFree(datetime);
1269  return 1;
1270  }
1271 
1272  if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) {
1273  log_msg(NULL, LOG_ERR, "Unknown keytype: %i in allocateKeysToZone", key_type);
1274  StrFree(datetime);
1275  return 1;
1276  }
1277 
1278  /* Get list of parameters */
1279  status = KsmParameterCollection(&collection, policy->id);
1280  if (status != 0) {
1281  StrFree(datetime);
1282  return status;
1283  }
1284 
1285  /* Make sure that enough keys are allocated to this zone */
1286  /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */
1287  status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1);
1288  if (status != 0) {
1289  log_msg(NULL, LOG_ERR, "Could not predict key requirement for next interval for %s", zone_name);
1290  StrFree(datetime);
1291  return 3;
1292  }
1293 
1294  /* How many do we have ? TODO should this include the currently active key?*/
1295  status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id);
1296  if (status != 0) {
1297  log_msg(NULL, LOG_ERR, "Could not count current key numbers for zone %s", zone_name);
1298  StrFree(datetime);
1299  return 3;
1300  }
1301 
1302  /* or about to retire */
1303  status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval);
1304  if (status != 0) {
1305  log_msg(NULL, LOG_ERR, "Could not count keys which may retire before the next run (for zone %s)", zone_name);
1306  StrFree(datetime);
1307  return 3;
1308  }
1309 
1310  StrFree(datetime);
1311  new_keys = keys_needed - (keys_in_queue - keys_pending_retirement);
1312 
1313  /* 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); */
1314 
1315  /* Allocate keys */
1316  for (i=0 ; i < new_keys ; i++){
1317  key_pair_id = 0;
1318  if (key_type == KSM_TYPE_KSK) {
1319  status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1320  if (status == -1 || key_pair_id == 0) {
1321  if (man_key_gen == 0) {
1322  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy ksk policy for zone: %s", zone_name);
1323  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1324  }
1325  else {
1326  log_msg(NULL, LOG_ERR, "Not enough keys to satisfy ksk policy for zone: %s", zone_name);
1327  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1328  }
1329  return 2;
1330  }
1331  else if (status != 0) {
1332  log_msg(NULL, LOG_ERR, "Could not get an unallocated ksk for zone: %s", zone_name);
1333  return 3;
1334  }
1335  } else {
1336  status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1337  if (status == -1 || key_pair_id == 0) {
1338  if (man_key_gen == 0) {
1339  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy zsk policy for zone: %s", zone_name);
1340  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1341  }
1342  else {
1343  log_msg(NULL, LOG_ERR, "Not enough keys to satisfy zsk policy for zone: %s", zone_name);
1344  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1345  }
1346  return 2;
1347  }
1348  else if (status != 0) {
1349  log_msg(NULL, LOG_ERR, "Could not get an unallocated zsk for zone: %s", zone_name);
1350  return 3;
1351  }
1352  }
1353  if(key_pair_id > 0) {
1354  status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type, KSM_STATE_GENERATE, datetime, NULL, &ignore);
1355  /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */
1356  } else {
1357  /* This shouldn't happen */
1358  log_msg(NULL, LOG_ERR, "KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name);
1359  exit(1);
1360  }
1361 
1362  }
1363 
1364  return status;
1365 }
1366 
1367 /*
1368  * Read the conf.xml file, extract the location of the zonelist.
1369  */
1370 int read_zonelist_filename(const char* filename, char** zone_list_filename)
1371 {
1372  xmlTextReaderPtr reader = NULL;
1373  xmlDocPtr doc = NULL;
1374  xmlXPathContextPtr xpathCtx = NULL;
1375  xmlXPathObjectPtr xpathObj = NULL;
1376  int ret = 0; /* status of the XML parsing */
1377  char* temp_char = NULL;
1378  char* tag_name = NULL;
1379 
1380  xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
1381 
1382  /* Start reading the file; we will be looking for "Common" tags */
1383  reader = xmlNewTextReaderFilename(filename);
1384  if (reader != NULL) {
1385  ret = xmlTextReaderRead(reader);
1386  while (ret == 1) {
1387  tag_name = (char*) xmlTextReaderLocalName(reader);
1388  /* Found <Common> */
1389  if (strncmp(tag_name, "Common", 6) == 0
1390  && xmlTextReaderNodeType(reader) == 1) {
1391 
1392  /* Expand this node and get the rest of the info with XPath */
1393  xmlTextReaderExpand(reader);
1394  doc = xmlTextReaderCurrentDoc(reader);
1395  if (doc == NULL) {
1396  log_msg(NULL, LOG_ERR, "Error: can not read Common section of %s", filename);
1397  /* Don't return? try to parse the rest of the file? */
1398  ret = xmlTextReaderRead(reader);
1399  continue;
1400  }
1401 
1402  xpathCtx = xmlXPathNewContext(doc);
1403  if(xpathCtx == NULL) {
1404  log_msg(NULL, LOG_ERR, "Error: can not create XPath context for Common section");
1405  /* Don't return? try to parse the rest of the file? */
1406  ret = xmlTextReaderRead(reader);
1407  continue;
1408  }
1409 
1410  /* Evaluate xpath expression for ZoneListFile */
1411  xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
1412  if(xpathObj == NULL) {
1413  log_msg(NULL, LOG_ERR, "Error: unable to evaluate xpath expression: %s", zonelist_expr);
1414  /* Don't return? try to parse the rest of the file? */
1415  ret = xmlTextReaderRead(reader);
1416  continue;
1417  }
1418  *zone_list_filename = NULL;
1419  temp_char = (char *)xmlXPathCastToString(xpathObj);
1420  StrAppend(zone_list_filename, temp_char);
1421  StrFree(temp_char);
1422  xmlXPathFreeObject(xpathObj);
1423  log_msg(NULL, LOG_INFO, "zonelist filename set to %s.", *zone_list_filename);
1424  }
1425  /* Read the next line */
1426  ret = xmlTextReaderRead(reader);
1427  StrFree(tag_name);
1428  }
1429  xmlFreeTextReader(reader);
1430  if (ret != 0) {
1431  log_msg(NULL, LOG_ERR, "%s : failed to parse", filename);
1432  return(1);
1433  }
1434  } else {
1435  log_msg(NULL, LOG_ERR, "Unable to open %s", filename);
1436  return(1);
1437  }
1438  if (xpathCtx) {
1439  xmlXPathFreeContext(xpathCtx);
1440  }
1441  if (doc) {
1442  xmlFreeDoc(doc);
1443  }
1444 
1445  return 0;
1446 }
1447 
1448 /*+
1449  * do_purge - Purge dead Keys
1450  *
1451  *
1452  * Arguments:
1453  *
1454  * int interval
1455  * how long a key needs to have been dead for before we purge it
1456  *
1457  * int policy_id
1458  * ID of the policy
1459  *
1460  * Returns:
1461  * int
1462  * Status return. 0 on success.
1463  * other on fail
1464  */
1465 
1466 int do_purge(int interval, int policy_id)
1467 {
1468  char* sql = NULL; /* SQL query */
1469  char* sql1 = NULL; /* SQL query */
1470  char* sql2 = NULL; /* SQL query */
1471  char* sql3 = NULL; /* SQL query */
1472  int status = 0; /* Status return */
1473  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
1474  DB_RESULT result; /* Result of the query */
1475  DB_ROW row = NULL; /* Row data */
1476 
1477  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
1478  unsigned int nchar; /* Number of characters converted */
1479 
1480  int temp_id = -1; /* place to store the key id returned */
1481  char* temp_loc = NULL; /* place to store location returned */
1482  int count = 0; /* How many keys don't match the purge */
1483 
1484  char *rightnow;
1485 
1486  /* Key information */
1487  hsm_key_t *key = NULL;
1488 
1489  log_msg(NULL, LOG_DEBUG, "Purging keys...");
1490 
1491  rightnow = DtParseDateTimeString("now");
1492 
1493  /* Check datetime in case it came back NULL */
1494  if (rightnow == NULL) {
1495  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
1496  exit(1);
1497  }
1498 
1499  /* Select rows */
1500  StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 ");
1501 
1502  if (policy_id != -1) {
1503  StrAppend(&sql, "and policy_id = ");
1504  snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id);
1505  StrAppend(&sql, stringval);
1506  }
1507 
1508  DusEnd(&sql);
1509 
1510  status = DbExecuteSql(DbHandle(), sql, &result);
1511 
1512  if (status == 0) {
1513  status = DbFetchRow(result, &row);
1514  while (status == 0) {
1515  /* Got a row, check it */
1516  DbInt(row, 0, &temp_id);
1517  DbString(row, 1, &temp_loc);
1518 
1519  sql1 = DqsCountInit("dnsseckeys");
1520  DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1521  DdsConditionInt(&sql1, "(state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1);
1522 
1523 #ifdef USE_MYSQL
1524  nchar = snprintf(buffer, sizeof(buffer),
1525  " or state = %d and DEAD > DATE_ADD('%s', INTERVAL -%d SECOND)) ", KSM_STATE_DEAD, rightnow, interval);
1526 #else
1527  nchar = snprintf(buffer, sizeof(buffer),
1528  " or state = %d and DEAD > DATETIME('%s', '-%d SECONDS')) ", KSM_STATE_DEAD, rightnow, interval);
1529 #endif /* USE_MYSQL */
1530 
1531  if (nchar >= sizeof(buffer)) {
1532  log_msg(NULL, LOG_ERR, "Error: failed to create SQL statement to purge keys\n");
1533  DbStringFree(temp_loc);
1534  DbFreeRow(row);
1535  StrFree(rightnow);
1536  return(-1);
1537  }
1538 
1539  StrAppend(&sql1, buffer);
1540  DqsEnd(&sql1);
1541 
1542  status = DbIntQuery(DbHandle(), &count, sql1);
1543  DqsFree(sql1);
1544 
1545  if (status != 0) {
1546  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1547  DbStringFree(temp_loc);
1548  DbFreeRow(row);
1549  StrFree(rightnow);
1550  return status;
1551  }
1552 
1553  /* If the count is zero then there is no reason not to purge this key */
1554  if (count == 0) {
1555 
1556  /* Delete from dnsseckeys */
1557  sql2 = DdsInit("dnsseckeys");
1558  DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1559  DdsEnd(&sql);
1560 
1561  status = DbExecuteSqlNoResult(DbHandle(), sql2);
1562  DdsFree(sql2);
1563  if (status != 0)
1564  {
1565  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1566  DbStringFree(temp_loc);
1567  DbFreeRow(row);
1568  StrFree(rightnow);
1569  return status;
1570  }
1571 
1572  /* Delete from keypairs */
1573  sql3 = DdsInit("keypairs");
1574  DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0);
1575  DdsEnd(&sql);
1576 
1577  status = DbExecuteSqlNoResult(DbHandle(), sql3);
1578  DdsFree(sql3);
1579  if (status != 0)
1580  {
1581  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1582  DbStringFree(temp_loc);
1583  DbFreeRow(row);
1584  StrFree(rightnow);
1585  return status;
1586  }
1587 
1588  /* Delete from the HSM */
1589  key = hsm_find_key_by_id(NULL, temp_loc);
1590 
1591  if (!key) {
1592  log_msg(NULL, LOG_ERR, "Key not found: %s\n", temp_loc);
1593  DbStringFree(temp_loc);
1594  DbFreeRow(row);
1595  StrFree(rightnow);
1596  return -1;
1597  }
1598 
1599  status = hsm_remove_key(NULL, key);
1600 
1601  hsm_key_free(key);
1602 
1603  if (!status) {
1604  log_msg(NULL, LOG_INFO, "Key remove successful.\n");
1605  } else {
1606  log_msg(NULL, LOG_ERR, "Key remove failed.\n");
1607  DbStringFree(temp_loc);
1608  DbFreeRow(row);
1609  StrFree(rightnow);
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) {
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  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d, %d, %d)",
1679  if (nchar >= sizeof(buffer)) {
1680  status = -1;
1681  return status;
1682  }
1683 
1684  /* Find the oldest active key, this is the one which will be retired
1685  NOTE; this may not match any keys */
1686 
1687  count_clause = DqsCountInit("KEYDATA_VIEW");
1688  DqsConditionInt(&count_clause, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1689  DqsConditionInt(&count_clause, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
1690  if (zone_id != -1) {
1691  DqsConditionInt(&count_clause, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1692  }
1693 
1694  status = DbIntQuery(DbHandle(), &active_count, count_clause);
1695  StrFree(count_clause);
1696  if (status != 0)
1697  {
1698  log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n");
1699  return status;
1700  }
1701 
1702  if (active_count > 0) {
1703 
1704  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
1705  StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1706  StrAppend(&where_clause, stringval);
1707  StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1708  StrAppend(&where_clause, stringval);
1709  StrAppend(&where_clause, ")");
1710 
1711  /* Execute query and free up the query string */
1712  status = DbIntQuery(DbHandle(), &id, where_clause);
1713  StrFree(where_clause);
1714  if (status != 0)
1715  {
1716  log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n");
1717  return status;
1718  }
1719  }
1720 
1721  /* First up we need to count how many DSs we will have */
1722  where = 0;
1723  sql = DqsCountInit("KEYDATA_VIEW");
1724  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1725  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1726  if (zone_id != -1) {
1727  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1728  }
1729  if (id != -1) {
1730  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1731  }
1732  DqsEnd(&sql);
1733 
1734  status = DbIntQuery(DbHandle(), &count, sql);
1735  DqsFree(sql);
1736 
1737  if (status != 0) {
1738  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1739  return status;
1740  }
1741 
1742  if (count == 0) {
1743  /* No KSKs in zone? */
1744  return status;
1745  }
1746 
1747  /* Allocate space for the list of key IDs */
1748  keyids = MemMalloc(count * sizeof(int));
1749 
1750  /* Get the list of IDs */
1751 
1752  where = 0;
1753  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1754  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1755  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1756  if (zone_id != -1) {
1757  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1758  }
1759  if (id != -1) {
1760  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1761  }
1762  DqsEnd(&sql);
1763 
1764  status = KsmKeyInitSql(&result, sql);
1765  DqsFree(sql);
1766 
1767  if (status == 0) {
1768  while (status == 0) {
1769  status = KsmKey(result, &data);
1770  if (status == 0) {
1771  keyids[i] = data.keypair_id;
1772  i++;
1773  }
1774  }
1775 
1776  /* Convert EOF status to success */
1777 
1778  if (status == -1) {
1779  status = 0;
1780  } else {
1781  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1782  StrFree(keyids);
1783  return status;
1784  }
1785 
1786  KsmKeyEnd(result);
1787 
1788  } else {
1789  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1790  StrFree(keyids);
1791  return status;
1792  }
1793 
1794  /*
1795  * Now construct the "IN" statement listing the IDs of the keys we
1796  * are planning to change the state of.
1797  */
1798 
1799  StrAppend(&insql, "(");
1800  for (j = 0; j < i; ++j) {
1801  if (j != 0) {
1802  StrAppend(&insql, ",");
1803  }
1804  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
1805  StrAppend(&insql, buffer);
1806  }
1807  StrAppend(&insql, ")");
1808 
1809  StrFree(keyids);
1810 
1811  /* Indicate that the DS record should now be submitted */
1812  sql2 = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1813  DqsConditionKeyword(&sql2, "ID", DQS_COMPARE_IN, insql, 0);
1814  DqsConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
1815  DqsEnd(&sql2);
1816 
1817  log_msg(NULL, LOG_INFO, "DS Record set has changed, the current set looks like:");
1818 
1819  status = KsmKeyInitSql(&result3, sql2);
1820  DqsFree(sql2);
1821  if (status == 0) {
1822  status = KsmKey(result3, &data3);
1823  while (status == 0) {
1824 
1825  /* Code to output the DNSKEY record (stolen from hsmutil) */
1826  key = hsm_find_key_by_id(NULL, data3.location);
1827 
1828  if (!key) {
1829  log_msg(NULL, LOG_ERR, "Key %s in DB but not repository.", data3.location);
1830  StrFree(insql);
1831  return status;
1832  }
1833 
1834  StrAppend(&ds_seen_buffer, ", ");
1835  StrAppend(&ds_seen_buffer, data3.location);
1836 
1837  sign_params = hsm_sign_params_new();
1838  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name);
1839  sign_params->algorithm = data3.algorithm;
1840  sign_params->flags = LDNS_KEY_ZONE_KEY;
1841  sign_params->flags += LDNS_KEY_SEP_KEY;
1842  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
1843 
1844  /* Set TTL if we can find it; else leave it as the default */
1845  /* We need a policy id */
1846  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
1847  if (status == 0) {
1848 
1849  /* Use this to get the TTL parameter value */
1850  status = KsmParameterValue(KSM_PAR_KSKTTL_STRING, KSM_PAR_KSKTTL_CAT, &rrttl, policy_id, &param_id);
1851  if (status == 0) {
1852  ldns_rr_set_ttl(dnskey_rr, rrttl);
1853  }
1854  }
1855 
1856  temp_char = ldns_rr2str(dnskey_rr);
1857  ldns_rr_free(dnskey_rr);
1858 
1859  /* Replace tab with white-space */
1860  for (i = 0; temp_char[i]; ++i) {
1861  if (temp_char[i] == '\t') {
1862  temp_char[i] = ' ';
1863  }
1864  }
1865  log_msg(NULL, LOG_INFO, "%s", temp_char);
1866 
1867  /* We need to strip off trailing comments before we send
1868  to any clients that might be listening */
1869  for (i = 0; temp_char[i]; ++i) {
1870  if (temp_char[i] == ';') {
1871  temp_char[i] = '\n';
1872  temp_char[i+1] = '\0';
1873  break;
1874  }
1875  }
1876  StrAppend(&ds_buffer, temp_char);
1877  StrFree(temp_char);
1878 
1879 /* StrAppend(&ds_buffer, "\n;KSK DS record (SHA1):\n");
1880  ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
1881  temp_char = ldns_rr2str(ds_sha1_rr);
1882  StrAppend(&ds_buffer, temp_char);
1883  StrFree(temp_char);
1884 
1885  StrAppend(&ds_buffer, "\n;KSK DS record (SHA256):\n");
1886  ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
1887  temp_char = ldns_rr2str(ds_sha256_rr);
1888  StrAppend(&ds_buffer, temp_char);
1889  StrFree(temp_char);
1890 */
1891 
1892  hsm_sign_params_free(sign_params);
1893  hsm_key_free(key);
1894  status = KsmKey(result3, &data3);
1895  }
1896  /* Convert EOF status to success */
1897  if (status == -1) {
1898  status = 0;
1899  }
1900 
1901  KsmKeyEnd(result3);
1902  }
1903 
1904  if (DSSubmitCmd[0] != '\0') {
1905  /* send records to the configured command */
1906  fp = popen(DSSubmitCmd, "w");
1907  if (fp == NULL) {
1908  log_msg(NULL, LOG_ERR, "Failed to run command: %s: %s", DSSubmitCmd, strerror(errno));
1909  return -1;
1910  }
1911  bytes_written = fprintf(fp, "%s", ds_buffer);
1912  if (bytes_written < 0) {
1913  log_msg(NULL, LOG_ERR, "Failed to write to %s: %s", DSSubmitCmd, strerror(errno));
1914  return -1;
1915  }
1916 
1917  if (pclose(fp) == -1) {
1918  log_msg(NULL, LOG_ERR, "Failed to close %s: %s", DSSubmitCmd, strerror(errno));
1919  return -1;
1920  }
1921  }
1922 
1923  StrFree(ds_buffer);
1924 
1925  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);
1926 
1927  StrFree(ds_seen_buffer);
1928 
1929  StrFree(insql);
1930 
1931  return status;
1932 }
1933 
1935 {
1936  int result = 0;
1937  char *hsm_error_message = NULL;
1938 
1939  result = hsm_check_context(*ctx);
1940 
1941  /* If we didn't get HSM_OK then close and reopen HSM */
1942  if (result != HSM_OK) {
1943 
1944  if (*ctx) {
1945  hsm_destroy_context(*ctx);
1946  }
1947 
1948  result = hsm_close();
1949 
1950  if (config->configfile != NULL) {
1951  result = hsm_open(config->configfile, hsm_prompt_pin, NULL);
1952  } else {
1953  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_prompt_pin, NULL);
1954  }
1955  if (result) {
1956  hsm_error_message = hsm_get_error(*ctx);
1957  if (hsm_error_message) {
1958  log_msg(config, LOG_ERR, hsm_error_message);
1959  free(hsm_error_message);
1960  } else {
1961  /* decode the error code ourselves
1962  TODO find if there is a better way to do this (and can all
1963  of these be returned? are there others?) */
1964  switch (result) {
1965  case HSM_ERROR:
1966  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
1967  break;
1968  case HSM_PIN_INCORRECT:
1969  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
1970  break;
1971  case HSM_CONFIG_FILE_ERROR:
1972  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
1973  break;
1974  case HSM_REPOSITORY_NOT_FOUND:
1975  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
1976  break;
1977  case HSM_NO_REPOSITORIES:
1978  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
1979  break;
1980  default:
1981  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
1982  }
1983  }
1984  unlink(config->pidfile);
1985  exit(1);
1986  }
1987  log_msg(config, LOG_INFO, "HSM reopened successfully.");
1988  *ctx = hsm_create_context();
1989  } else {
1990  log_msg(config, LOG_INFO, "HSM connection open.");
1991  }
1992 
1993 }
1994 
void DbFreeResult(DB_RESULT result)
void server_main(DAEMONCONFIG *config)
Definition: enforcer.c:82
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:249
unsigned long sm_capacity
Definition: ksm.h:212
bool once
Definition: daemon.h:91
sqlite3 * DB_HANDLE
Definition: database.h:79
#define KSM_TYPE_ZSK
Definition: ksm.h:363
void kaspConnect(DAEMONCONFIG *config, DB_HANDLE *handle)
Definition: kaspaccess.c:129
char * audit
Definition: ksm.h:261
#define StrFree(x)
Definition: string_util.h:68
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:376
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:372
char location[KSM_NAME_LENGTH]
Definition: ksm.h:112
int KsmKeyCountQueue(int keytype, int *count, int zone_id)
Definition: ksm_key.c:655
KSM_POLICY * KsmPolicyAlloc()
Definition: ksm_policy.c:906
#define KSM_STATE_READY
Definition: ksm.h:370
KSM_COMMON_KEY_POLICY * keys
Definition: ksm.h:254
int state
Definition: ksm.h:102
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:256
void check_hsm_connection(hsm_ctx_t **ctx, DAEMONCONFIG *config)
Definition: enforcer.c:1934
int bits
Definition: ksm.h:208
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:204
char sm_name[KSM_NAME_LENGTH]
Definition: ksm.h:211
int KsmPolicyUpdateSalt(KSM_POLICY *policy)
Definition: ksm_policy.c:498
int shared_keys
Definition: ksm.h:262
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
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)
Definition: enforcer.c:865
#define KSM_STATE_KEYPUBLISH
Definition: ksm.h:384
void DdsFree(char *query)
Definition: dd_string.c:117
int algorithm
Definition: ksm.h:207
#define MemFree(ptr)
Definition: memory.h:50
int read_zonelist_filename(const char *filename, char **zone_list_filename)
Definition: enforcer.c:1370
char * DqsCountInit(const char *table)
Definition: dq_string.c:92
int KsmCheckNextRollover(int keytype, int zone_id, char **datetime)
Definition: ksm_list.c:448
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:194
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:860
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:380
KSM_DENIAL_POLICY * denial
Definition: ksm.h:253
int KsmZoneIdFromName(const char *zone_name, int *zone_id)
Definition: ksm_zone.c:245
KSM_KEY_POLICY * ksk
Definition: ksm.h:255
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:943
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:251
int ReadConfig(DAEMONCONFIG *config, int verbose)
Definition: daemon_util.c:707
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:103
int KsmRequestGenerateCount(int keytype, int *count, int zone_id)
Definition: ksm_request.c:1683
#define KSM_SQL_SIZE
Definition: ksm.h:66
int release_lite_lock(FILE *lock_fd)
Definition: daemon_util.c:1162
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:78
int algorithm
Definition: ksm.h:104
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:447
#define KSM_STATE_RETIRE
Definition: ksm.h:374
#define KSM_STATE_PUBLISH
Definition: ksm.h:368
void KsmParameterCollectionCache(int enable)
char * policy
Definition: daemon.h:117
DB_ID keypair_id
Definition: ksm.h:101
int sm
Definition: ksm.h:210
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:1128
DAEMONCONFIG config
Definition: daemon.c:73
#define KSM_INT_STR_SIZE
Definition: ksm.h:67
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:1247
int id
Definition: ksm.h:248
int ttl
Definition: ksm.h:215
int writepid(DAEMONCONFIG *config)
Definition: daemon_util.c:468
#define KSM_PAR_KSKTTL_STRING
Definition: ksm.h:446
int require_backup
Definition: ksm.h:213
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:378
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:361
int DbInt(DB_ROW row, int field_index, int *value)
void * MemMalloc(size_t size)
Definition: memory.c:59
int algorithm
Definition: ksm.h:189
#define KSM_STATE_DSREADY
Definition: ksm.h:382
int rollover_scheme
Definition: ksm.h:220
int NewDSSet(int zone_id, const char *zone_name, const char *DSSubmitCmd)
Definition: enforcer.c:1636
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:471
int server_init(DAEMONCONFIG *config)
Definition: enforcer.c:63
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:190
#define KSM_STATE_GENERATE
Definition: ksm.h:366
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:1466
KSM_SIGNATURE_POLICY * signature
Definition: ksm.h:252
int commKeyConfig(void *context, KSM_KEYDATA *key_data)
Definition: enforcer.c:1190
void DbStringFree(char *string)