OpenDNSSEC-enforcer  1.4.9
enforcer.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /*
28  * enforcer.c code implements the server_main
29  * function needed by daemon.c
30  *
31  * The bit that makes the daemon do something useful
32  */
33 
34 #include "config.h"
35 
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <syslog.h>
41 #include <sys/stat.h>
42 
43 #include <libxml/xmlreader.h>
44 #include <libxml/xpath.h>
45 
46 #include "daemon.h"
47 #include "daemon_util.h"
48 #include "enforcer.h"
49 #include "kaspaccess.h"
50 
51 #include "ksm/ksm.h"
52 #include "ksm/memory.h"
53 #include "ksm/string_util.h"
54 #include "ksm/string_util2.h"
55 #include "ksm/datetime.h"
56 #include "ksm/db_fields.h"
57 
58 #include "libhsm.h"
59 #include "libhsmdns.h"
60 
61 int
63 {
64  if (config == NULL) {
65  log_msg(NULL, LOG_ERR, "Error in server_init, no config provided");
66  exit(1);
67  }
68 
69  /* set the default pidfile if nothing was provided on the command line*/
70  if (config->pidfile == NULL) {
71  config->pidfile = StrStrdup( (char *)OPENDNSSEC_ENFORCER_PIDFILE);
72  }
73 
74  return 0;
75 }
76 
77 /*
78  * Main loop of enforcerd server
79  */
80 void
82 {
83  DB_RESULT handle;
84  DB_HANDLE dbhandle;
85  int status = 0;
86  struct timeval tv;
87  KSM_POLICY *policy;
88  int result;
89  hsm_ctx_t *ctx = NULL;
90  char *hsm_error_message = NULL;
91 
92  FILE *lock_fd = NULL; /* for sqlite file locking */
93  char *lock_filename = NULL;
94 
95  if (config == NULL) {
96  log_msg(NULL, LOG_ERR, "Error in server_main, no config provided");
97  exit(1);
98  }
99 
100  policy = KsmPolicyAlloc();
101  if (policy == NULL) {
102  log_msg(config, LOG_ERR, "Malloc for policy struct failed");
103  exit(1);
104  }
105  kaspSetPolicyDefaults(policy, NULL);
106 
107  /* Read the config file */
108  status = ReadConfig(config , 0);
109  if (status != 0) {
110  log_msg(config, LOG_ERR, "Error reading config");
111  exit(1);
112  }
113 
114  /* If we are doing key generation then connect to the hsm */
115 /* if (config->manualKeyGeneration == 0) {*/
116  /* We keep the HSM connection open for the lifetime of the daemon */
117  if (config->configfile != NULL) {
118  result = hsm_open(config->configfile, hsm_check_pin);
119  } else {
120  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_check_pin);
121  }
122  if (result) {
123  hsm_error_message = hsm_get_error(ctx);
124  if (hsm_error_message) {
125  log_msg(config, LOG_ERR, "%s", hsm_error_message);
126  free(hsm_error_message);
127  } else {
128  /* decode the error code ourselves
129  TODO find if there is a better way to do this (and can all of these be returned? are there others?) */
130  switch (result) {
131  case HSM_ERROR:
132  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
133  break;
134  case HSM_PIN_INCORRECT:
135  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
136  break;
137  case HSM_CONFIG_FILE_ERROR:
138  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
139  break;
140  case HSM_REPOSITORY_NOT_FOUND:
141  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
142  break;
143  case HSM_NO_REPOSITORIES:
144  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
145  break;
146  default:
147  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
148  }
149  }
150  if (result == HSM_NO_REPOSITORIES) {
151  exit(0);
152  } else {
153  exit(1);
154  }
155  }
156  log_msg(config, LOG_INFO, "HSM opened successfully.");
157  ctx = hsm_create_context();
158  /*}*/
159 
160  log_msg(config, LOG_INFO, "Checking database connection...");
161  if (kaspTryConnect(config, &dbhandle)) {
162  log_msg(config, LOG_ERR, "Database connection failed");
163  exit(1);
164  }
165  log_msg(config, LOG_INFO, "Database connection ok.");
166 
167  /* Create pidfile as late as possible to report start up error */
168  if (writepid(config) == -1) {
169  log_msg(config, LOG_ERR, "cannot write the pidfile %s: %s",
170  config->pidfile, strerror(errno));
171  exit(1);
172  }
173 
174  while (1) {
175 
176  /* Read the config file */
177  status = ReadConfig(config, 1);
178  if (status != 0) {
179  log_msg(config, LOG_ERR, "Error reading config");
180  unlink(config->pidfile);
181  exit(1);
182  }
183  /* If we are in sqlite mode then take a lock out on a file to
184  prevent multiple access (not sure that we can be sure that sqlite is
185  safe for multiple processes to access). */
186  if (DbFlavour() == SQLITE_DB) {
187 
188  /* set up lock filename (it may have changed?) */
189  lock_filename = NULL;
190  StrAppend(&lock_filename, (char *)config->schema);
191  StrAppend(&lock_filename, ".our_lock");
192 
193  lock_fd = fopen(lock_filename, "w");
194  status = get_lite_lock(lock_filename, lock_fd);
195  StrFree(lock_filename);
196  if (status != 0) {
197  log_msg(config, LOG_ERR, "Error getting db lock");
198  unlink(config->pidfile);
199  exit(1);
200  }
201  }
202 
203  log_msg(config, LOG_INFO, "Connecting to Database...");
204  kaspConnect(config, &dbhandle);
205 
206  /* check if any specific policy was passed as an arg */
207  if (config->policy != NULL) {
208  log_msg(config, LOG_INFO, "Will only process policy \"%s\" as specified on the command line with the --policy option.", config->policy);
209  status = KsmPolicyExists(config->policy);
210  if (status != 0) {
211  log_msg(config, LOG_ERR, "Policy \"%s\" not found. Exiting.", config->policy);
212  unlink(config->pidfile);
213  exit(1);
214  }
215  }
216  /* Read all policies.
217  If config->policy is NULL this will return all the policies, if not NULL then just that policy */
218  status = KsmPolicyInit(&handle, config->policy);
219  if (status == 0) {
220  /* get the first policy */
221  status = KsmPolicy(handle, policy);
222  while (status == 0) {
223  log_msg(config, LOG_INFO, "Policy %s found.", policy->name);
224  /* Clear the policy struct */
225  kaspSetPolicyDefaults(policy, NULL);
226 
227  /* Read the parameters for that policy */
228  status = kaspReadPolicy(policy);
229 
230  /* Update the salt if it is not up to date */
231  if (policy->denial->version == 3)
232  {
233  status = KsmPolicyUpdateSalt(policy);
234  if (status != 0) {
235  /* Don't return? */
236  log_msg(config, LOG_ERR, "Error (%d) updating salt for %s", status, policy->name);
237  }
238  }
239 
240  /* Do keygen stuff if required */
241  if (config->manualKeyGeneration == 0) {
242  status = do_keygen(config, policy, ctx);
243  }
244 
245  /* TODO move communicated stuff here eventually */
246  /* Find all zones and do communication stuff */
247 
248  /* Purge dead keys if we are asked to in this policy */
249  if (policy->keys->purge != -1) {
250  status = do_purge(policy->keys->purge, policy->id);
251  }
252 
253  /* get next policy */
254  status = KsmPolicy(handle, policy);
255  }
256  } else {
257  log_msg(config, LOG_ERR, "Error querying KASP DB for policies.");
258  unlink(config->pidfile);
259  exit(1);
260  }
261 
262  /* Communicate zones to the signer */
263  KsmParameterCollectionCache(1); /* Enable caching of policy parameters while in do_communication() */
264  /* If config->policy is NULL then we were not passed a policy on the cmd line and all the policies
265  should be processed. However if we have a specific policy, then the 'policy' parameter will be
266  already set to that when we call do_communiciation and only that policy will be processed. */
267  do_communication(config, policy, (config->policy == NULL));
269 
270  DbFreeResult(handle);
271 
272  /* Disconnect from DB in case we are asleep for a long time */
273  log_msg(config, LOG_INFO, "Disconnecting from Database...");
274  kaspDisconnect(&dbhandle);
275 
276  /* Release sqlite lock file (if we have it) */
277  if (DbFlavour() == SQLITE_DB) {
278  status = release_lite_lock(lock_fd);
279  if (status != 0) {
280  log_msg(config, LOG_ERR, "Error releasing db lock");
281  unlink(config->pidfile);
282  exit(1);
283  }
284  fclose(lock_fd);
285  }
286 
287  if (config->once == true ){
288  log_msg(config, LOG_INFO, "Running once only, exiting...");
289  break;
290  }
291 
292  /* If we have been sent a SIGTERM then it is time to exit */
293  if (config->term == 1 ){
294  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
295  break;
296  }
297  /* Or SIGINT */
298  if (config->term == 2 ){
299  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
300  break;
301  }
302 
303  /* sleep for the interval */
304  tv.tv_sec = config->interval;
305  tv.tv_usec = 0;
306  log_msg(config, LOG_INFO, "Sleeping for %i seconds.",config->interval);
307  select(0, NULL, NULL, NULL, &tv);
308 
309  /* If we have been sent a SIGTERM then it is time to exit */
310  if (config->term == 1 ){
311  log_msg(config, LOG_INFO, "Received SIGTERM, exiting...");
312  break;
313  }
314  /* Or SIGINT */
315  if (config->term == 2 ){
316  log_msg(config, LOG_INFO, "Received SIGINT, exiting...");
317  break;
318  }
319 
320  /* Make sure that we can still talk to the HSM; this call exits if
321  we can not (after trying to reconnect) */
322  check_hsm_connection(&ctx, config);
323  }
324 
325  /*
326  * Destroy HSM context
327  */
328  if (ctx) {
329  hsm_destroy_context(ctx);
330  }
331 
332  result = hsm_close();
333  log_msg(config, LOG_INFO, "all done! hsm_close result: %d", result);
334 
335  KsmPolicyFree(policy);
336 
337  if (unlink(config->pidfile) == -1) {
338  log_msg(config, LOG_ERR, "unlink pidfile %s failed: %s",
339  config->pidfile?config->pidfile:"(null)",
340  strerror(errno));
341  }
342 
343  xmlCleanupParser();
344 
345 }
346 
347 int do_keygen(DAEMONCONFIG *config, KSM_POLICY* policy, hsm_ctx_t *ctx)
348 {
349  int status = 0;
350 
351  char *rightnow;
352  int i = 0;
353  char *id;
354  hsm_key_t *key = NULL;
355  char *hsm_error_message = NULL;
356  DB_ID ignore = 0;
357  int ksks_needed = 0; /* Total No of ksks needed before next generation run */
358  int zsks_needed = 0; /* Total No of zsks needed before next generation run */
359  int keys_in_queue = 0; /* number of unused keys */
360  int new_keys = 0; /* number of keys required */
361  unsigned int current_count = 0; /* number of keys already in HSM */
362 
363  int same_keys = 0; /* Do ksks and zsks look the same ? */
364  int ksks_created = 0; /* Were any KSKs created? */
365 
366  DB_RESULT result;
367  int zone_count = 0; /* Number of zones on policy */
368 
369  if (policy->shared_keys == 1 ) {
370  log_msg(config, LOG_INFO, "Key sharing is On");
371  } else {
372  log_msg(config, LOG_INFO, "Key sharing is Off.");
373  }
374 
375  rightnow = DtParseDateTimeString("now");
376 
377  /* Check datetime in case it came back NULL */
378  if (rightnow == NULL) {
379  log_msg(config, LOG_ERR, "Couldn't turn \"now\" into a date, quitting...");
380  exit(1);
381  }
382 
383  /* See if our ZSKs and KSKs look the same */
384  if (policy->ksk->sm == policy->zsk->sm && policy->ksk->bits == policy->zsk->bits && policy->ksk->algorithm == policy->zsk->algorithm) {
385  same_keys = 1;
386  } else {
387  same_keys = 0;
388  }
389 
390  /* How many zones on this policy */
391  status = KsmZoneCountInit(&result, policy->id);
392  if (status == 0) {
393  status = KsmZoneCount(result, &zone_count);
394  }
395  DbFreeResult(result);
396 
397  if (status == 0) {
398  /* make sure that we have at least one zone */
399  if (zone_count == 0) {
400  log_msg(config, LOG_INFO, "No zones on policy %s, skipping...", policy->name);
401  StrFree(rightnow);
402  return status;
403  }
404  } else {
405  log_msg(NULL, LOG_ERR, "Could not count zones on policy %s", policy->name);
406  StrFree(rightnow);
407  return status;
408  }
409  log_msg(config, LOG_INFO, "%d zone(s) found on policy \"%s\"\n", zone_count, policy->name);
410 
411  /* Find out how many ksk keys are needed for the POLICY */
412  status = KsmKeyPredict(policy->id, KSM_TYPE_KSK, policy->shared_keys, config->interval, &ksks_needed, policy->ksk->rollover_scheme, zone_count);
413  if (status != 0) {
414  log_msg(NULL, LOG_ERR, "Could not predict ksk requirement for next interval for %s", policy->name);
415  /* TODO exit? continue with next policy? */
416  }
417  /* Find out how many suitable keys we have */
418  status = KsmKeyCountStillGood(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_KSK);
419  if (status != 0) {
420  log_msg(NULL, LOG_ERR, "Could not count current ksk numbers for policy %s", policy->name);
421  /* TODO exit? continue with next policy? */
422  }
423  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
424 
425  new_keys = ksks_needed - keys_in_queue;
426 
427  /* Check capacity of HSM will not be exceeded */
428  if (policy->ksk->sm_capacity != 0 && new_keys >= 0) {
429  current_count = hsm_count_keys_repository(ctx, policy->ksk->sm_name);
430  if (current_count >= policy->ksk->sm_capacity) {
431  log_msg(config, LOG_ERR, "Repository %s is full, cannot create more KSKs for policy %s\n", policy->ksk->sm_name, policy->name);
432  new_keys = 0;
433  }
434  else if (current_count + new_keys > policy->ksk->sm_capacity) {
435  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);
436  new_keys = policy->ksk->sm_capacity - current_count;
437  }
438  }
439  if (new_keys <= 0 ) {
440  log_msg(config, LOG_INFO,"No new KSKs need to be created.\n");
441  }
442  else {
443  log_msg(config, LOG_INFO, "%d new KSK(s) (%d bits) need to be created for policy %s: keys_to_generate(%d) = keys_needed(%d) - keys_available(%d).\n", new_keys, policy->ksk->bits, policy->name, new_keys, ksks_needed, keys_in_queue);
444  }
445 
446  /* Create the required keys */
447  for (i=new_keys ; i > 0 ; i--){
448  if (hsm_supported_algorithm(policy->ksk->algorithm) == 0) {
449  /* NOTE: for now we know that libhsm only supports RSA keys */
450  key = hsm_generate_rsa_key(ctx, policy->ksk->sm_name, policy->ksk->bits);
451  if (key) {
452  log_msg(config, LOG_DEBUG, "Created key in repository %s", policy->ksk->sm_name);
453  } else {
454  log_msg(config, LOG_ERR, "Error creating key in repository %s", policy->ksk->sm_name);
455  hsm_error_message = hsm_get_error(ctx);
456  if (hsm_error_message) {
457  log_msg(config, LOG_ERR, "%s", hsm_error_message);
458  free(hsm_error_message);
459  }
460  unlink(config->pidfile);
461  exit(1);
462  }
463  id = hsm_get_key_id(ctx, key);
464  hsm_key_free(key);
465  status = KsmKeyPairCreate(policy->id, id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, rightnow, &ignore);
466  if (status != 0) {
467  log_msg(config, LOG_ERR,"Error creating key in Database");
468  hsm_error_message = hsm_get_error(ctx);
469  if (hsm_error_message) {
470  log_msg(config, LOG_ERR, "%s", hsm_error_message);
471  free(hsm_error_message);
472  }
473  unlink(config->pidfile);
474  exit(1);
475  }
476  log_msg(config, LOG_INFO, "Created KSK size: %i, alg: %i with id: %s in repository: %s and database.", policy->ksk->bits,
477  policy->ksk->algorithm, id, policy->ksk->sm_name);
478  free(id);
479  } else {
480  log_msg(config, LOG_ERR, "Key algorithm %d unsupported by libhsm, exiting...", policy->ksk->algorithm);
481  unlink(config->pidfile);
482  exit(1);
483  }
484  }
485  ksks_created = new_keys;
486 
487  /* Find out how many zsk keys are needed */
488  keys_in_queue = 0;
489  new_keys = 0;
490  current_count = 0;
491 
492  /* Find out how many zsk keys are needed for the POLICY */
493  status = KsmKeyPredict(policy->id, KSM_TYPE_ZSK, policy->shared_keys, config->interval, &zsks_needed, 0, zone_count);
494  if (status != 0) {
495  log_msg(NULL, LOG_ERR, "Could not predict zsk requirement for next intervalfor %s", policy->name);
496  /* TODO exit? continue with next policy? */
497  }
498  /* Find out how many suitable keys we have */
499  status = KsmKeyCountStillGood(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, config->interval, rightnow, &keys_in_queue, KSM_TYPE_ZSK);
500  if (status != 0) {
501  log_msg(NULL, LOG_ERR, "Could not count current zsk numbers for policy %s", policy->name);
502  /* TODO exit? continue with next policy? */
503  }
504  /* Don't have to adjust the queue for shared keys as the prediction has already taken care of that.*/
505  /* Might have to account for ksks */
506  if (same_keys) {
507  keys_in_queue -= ksks_needed;
508  }
509 
510  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 for policy %s: keys_to_generate(%d) = keys_needed(%d) - keys_available(%d).\n", new_keys, policy->zsk->bits, policy->name, new_keys, zsks_needed, keys_in_queue);
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  int flags = key_data->keytype;
1193 
1194  if (key_data->revoke)
1195  flags |= KSM_FLAG_REVOKE;
1196 
1197  fprintf(file, "\t\t\t<Key>\n");
1198  fprintf(file, "\t\t\t\t<Flags>%d</Flags>\n", flags);
1199  fprintf(file, "\t\t\t\t<Algorithm>%d</Algorithm>\n", key_data->algorithm);
1200  fprintf(file, "\t\t\t\t<Locator>%s</Locator>\n", key_data->location);
1201 
1202  if (key_data->keytype == KSM_TYPE_KSK) {
1203  if (!(key_data->rfc5011 && key_data->state == KSM_STATE_PUBLISH))
1204  fprintf(file, "\t\t\t\t<KSK />\n");
1205  }
1206  if (key_data->keytype == KSM_TYPE_ZSK && key_data->state == KSM_STATE_ACTIVE)
1207  {
1208  fprintf(file, "\t\t\t\t<ZSK />\n");
1209  }
1210  if ((key_data->state > KSM_STATE_GENERATE && key_data->state < KSM_STATE_DEAD) || key_data->state == KSM_STATE_KEYPUBLISH)
1211  {
1212  fprintf(file, "\t\t\t\t<Publish />\n");
1213  }
1214  if (key_data->rfc5011)
1215  {
1216  fprintf(file, "\t\t\t\t<RFC5011 />\n");
1217  }
1218  fprintf(file, "\t\t\t</Key>\n");
1219  fprintf(file, "\n");
1220 
1221  return 0;
1222 }
1223 
1224 /* allocateKeysToZone
1225  *
1226  * Description:
1227  * Allocates existing keys to zones
1228  *
1229  * Arguments:
1230  * policy
1231  * policy that the keys were created for
1232  * key_type
1233  * KSK or ZSK
1234  * zone_id
1235  * ID of zone in question
1236  * interval
1237  * time before next run
1238  * zone_name
1239  * just in case we need to log something
1240  * man_key_gen
1241  * lack of keys may be an issue for the user to fix
1242  * int rollover_scheme
1243  * KSK rollover scheme in use
1244  *
1245  * Returns:
1246  * int
1247  * Status return. 0=> Success, non-zero => error.
1248  * 1 == error with input
1249  * 2 == not enough keys to satisfy policy
1250  * 3 == database error
1251  -*/
1252 
1253 
1254 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)
1255 {
1256  int status = 0;
1257  int keys_needed = 0;
1258  int keys_in_queue = 0;
1259  int keys_pending_retirement = 0;
1260  int new_keys = 0;
1261  int key_pair_id = 0;
1262  int i = 0;
1263  DB_ID ignore = 0;
1264  KSM_PARCOLL collection; /* Parameters collection */
1265  char* datetime = DtParseDateTimeString("now");
1266 
1267  /* Check datetime in case it came back NULL */
1268  if (datetime == NULL) {
1269  log_msg(NULL, LOG_DEBUG, "Couldn't turn \"now\" into a date, quitting...");
1270  return -1;
1271  }
1272 
1273  if (policy == NULL) {
1274  log_msg(NULL, LOG_ERR, "NULL policy sent to allocateKeysToZone");
1275  StrFree(datetime);
1276  return 1;
1277  }
1278 
1279  if (key_type != KSM_TYPE_KSK && key_type != KSM_TYPE_ZSK) {
1280  log_msg(NULL, LOG_ERR, "Unknown keytype: %i in allocateKeysToZone", key_type);
1281  StrFree(datetime);
1282  return 1;
1283  }
1284 
1285  /* Get list of parameters */
1286  status = KsmParameterCollection(&collection, policy->id);
1287  if (status != 0) {
1288  StrFree(datetime);
1289  return status;
1290  }
1291 
1292  /* Make sure that enough keys are allocated to this zone */
1293  /* How many do we need ? (set sharing to 1 so that we get the number needed for a single zone on this policy */
1294  status = KsmKeyPredict(policy->id, key_type, 1, interval, &keys_needed, rollover_scheme, 1);
1295  if (status != 0) {
1296  log_msg(NULL, LOG_ERR, "Could not predict key requirement for next interval for %s", zone_name);
1297  StrFree(datetime);
1298  return 3;
1299  }
1300 
1301  /* How many do we have ? TODO should this include the currently active key?*/
1302  status = KsmKeyCountQueue(key_type, &keys_in_queue, zone_id);
1303  if (status != 0) {
1304  log_msg(NULL, LOG_ERR, "Could not count current key numbers for zone %s", zone_name);
1305  StrFree(datetime);
1306  return 3;
1307  }
1308 
1309  /* or about to retire */
1310  status = KsmRequestPendingRetireCount(key_type, datetime, &collection, &keys_pending_retirement, zone_id, interval);
1311  if (status != 0) {
1312  log_msg(NULL, LOG_ERR, "Could not count keys which may retire before the next run (for zone %s)", zone_name);
1313  StrFree(datetime);
1314  return 3;
1315  }
1316 
1317  StrFree(datetime);
1318  new_keys = keys_needed - (keys_in_queue - keys_pending_retirement);
1319 
1320  /* TODO: Add check that new_keys is more than 0 */
1321  /*log_msg(NULL, LOG_DEBUG, "%s key allocation for zone %s: keys_to_allocate(%d) = keys_needed(%d) - (keys_available(%d) - keys_pending_retirement(%d))\n", key_type == KSM_TYPE_KSK ? "KSK" : "ZSK", zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement); */
1322 
1323  /* Allocate keys */
1324  for (i=0 ; i < new_keys ; i++){
1325  key_pair_id = 0;
1326  if (key_type == KSM_TYPE_KSK) {
1327  status = KsmKeyGetUnallocated(policy->id, policy->ksk->sm, policy->ksk->bits, policy->ksk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1328  if (status == -1 || key_pair_id == 0) {
1329  if (man_key_gen == 0) {
1330  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy ksk policy for zone: %s. keys_to_allocate(%d) = keys_needed(%d) - (keys_available(%d) - keys_pending_retirement(%d))\n", zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement);
1331  log_msg(NULL, LOG_WARNING, "Tried to allocate %d keys, failed on allocating key number %d", new_keys, i+1);
1332  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1333  }
1334  else {
1335  log_msg(NULL, LOG_ERR, "Not enough keys to satisfy ksk policy for zone: %s. keys_to_allocate(%d) = keys_needed(%d) - (keys_available(%d) - keys_pending_retirement(%d))\n", zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement);
1336  log_msg(NULL, LOG_ERR, "Tried to allocate %d keys, failed on allocating key number %d", new_keys, i+1);
1337  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1338  }
1339  return 2;
1340  }
1341  else if (status != 0) {
1342  log_msg(NULL, LOG_ERR, "Could not get an unallocated ksk for zone: %s", zone_name);
1343  return 3;
1344  }
1345  } else {
1346  status = KsmKeyGetUnallocated(policy->id, policy->zsk->sm, policy->zsk->bits, policy->zsk->algorithm, zone_id, policy->keys->share_keys, &key_pair_id);
1347  if (status == -1 || key_pair_id == 0) {
1348  if (man_key_gen == 0) {
1349  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy zsk policy for zone: %s. keys_to_allocate(%d) = keys_needed(%d) - (keys_available(%d) - keys_pending_retirement(%d))\n", zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement);
1350  log_msg(NULL, LOG_WARNING, "Tried to allocate %d keys, failed on allocating key number %d", new_keys, i+1);
1351  log_msg(NULL, LOG_WARNING, "ods-enforcerd will create some more keys on its next run");
1352  }
1353  else {
1354  log_msg(NULL, LOG_WARNING, "Not enough keys to satisfy zsk policy for zone: %s. keys_to_allocate(%d) = keys_needed(%d) - (keys_available(%d) - keys_pending_retirement(%d))\n", zone_name, new_keys, keys_needed, keys_in_queue, keys_pending_retirement);
1355  log_msg(NULL, LOG_WARNING, "Tried to allocate %d keys, failed on allocating key number %d", new_keys, i+1);
1356  log_msg(NULL, LOG_ERR, "please use \"ods-ksmutil key generate\" to create some more keys.");
1357  }
1358  return 2;
1359  }
1360  else if (status != 0) {
1361  log_msg(NULL, LOG_ERR, "Could not get an unallocated zsk for zone: %s", zone_name);
1362  return 3;
1363  }
1364  }
1365  if(key_pair_id > 0) {
1366  status = KsmDnssecKeyCreate(zone_id, key_pair_id, key_type,
1367  KSM_STATE_GENERATE, policy->ksk->rfc5011, datetime,
1368  NULL, &ignore);
1369  /* fprintf(stderr, "comm(%d) %s: allocated keypair id %d\n", key_type, zone_name, key_pair_id); */
1370  } else {
1371  /* This shouldn't happen */
1372  log_msg(NULL, LOG_ERR, "KsmKeyGetUnallocated returned bad key_id %d for zone: %s; exiting...", key_pair_id, zone_name);
1373  return -1;
1374  }
1375  }
1376  if (new_keys > 0) {
1377  log_msg(NULL, LOG_DEBUG, "%s key allocation for zone %s: %d key(s) allocated\n", key_type == KSM_TYPE_KSK ? "KSK" : "ZSK", zone_name, new_keys);
1378  }
1379  return status;
1380 }
1381 
1382 /*
1383  * Read the conf.xml file, extract the location of the zonelist.
1384  */
1385 int read_zonelist_filename(const char* filename, char** zone_list_filename)
1386 {
1387  xmlTextReaderPtr reader = NULL;
1388  xmlDocPtr doc = NULL;
1389  xmlXPathContextPtr xpathCtx = NULL;
1390  xmlXPathObjectPtr xpathObj = NULL;
1391  int ret = 0; /* status of the XML parsing */
1392  char* temp_char = NULL;
1393  char* tag_name = NULL;
1394 
1395  xmlChar *zonelist_expr = (unsigned char*) "//Common/ZoneListFile";
1396 
1397  /* Start reading the file; we will be looking for "Common" tags */
1398  reader = xmlNewTextReaderFilename(filename);
1399  if (reader != NULL) {
1400  ret = xmlTextReaderRead(reader);
1401  while (ret == 1) {
1402  tag_name = (char*) xmlTextReaderLocalName(reader);
1403  /* Found <Common> */
1404  if (strncmp(tag_name, "Common", 6) == 0
1405  && xmlTextReaderNodeType(reader) == 1) {
1406 
1407  /* Expand this node and get the rest of the info with XPath */
1408  xmlTextReaderExpand(reader);
1409  doc = xmlTextReaderCurrentDoc(reader);
1410  if (doc == NULL) {
1411  log_msg(NULL, LOG_ERR, "Error: can not read Common section of %s", filename);
1412  /* Don't return? try to parse the rest of the file? */
1413  ret = xmlTextReaderRead(reader);
1414  continue;
1415  }
1416 
1417  xpathCtx = xmlXPathNewContext(doc);
1418  if(xpathCtx == NULL) {
1419  log_msg(NULL, LOG_ERR, "Error: can not create XPath context for Common section");
1420  /* Don't return? try to parse the rest of the file? */
1421  ret = xmlTextReaderRead(reader);
1422  continue;
1423  }
1424 
1425  /* Evaluate xpath expression for ZoneListFile */
1426  xpathObj = xmlXPathEvalExpression(zonelist_expr, xpathCtx);
1427  if(xpathObj == NULL) {
1428  log_msg(NULL, LOG_ERR, "Error: unable to evaluate xpath expression: %s", zonelist_expr);
1429  /* Don't return? try to parse the rest of the file? */
1430  ret = xmlTextReaderRead(reader);
1431  continue;
1432  }
1433  *zone_list_filename = NULL;
1434  temp_char = (char *)xmlXPathCastToString(xpathObj);
1435  StrAppend(zone_list_filename, temp_char);
1436  StrFree(temp_char);
1437  xmlXPathFreeObject(xpathObj);
1438  log_msg(NULL, LOG_INFO, "zonelist filename set to %s.", *zone_list_filename);
1439  }
1440  /* Read the next line */
1441  ret = xmlTextReaderRead(reader);
1442  StrFree(tag_name);
1443  }
1444  xmlFreeTextReader(reader);
1445  if (ret != 0) {
1446  log_msg(NULL, LOG_ERR, "%s : failed to parse", filename);
1447  return(1);
1448  }
1449  } else {
1450  log_msg(NULL, LOG_ERR, "Unable to open %s", filename);
1451  return(1);
1452  }
1453  if (xpathCtx) {
1454  xmlXPathFreeContext(xpathCtx);
1455  }
1456  if (doc) {
1457  xmlFreeDoc(doc);
1458  }
1459 
1460  return 0;
1461 }
1462 
1463 /*+
1464  * do_purge - Purge dead Keys
1465  *
1466  *
1467  * Arguments:
1468  *
1469  * int interval
1470  * how long a key needs to have been dead for before we purge it
1471  *
1472  * int policy_id
1473  * ID of the policy
1474  *
1475  * Returns:
1476  * int
1477  * Status return. 0 on success.
1478  * other on fail
1479  */
1480 
1481 int do_purge(int interval, int policy_id)
1482 {
1483  char* sql = NULL; /* SQL query */
1484  char* sql1 = NULL; /* SQL query */
1485  char* sql2 = NULL; /* SQL query */
1486  char* sql3 = NULL; /* SQL query */
1487  int status = 0; /* Status return */
1488  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
1489  DB_RESULT result; /* Result of the query */
1490  DB_ROW row = NULL; /* Row data */
1491 
1492  char buffer[KSM_SQL_SIZE]; /* Long enough for any statement */
1493 
1494  int temp_id = -1; /* place to store the key id returned */
1495  char* temp_loc = NULL; /* place to store location returned */
1496  int count = 0; /* How many keys don't match the purge */
1497 
1498  char *rightnow;
1499 
1500  /* Key information */
1501  hsm_key_t *key = NULL;
1502 
1503  log_msg(NULL, LOG_DEBUG, "Purging keys...");
1504 
1505  rightnow = DtParseDateTimeString("now");
1506 
1507  /* Check datetime in case it came back NULL */
1508  if (rightnow == NULL) {
1509  log_msg(NULL, LOG_ERR, "Couldn't turn \"now\" into a date, quitting...");
1510  exit(1);
1511  }
1512 
1513  /* Select rows */
1514  StrAppend(&sql, "select distinct id, location from KEYDATA_VIEW where state = 6 ");
1515 
1516  if (policy_id != -1) {
1517  StrAppend(&sql, "and policy_id = ");
1518  snprintf(stringval, KSM_INT_STR_SIZE, "%d", policy_id);
1519  StrAppend(&sql, stringval);
1520  }
1521 
1522  DusEnd(&sql);
1523 
1524  status = DbExecuteSql(DbHandle(), sql, &result);
1525 
1526  if (status == 0) {
1527  status = DbFetchRow(result, &row);
1528  while (status == 0) {
1529  /* Got a row, check it */
1530  DbInt(row, 0, &temp_id);
1531  DbString(row, 1, &temp_loc);
1532 
1533  sql1 = DqsCountInit("dnsseckeys");
1534  DdsConditionInt(&sql1, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1535  DdsConditionInt(&sql1, "(state", DQS_COMPARE_NE, KSM_STATE_DEAD, 1);
1536 
1537  status = DbDateDiff(rightnow, interval, -1, buffer, KSM_SQL_SIZE);
1538  if (status != 0) {
1539  log_msg(NULL, LOG_ERR, "DbDateDiff failed\n");
1540  DbStringFree(temp_loc);
1541  DbFreeRow(row);
1542  StrFree(rightnow);
1543  DusFree(sql);
1544  DqsFree(sql1);
1545  return status;
1546  }
1547 
1548  StrAppend(&sql1, " or state = 6 and DEAD > ");
1549  StrAppend(&sql1, buffer);
1550  StrAppend(&sql1, ")");
1551  DqsEnd(&sql1);
1552 
1553  status = DbIntQuery(DbHandle(), &count, sql1);
1554  DqsFree(sql1);
1555 
1556  if (status != 0) {
1557  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1558  DbStringFree(temp_loc);
1559  DbFreeRow(row);
1560  StrFree(rightnow);
1561  DusFree(sql);
1562  return status;
1563  }
1564 
1565  /* If the count is zero then there is no reason not to purge this key */
1566  if (count == 0) {
1567 
1568  /* Delete from dnsseckeys */
1569  sql2 = DdsInit("dnsseckeys");
1570  DdsConditionInt(&sql2, "keypair_id", DQS_COMPARE_EQ, temp_id, 0);
1571  DdsEnd(&sql2);
1572 
1573  status = DbExecuteSqlNoResult(DbHandle(), sql2);
1574  DdsFree(sql2);
1575  if (status != 0)
1576  {
1577  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1578  DbStringFree(temp_loc);
1579  DbFreeRow(row);
1580  StrFree(rightnow);
1581  DusFree(sql);
1582  return status;
1583  }
1584 
1585  /* Delete from keypairs */
1586  sql3 = DdsInit("keypairs");
1587  DdsConditionInt(&sql3, "id", DQS_COMPARE_EQ, temp_id, 0);
1588  DdsEnd(&sql);
1589 
1590  status = DbExecuteSqlNoResult(DbHandle(), sql3);
1591  DdsFree(sql3);
1592  if (status != 0)
1593  {
1594  log_msg(NULL, LOG_ERR, "SQL failed: %s\n", DbErrmsg(DbHandle()));
1595  DbStringFree(temp_loc);
1596  DbFreeRow(row);
1597  StrFree(rightnow);
1598  DusFree(sql);
1599  return status;
1600  }
1601 
1602  /* Delete from the HSM */
1603  key = hsm_find_key_by_id(NULL, temp_loc);
1604 
1605  if (!key) {
1606  log_msg(NULL, LOG_ERR, "Key not found: %s\n", temp_loc);
1607  DbStringFree(temp_loc);
1608  DbFreeRow(row);
1609  StrFree(rightnow);
1610  DusFree(sql);
1611  return -1;
1612  }
1613 
1614  status = hsm_remove_key(NULL, key);
1615 
1616  hsm_key_free(key);
1617 
1618  if (!status) {
1619  log_msg(NULL, LOG_INFO, "Key remove successful: %s\n", temp_loc);
1620  } else {
1621  log_msg(NULL, LOG_ERR, "Key remove failed: %s\n", temp_loc);
1622  DbStringFree(temp_loc);
1623  DbFreeRow(row);
1624  StrFree(rightnow);
1625  DusFree(sql);
1626  return -1;
1627  }
1628  }
1629 
1630  /* NEXT! */
1631  status = DbFetchRow(result, &row);
1632  }
1633 
1634  /* Convert EOF status to success */
1635 
1636  if (status == -1) {
1637  status = 0;
1638  }
1639 
1640  DbFreeResult(result);
1641  }
1642 
1643  DusFree(sql);
1644  DbFreeRow(row);
1645 
1646  DbStringFree(temp_loc);
1647  StrFree(rightnow);
1648 
1649  return status;
1650 }
1651 
1652 int NewDSSet(int zone_id, const char* zone_name, const char* DSSubmitCmd, int DSSubCKA_ID) {
1653  int where = 0; /* for the SELECT statement */
1654  char* sql = NULL; /* SQL statement (when verifying) */
1655  char* sql2 = NULL; /* SQL statement (if getting DS) */
1656  int status = 0; /* Status return */
1657  int count = 0; /* How many keys fit our select? */
1658  int i = 0; /* A counter */
1659  int j = 0; /* Another counter */
1660  char* insql = NULL; /* SQL "IN" clause */
1661  int* keyids; /* List of IDs of keys to promote */
1662  DB_RESULT result; /* List result set */
1663  KSM_KEYDATA data; /* Data for this key */
1664  size_t nchar; /* Number of characters written */
1665  char buffer[256]; /* For constructing part of the command */
1666  char* count_clause = NULL;
1667  char* where_clause = NULL;
1668  int id = -1; /* ID of key which will retire */
1669  int active_count = -1; /* Number of currently active keys */
1670 
1671  char stringval[KSM_INT_STR_SIZE]; /* For Integer to String conversion */
1672  DB_RESULT result3; /* Result of DS query */
1673  KSM_KEYDATA data3; /* DS information */
1674  char* ds_buffer = NULL; /* Contents of DS records */
1675  char* ds_seen_buffer = NULL; /* Which keys have we promoted */
1676  char* temp_char = NULL; /* Contents of DS records */
1677 
1678  /* To find the ttl of the DS */
1679  int policy_id = -1;
1680  int rrttl = -1;
1681  int param_id = -1; /* unused */
1682 
1683  /* Key information */
1684  hsm_key_t *key = NULL;
1685  ldns_rr *dnskey_rr = NULL;
1686  hsm_sign_params_t *sign_params = NULL;
1687 
1688  FILE *fp;
1689  int bytes_written = -1;
1690 
1691  struct stat stat_ret; /* we will test the DSSubmitCmd */
1692 
1693  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d, %d, %d, %d, %d)",
1697  if (nchar >= sizeof(buffer)) {
1698  status = -1;
1699  return status;
1700  }
1701 
1702  /* Find the oldest active key, this is the one which will be retired
1703  NOTE; this may not match any keys */
1704 
1705  count_clause = DqsCountInit("KEYDATA_VIEW");
1706  DqsConditionInt(&count_clause, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1707  DqsConditionInt(&count_clause, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
1708  if (zone_id != -1) {
1709  DqsConditionInt(&count_clause, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1710  }
1711 
1712  status = DbIntQuery(DbHandle(), &active_count, count_clause);
1713  StrFree(count_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  if (active_count > 0) {
1721 
1722  snprintf(stringval, KSM_INT_STR_SIZE, "%d", zone_id);
1723  StrAppend(&where_clause, "select id from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1724  StrAppend(&where_clause, stringval);
1725  StrAppend(&where_clause, " and retire = (select min(retire) from KEYDATA_VIEW where state = 4 and keytype = 257 and zone_id = ");
1726  StrAppend(&where_clause, stringval);
1727  StrAppend(&where_clause, ")");
1728 
1729  /* Execute query and free up the query string */
1730  status = DbIntQuery(DbHandle(), &id, where_clause);
1731  StrFree(where_clause);
1732  if (status != 0)
1733  {
1734  log_msg(NULL, LOG_ERR, "Error: failed to find ID of key to retire\n");
1735  return status;
1736  }
1737  }
1738 
1739  /* First up we need to count how many DSs we will have */
1740  where = 0;
1741  sql = DqsCountInit("KEYDATA_VIEW");
1742  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1743  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1744  if (zone_id != -1) {
1745  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1746  }
1747  if (id != -1) {
1748  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1749  }
1750  DqsEnd(&sql);
1751 
1752  status = DbIntQuery(DbHandle(), &count, sql);
1753  DqsFree(sql);
1754 
1755  if (status != 0) {
1756  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1757  return status;
1758  }
1759 
1760  if (count == 0) {
1761  /* No KSKs in zone? */
1762  return status;
1763  }
1764 
1765  /* Allocate space for the list of key IDs */
1766  keyids = MemMalloc(count * sizeof(int));
1767 
1768  /* Get the list of IDs */
1769 
1770  where = 0;
1771  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1772  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, where++);
1773  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, where++);
1774  if (zone_id != -1) {
1775  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
1776  }
1777  if (id != -1) {
1778  DqsConditionInt(&sql, "ID", DQS_COMPARE_NE, id, where++);
1779  }
1780  DqsEnd(&sql);
1781 
1782  status = KsmKeyInitSql(&result, sql);
1783  DqsFree(sql);
1784 
1785  if (status == 0) {
1786  while (status == 0) {
1787  status = KsmKey(result, &data);
1788  if (status == 0) {
1789  keyids[i] = data.keypair_id;
1790  i++;
1791  }
1792  }
1793 
1794  /* Convert EOF status to success */
1795 
1796  if (status == -1) {
1797  status = 0;
1798  } else {
1799  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1800  StrFree(keyids);
1801  return status;
1802  }
1803 
1804  KsmKeyEnd(result);
1805 
1806  } else {
1807  /*status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));*/
1808  StrFree(keyids);
1809  return status;
1810  }
1811 
1812  /*
1813  * Now construct the "IN" statement listing the IDs of the keys we
1814  * are planning to change the state of.
1815  */
1816 
1817  StrAppend(&insql, "(");
1818  for (j = 0; j < i; ++j) {
1819  if (j != 0) {
1820  StrAppend(&insql, ",");
1821  }
1822  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
1823  StrAppend(&insql, buffer);
1824  }
1825  StrAppend(&insql, ")");
1826 
1827  StrFree(keyids);
1828 
1829  /* Indicate that the DS record should now be submitted */
1830  sql2 = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
1831  DqsConditionKeyword(&sql2, "ID", DQS_COMPARE_IN, insql, 0);
1832  DqsConditionInt(&sql2, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
1833  DqsEnd(&sql2);
1834 
1835  log_msg(NULL, LOG_INFO, "DS Record set has changed, the current set looks like:");
1836 
1837  status = KsmKeyInitSql(&result3, sql2);
1838  DqsFree(sql2);
1839  if (status == 0) {
1840  status = KsmKey(result3, &data3);
1841  while (status == 0) {
1842 
1843  /* Code to output the DNSKEY record (stolen from hsmutil) */
1844  key = hsm_find_key_by_id(NULL, data3.location);
1845 
1846  if (!key) {
1847  log_msg(NULL, LOG_ERR, "Key %s in DB but not repository.", data3.location);
1848  StrFree(insql);
1849  return status;
1850  }
1851 
1852  StrAppend(&ds_seen_buffer, ", ");
1853  StrAppend(&ds_seen_buffer, data3.location);
1854 
1855  sign_params = hsm_sign_params_new();
1856  sign_params->owner = ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, zone_name);
1857  sign_params->algorithm = data3.algorithm;
1858  sign_params->flags = LDNS_KEY_ZONE_KEY;
1859  sign_params->flags += LDNS_KEY_SEP_KEY;
1860  dnskey_rr = hsm_get_dnskey(NULL, key, sign_params);
1861 
1862  /* Set TTL if we can find it; else leave it as the default */
1863  /* We need a policy id */
1864  status = KsmPolicyIdFromZoneId(zone_id, &policy_id);
1865  if (status == 0) {
1866 
1867  /* Use this to get the TTL parameter value */
1868  status = KsmParameterValue(KSM_PAR_KSKTTL_STRING, KSM_PAR_KSKTTL_CAT, &rrttl, policy_id, &param_id);
1869  if (status == 0) {
1870  ldns_rr_set_ttl(dnskey_rr, rrttl);
1871  }
1872  }
1873 
1874  temp_char = ldns_rr2str(dnskey_rr);
1875  ldns_rr_free(dnskey_rr);
1876 
1877  /* Replace tab with white-space */
1878  for (i = 0; temp_char[i]; ++i) {
1879  if (temp_char[i] == '\t') {
1880  temp_char[i] = ' ';
1881  }
1882  }
1883  log_msg(NULL, LOG_INFO, "%s", temp_char);
1884 
1885  /* We need to strip off trailing comments before we send
1886  to any clients that might be listening */
1887  for (i = 0; temp_char[i]; ++i) {
1888  if (temp_char[i] == ';') {
1889  temp_char[i] = '\n';
1890  temp_char[i+1] = '\0';
1891  break;
1892  }
1893  }
1894  StrAppend(&ds_buffer, temp_char);
1895 
1896  /* Add the CKA_ID if asked */
1897  if (DSSubCKA_ID) {
1898  StrAppend(&ds_buffer, "; {cka_id = ");
1899  StrAppend(&ds_buffer, data3.location);
1900  StrAppend(&ds_buffer, "}");
1901  }
1902 
1903  StrFree(temp_char);
1904 
1905 /* StrAppend(&ds_buffer, "\n;KSK DS record (SHA1):\n");
1906  ds_sha1_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA1);
1907  temp_char = ldns_rr2str(ds_sha1_rr);
1908  StrAppend(&ds_buffer, temp_char);
1909  StrFree(temp_char);
1910 
1911  StrAppend(&ds_buffer, "\n;KSK DS record (SHA256):\n");
1912  ds_sha256_rr = ldns_key_rr2ds(dnskey_rr, LDNS_SHA256);
1913  temp_char = ldns_rr2str(ds_sha256_rr);
1914  StrAppend(&ds_buffer, temp_char);
1915  StrFree(temp_char);
1916 */
1917 
1918  hsm_sign_params_free(sign_params);
1919  hsm_key_free(key);
1920  status = KsmKey(result3, &data3);
1921  }
1922  /* Convert EOF status to success */
1923  if (status == -1) {
1924  status = 0;
1925  }
1926 
1927  KsmKeyEnd(result3);
1928  }
1929 
1930  if (DSSubmitCmd[0] != '\0') {
1931  /* First check that the command exists */
1932  if (stat(DSSubmitCmd, &stat_ret) != 0) {
1933  log_msg(NULL, LOG_WARNING, "Cannot stat file %s: %s", DSSubmitCmd, strerror(errno));
1934  }
1935  /* Then see if it is a regular file, then if usr, grp or all have execute set */
1936  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)) {
1937  log_msg(NULL, LOG_WARNING, "File %s is not executable", DSSubmitCmd);
1938  }
1939  else {
1940 
1941  /* send records to the configured command */
1942  fp = popen(DSSubmitCmd, "w");
1943  if (fp == NULL) {
1944  log_msg(NULL, LOG_ERR, "Failed to run command: %s: %s", DSSubmitCmd, strerror(errno));
1945  StrFree(insql);
1946  return -1;
1947  }
1948  bytes_written = fprintf(fp, "%s", ds_buffer);
1949  if (bytes_written < 0) {
1950  log_msg(NULL, LOG_ERR, "Failed to write to %s: %s", DSSubmitCmd, strerror(errno));
1951  (void)pclose(fp);
1952  return -1;
1953  }
1954 
1955  if (pclose(fp) == -1) {
1956  log_msg(NULL, LOG_ERR, "Failed to close %s: %s", DSSubmitCmd, strerror(errno));
1957  StrFree(ds_buffer);
1958  StrFree(ds_seen_buffer);
1959  StrFree(insql);
1960  return -1;
1961  }
1962  }
1963  }
1964 
1965  StrFree(ds_buffer);
1966 
1967  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);
1968 
1969  StrFree(ds_seen_buffer);
1970 
1971  StrFree(insql);
1972 
1973  return status;
1974 }
1975 
1977 {
1978  int result = 0;
1979  char *hsm_error_message = NULL;
1980 
1981  result = hsm_check_context(*ctx);
1982 
1983  /* If we didn't get HSM_OK then close and reopen HSM */
1984  if (result != HSM_OK) {
1985 
1986  if (*ctx) {
1987  hsm_destroy_context(*ctx);
1988  *ctx = NULL;
1989  }
1990 
1991  result = hsm_close();
1992 
1993  if (config->configfile != NULL) {
1994  result = hsm_open(config->configfile, hsm_check_pin);
1995  } else {
1996  result = hsm_open(OPENDNSSEC_CONFIG_FILE, hsm_check_pin);
1997  }
1998  if (result) {
1999  hsm_error_message = hsm_get_error(*ctx);
2000  if (hsm_error_message) {
2001  log_msg(config, LOG_ERR, hsm_error_message);
2002  free(hsm_error_message);
2003  } else {
2004  /* decode the error code ourselves
2005  TODO find if there is a better way to do this (and can all
2006  of these be returned? are there others?) */
2007  switch (result) {
2008  case HSM_ERROR:
2009  log_msg(config, LOG_ERR, "hsm_open() result: HSM error");
2010  break;
2011  case HSM_PIN_INCORRECT:
2012  log_msg(config, LOG_ERR, "hsm_open() result: incorrect PIN");
2013  break;
2014  case HSM_CONFIG_FILE_ERROR:
2015  log_msg(config, LOG_ERR, "hsm_open() result: config file error");
2016  break;
2017  case HSM_REPOSITORY_NOT_FOUND:
2018  log_msg(config, LOG_ERR, "hsm_open() result: repository not found");
2019  break;
2020  case HSM_NO_REPOSITORIES:
2021  log_msg(config, LOG_ERR, "hsm_open() result: no repositories");
2022  break;
2023  default:
2024  log_msg(config, LOG_ERR, "hsm_open() result: %d", result);
2025  }
2026  }
2027  unlink(config->pidfile);
2028  exit(1);
2029  }
2030  log_msg(config, LOG_INFO, "HSM reopened successfully.");
2031  *ctx = hsm_create_context();
2032  } else {
2033  log_msg(config, LOG_INFO, "HSM connection open.");
2034  }
2035 
2036 }
void DbFreeResult(DB_RESULT result)
int KsmPolicyInit(DB_RESULT *handle, const char *name)
Definition: ksm_policy.c:69
unsigned char * schema
Definition: daemon.h:108
char name[KSM_NAME_LENGTH]
Definition: ksm.h:247
unsigned long sm_capacity
Definition: ksm.h:214
bool once
Definition: daemon.h:90
sqlite3 * DB_HANDLE
Definition: database.h:77
#define KSM_TYPE_ZSK
Definition: ksm.h:362
void kaspConnect(DAEMONCONFIG *config, DB_HANDLE *handle)
Definition: kaspaccess.c:127
#define StrFree(x)
Definition: string_util.h:66
void server_main(DAEMONCONFIG *config)
Definition: enforcer.c:81
char * pidfile
Definition: daemon.h:92
char * DSSubmitCmd
Definition: daemon.h:115
int DbFlavour(void)
int rfc5011
Definition: ksm.h:218
int DbFetchRow(DB_RESULT result, DB_ROW *row)
#define KSM_STATE_DEAD
Definition: ksm.h:377
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:117
#define KSM_STATE_ACTIVE
Definition: ksm.h:373
char location[KSM_NAME_LENGTH]
Definition: ksm.h:112
int KsmKeyCountQueue(int keytype, int *count, int zone_id)
Definition: ksm_key.c:664
KSM_POLICY * KsmPolicyAlloc()
Definition: ksm_policy.c:959
#define KSM_STATE_READY
Definition: ksm.h:371
KSM_COMMON_KEY_POLICY * keys
Definition: ksm.h:252
int state
Definition: ksm.h:102
int KsmParameterCollection(KSM_PARCOLL *data, int policy_id)
void DusFree(char *sql)
Definition: du_string.c:223
int kaspTryConnect(DAEMONCONFIG *config, DB_HANDLE *handle)
Definition: kaspaccess.c:141
KSM_KEY_POLICY * zsk
Definition: ksm.h:254
void check_hsm_connection(hsm_ctx_t **ctx, DAEMONCONFIG *config)
Definition: enforcer.c:1976
int bits
Definition: ksm.h:210
uint16_t interval
Definition: daemon.h:110
void kaspDisconnect(DB_HANDLE *handle)
Definition: kaspaccess.c:155
void DqsConditionKeyword(char **query, const char *field, DQS_COMPARISON compare, const char *value, int index)
Definition: dq_string.c:251
int KsmKeyPairCreate(int policy_id, const char *HSMKeyID, int smID, int size, int alg, const char *generate, DB_ID *id)
Definition: ksm_key.c:84
int KsmZoneCount(DB_RESULT handle, int *count)
Definition: ksm_zone.c:206
char sm_name[KSM_NAME_LENGTH]
Definition: ksm.h:213
int KsmPolicyUpdateSalt(KSM_POLICY *policy)
Definition: ksm_policy.c:501
int shared_keys
Definition: ksm.h:258
int KsmPolicyRead(KSM_POLICY *policy)
Definition: ksm_policy.c:232
int rolloverNotify
Definition: daemon.h:114
char * configfile
Definition: daemon.h:104
void DqsFree(char *query)
Definition: dq_string.c:320
#define KSM_STATE_KEYPUBLISH
Definition: ksm.h:385
void DdsFree(char *query)
Definition: dd_string.c:115
int algorithm
Definition: ksm.h:209
#define MemFree(ptr)
Definition: memory.h:48
int read_zonelist_filename(const char *filename, char **zone_list_filename)
Definition: enforcer.c:1385
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:90
int KsmCheckNextRollover(int keytype, int zone_id, char **datetime)
Definition: ksm_list.c:457
DB_HANDLE DbHandle(void)
int DbString(DB_ROW row, int field_index, char **result)
char * StrStrdup(const char *string)
Definition: string_util.c:124
void DqsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dq_string.c:224
char salt[KSM_SALT_LENGTH]
Definition: ksm.h:196
void DdsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dd_string.c:88
int KsmPolicyIdFromZoneId(int zone_id, int *policy_id)
Definition: ksm_policy.c:866
char * DdsInit(const char *table)
Definition: dd_string.c:60
char * DtParseDateTimeString(const char *string)
Definition: datetime.c:614
#define KSM_STATE_DSPUBLISH
Definition: ksm.h:381
KSM_DENIAL_POLICY * denial
Definition: ksm.h:251
int KsmZoneIdFromName(const char *zone_name, int *zone_id)
Definition: ksm_zone.c:247
KSM_KEY_POLICY * ksk
Definition: ksm.h:253
int do_communication(DAEMONCONFIG *config, KSM_POLICY *policy, bool all_policies)
Definition: enforcer.c:586
unsigned long DB_ID
Definition: database.h:78
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 revoke
Definition: ksm.h:129
int manualKeyGeneration
Definition: daemon.h:113
#define SQLITE_DB
Definition: database.h:46
int do_keygen(DAEMONCONFIG *config, KSM_POLICY *policy, hsm_ctx_t *ctx)
Definition: enforcer.c:347
#define DB_KEYDATA_FIELDS
Definition: db_fields.h:56
const char * DbErrmsg(DB_HANDLE handle)
void KsmPolicyFree(KSM_POLICY *policy)
Definition: ksm_policy.c:997
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:249
int ReadConfig(DAEMONCONFIG *config, int verbose)
Definition: daemon_util.c:717
int term
Definition: daemon.h:101
int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
Definition: ksm_key.c:571
void kaspSetPolicyDefaults(KSM_POLICY *policy, char *name)
Definition: kaspaccess.c:46
const char * KsmKeywordSerialValueToName(int value)
Definition: ksm_keyword.c:252
int rfc5011
Definition: ksm.h:128
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:1710
#define KSM_SQL_SIZE
Definition: ksm.h:63
int release_lite_lock(FILE *lock_fd)
Definition: daemon_util.c:1203
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:76
int server_init(DAEMONCONFIG *config)
Definition: enforcer.c:62
int algorithm
Definition: ksm.h:104
void DusEnd(char **sql)
Definition: du_string.c:202
int DbIntQuery(DB_HANDLE handle, int *value, const char *query)
#define KSM_FLAG_REVOKE
Definition: ksm.h:365
#define KSM_PAR_KSKTTL_CAT
Definition: ksm.h:448
#define KSM_STATE_RETIRE
Definition: ksm.h:375
#define KSM_STATE_PUBLISH
Definition: ksm.h:369
int DbDateDiff(const char *start, int delta, int sign, char *buffer, size_t buflen)
void KsmParameterCollectionCache(int enable)
char * policy
Definition: daemon.h:117
DB_ID keypair_id
Definition: ksm.h:101
int sm
Definition: ksm.h:212
int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
Definition: ksm_key.c:881
int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, int rfc5011, const char *time, const char *retTime, DB_ID *id)
Definition: ksm_key.c:141
int get_lite_lock(char *lock_filename, FILE *lock_fd)
Definition: daemon_util.c:1169
DAEMONCONFIG config
Definition: daemon.c:71
#define KSM_INT_STR_SIZE
Definition: ksm.h:64
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:1254
int id
Definition: ksm.h:246
int ttl
Definition: ksm.h:217
int writepid(DAEMONCONFIG *config)
Definition: daemon_util.c:468
#define KSM_PAR_KSKTTL_STRING
Definition: ksm.h:447
int require_backup
Definition: ksm.h:215
void log_msg(DAEMONCONFIG *config, int priority, const char *format,...)
Definition: daemon_util.c:294
int KsmRequestPendingRetireCount(int keytype, const char *datetime, KSM_PARCOLL *parameters, int *count, int zone_id, int interval)
Definition: ksm_request.c:1507
#define KSM_STATE_DSSUB
Definition: ksm.h:379
int KsmZoneCountInit(DB_RESULT *handle, int id)
Definition: ksm_zone.c:107
void DdsEnd(char **query)
Definition: dd_string.c:109
#define KSM_TYPE_KSK
Definition: ksm.h:360
int DbInt(DB_ROW row, int field_index, int *value)
void * MemMalloc(size_t size)
Definition: memory.c:57
int algorithm
Definition: ksm.h:191
#define KSM_STATE_DSREADY
Definition: ksm.h:383
int NewDSSet(int zone_id, const char *zone_name, const char *DSSubmitCmd, int DSSubCKA_ID)
Definition: enforcer.c:1652
int rollover_scheme
Definition: ksm.h:222
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:478
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:95
int iteration
Definition: ksm.h:192
#define KSM_STATE_GENERATE
Definition: ksm.h:367
void DqsEnd(char **query)
Definition: dq_string.c:299
int kaspReadPolicy(KSM_POLICY *policy)
Definition: kaspaccess.c:164
int DtDateDiff(const char *date1, const char *date2, int *result)
Definition: datetime.c:825
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:743
int do_purge(int interval, int policy_id)
Definition: enforcer.c:1481
int DSSubCKA_ID
Definition: daemon.h:116
KSM_SIGNATURE_POLICY * signature
Definition: ksm.h:250
int commKeyConfig(void *context, KSM_KEYDATA *key_data)
Definition: enforcer.c:1189
void DbStringFree(char *string)