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