OpenDNSSEC-enforcer  1.3.9
ksm_request.c
Go to the documentation of this file.
1 /*
2  * $Id: ksm_request.c 4489 2011-02-17 10:17:39Z rb $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*+
30  * ksm_request.c - Handle Request Keys Processing
31  *
32  * Description:
33  * The REQUEST command asks KSM to list the keys to be included in the
34  * zone when it is next signed. It can optionally force a rollover by
35  * marking the active key as retired.
36 -*/
37 
38 #include <assert.h>
39 #include <stdio.h>
40 #include <string.h>
41 
42 #include "ksm/database.h"
43 #include "ksm/database_statement.h"
44 #include "ksm/db_fields.h"
45 #include "ksm/debug.h"
46 #include "ksm/ksm.h"
47 #include "ksm/kmedef.h"
48 #include "ksm/ksmdef.h"
49 #include "ksm/message.h"
50 #include "ksm/memory.h"
51 #include "ksm/string_util.h"
52 #include "ksm/string_util2.h"
53 
54 /* TODO The nomenclature needs to be updated to agree with that in the timing draft */
55 
56 /*+
57  * KsmRequestKeys - Request Keys for Output
58  *
59  * Description:
60  * Updates the key times and then calls KsmRequestKeysByType to process
61  * keys of the type chosen by the keytype argument.
62  *
63  * Arguments:
64  * int keytype
65  * Key type for which the request should happen.
66  *
67  * KSM_TYPE_KSK KSKs
68  * KSM_TYPE_ZSK ZSKs
69  * Other Both KSK and ZSK
70  *
71  * int rollover
72  * 1 to force a rollover, 0 to ignore
73  *
74  * const char* datetime
75  * Time at which the request is issued. Comparisons for key
76  * expirations etc. will be against this time.
77  *
78  * KSM_REQUEST_CALLBACK callback
79  * Callback function called for every key that will be issued.
80  *
81  * void* context
82  * Context argument passed uninterpreted to the callback function.
83  *
84  * int policy_id
85  * ID of policy that we are looking at
86  *
87  * int zone_id
88  * ID of zone that we are looking at (-1 == all zones)
89  *
90  * int run_interval
91  * how frequently do we run?
92  *
93  * int* NewDS
94  * were new DS records needed?
95 -*/
96 
97 int KsmRequestKeys(int keytype, int rollover, const char* datetime,
98  KSM_REQUEST_CALLBACK callback, void* context, int policy_id, int zone_id,
99  int run_interval, int* NewDS)
100 {
101  int status; /* Status return */
102 
103  /* Start the transaction */
104  status = DbBeginTransaction();
105  if (status != 0) {
106  /* Something went wrong */
107 
109  return status;
110  }
111 
112  /* Update the estimated times of state change */
113  status = KsmUpdate(policy_id, zone_id);
114  if (status == 0) {
115 
116  /* Process all key types */
117 
118  if ((keytype == KSM_TYPE_KSK) || (keytype == KSM_TYPE_ZSK)) {
119  status = KsmRequestKeysByType(keytype, rollover, datetime,
120  callback, context, policy_id, zone_id, run_interval, NewDS);
121 
122  if (status != 0) {
123  DbRollback();
124  return status;
125  }
126  }
127  else {
128  status = KsmRequestKeysByType(KSM_TYPE_KSK, rollover, datetime,
129  callback, context, policy_id, zone_id, run_interval, NewDS);
130  if (status != 0) {
131  DbRollback();
132  return status;
133  }
134 
135  status = KsmRequestKeysByType(KSM_TYPE_ZSK, rollover, datetime,
136  callback, context, policy_id, zone_id, run_interval, NewDS);
137  if (status != 0) {
138  DbRollback();
139  return status;
140  }
141  }
142 
143  /*
144  * Finally, update the key times again, in case any keys were
145  * moved between states.
146  */
147 
148  status = KsmUpdate(policy_id, zone_id);
149  if (status != 0) {
150  DbRollback();
151  return status;
152  }
153  else
154  {
155  /* Everything worked by the looks of it */
156  DbCommit();
157  }
158  }
159  else
160  {
161  /* Whatever happened, it was not good */
162  DbRollback();
163  }
164 
165  return status;
166 }
167 
168 
169 /*+
170  * KsmRequestKeysByType - Request Keys for Output
171  *
172  * Description:
173  * Does REQUEST KEYS processing for keys of a given type.
174  *
175  * Arguments:
176  * int keytype
177  * Key type for which the request should happen.
178  *
179  * KSM_TYPE_KSK KSKs
180  * KSM_TYPE_ZSK ZSKs
181  *
182  * int rollover
183  * 1 to force a rollover, 0 to ignore
184  *
185  * const char* datetime
186  * Time to insert into database.
187  *
188  * KSM_REQUEST_CALLBACK callback
189  * Callback function called for every key that will be issued.
190  *
191  * void* context
192  * Context argument passed uninterpreted to the callback function.
193  *
194  * int policy_id
195  * ID of policy that we are looking at
196  *
197  * int zone_id
198  * ID of zone that we are looking at
199  *
200  * int run_interval
201  * how frequently do we run?
202  *
203  * int* NewDS
204  * were new DS records needed?
205  *
206  * Returns:
207  * int
208  * Status return. 0 = Success, other = error (in which case a message
209  * will have been output).
210 -*/
211 
212 int KsmRequestKeysByType(int keytype, int rollover, const char* datetime,
213  KSM_REQUEST_CALLBACK callback, void* context, int policy_id, int zone_id,
214  int run_interval, int* NewDS)
215 {
216  int active; /* Number of active keys to be retired */
217  KSM_PARCOLL collection; /* Parameters collection */
218  int ready; /* Number of keys in the "ready" state */
219  int first_pass = 0; /* Indicates if this zone has been published before */
220  int status; /* Status return */
221  char* zone_name = NULL; /* For rollover message, if needed */
222  int manual_rollover = 0; /* Flag specific to keytype */
223 
224  /* Check that we have a valid key type */
225 
226  if ((keytype != KSM_TYPE_KSK) && (keytype != KSM_TYPE_ZSK)) {
227  status = MsgLog(KME_UNKEYTYPE, keytype);
228  return status;
229  }
230 
232  (keytype == KSM_TYPE_KSK) ? "key" : "zone");
233 
234  /* Get list of parameters */
235 
236  status = KsmParameterCollection(&collection, policy_id);
237  if (status != 0) {
238  return status;
239  }
240 
241  if (keytype == KSM_TYPE_KSK) {
242  manual_rollover = collection.kskmanroll;
243  }
244  else if (keytype == KSM_TYPE_ZSK) {
245  manual_rollover = collection.zskmanroll;
246  }
247 
248  /* Check to see if this zone has been published before */
249  status = KsmRequestCheckFirstPass(keytype, &first_pass, zone_id);
250  if (status != 0) {
251  return status;
252  }
253 
254  /*
255  * Step 0: If rolling over the key, set the expected retirement date of
256  * active keys to the given date/time.
257  */
258 
259  if (rollover) {
260  status = KsmRequestSetActiveExpectedRetire(keytype, datetime, zone_id);
261  if (status != 0) {
262  return status;
263  }
264  } else {
265  /* Check for the compromised flag on the currently active key;
266  if set then force rollover to 1 (could set manual_rollover to 0)
267  NOTE: because of where this is called from we can not overwrite
268  the incoming rollover flag if set */
269  status = KsmRequestCheckCompromisedFlag(keytype, zone_id, &rollover);
270  if (status != 0) {
271  return status;
272  }
273  }
274  /*
275  * Step 0a: Complete Key rollover of standbykeys in KEYPUBLISH state
276  * if we are after their active time, move them into the active state
277  */
278  if (keytype == KSM_TYPE_KSK) {
279  status = KsmRequestChangeStateKeyPublishActive(datetime, zone_id, policy_id, NewDS);
280  if (status != 0) {
281  return status;
282  }
283 
284  if (*NewDS == 1) {
285  /* Standby Key has become active, retire the old key */
286  status = KsmRequestChangeStateActiveRetire(keytype, datetime, zone_id, policy_id);
287  if (status != 0) {
288  StrFree(zone_name);
289  return status;
290  }
291  *NewDS = 0; /* We were naughty when we used this flag, clean up */
292  /* DS set won't change until the old active key moves to dead */
293  }
294  }
295 
296 
297  /*
298  * Step 1. For each retired key, mark it as dead if it past the given
299  * time.
300  */
301 
302  status = KsmRequestChangeStateRetireDead(keytype, datetime, zone_id, policy_id, collection.kskroll, NewDS);
303  if (status != 0) {
304  return status;
305  }
306 
307  /*
308  * Step 2. For each key in the published state, set it ready if it has
309  * been in the zone long enough.
310  */
311 
312  if (keytype == KSM_TYPE_ZSK ||
313  collection.kskroll == KSM_ROLL_DNSKEY ||
314  first_pass == 1) {
315  status = KsmRequestChangeStatePublishReady(keytype, datetime, zone_id, policy_id, NewDS);
316  if (status != 0) {
317  return status;
318  }
319  }
320 
321  /*
322  * Step 2a. For each key in the dspublished state, set it dsready if it has
323  * been in the zone long enough.
324  */
325 
326  if (keytype == KSM_TYPE_KSK) {
327  status = KsmRequestChangeStateDSPublishDSReady(keytype, datetime, zone_id, policy_id);
328  if (status != 0) {
329  return status;
330  }
331  }
332 
333  /*
334  * Step 3a. make sure that we have enough standby KSKs
335  * Doing this before 3.
336  */
337 
338  if (keytype == KSM_TYPE_KSK) {
339  status = KsmRequestChangeStateGenerateDSSubConditional(keytype, datetime, &collection, zone_id, NewDS);
340 
341  /* Reset this flag; TODO is this correct? */
342  if (first_pass == 1) {
343  *NewDS = 0;
344  }
345  if (status != 0) {
346  return status;
347  }
348  }
349 
350  /*
351  * Step 3. We are within the appropriate interval of the retirement
352  * of the active key, move keys from the generate state into the
353  * publish state.
354  */
355 
356  status = KsmRequestChangeStateGeneratePublishConditional(keytype, datetime, &collection, zone_id, run_interval);
357  if (status != 0) {
358  return status;
359  }
360 
361  /*
362  * Step 4. If there is an active key and the date on which this procedure
363  * is run is earlier than the retire time of that key, exit the procedure.
364  */
365 
366  status = KsmRequestCheckActiveKey(keytype, datetime, &active, zone_id);
367  if (status != 0) {
368  return status;
369  }
370 
371  /*
372  * Step 5: Unless we are forcing a rollover, if there are some keys that
373  * will be active after the cut-off, end the modification of key states and
374  * times now. Otherwise continue.
375  *
376  * Note that we don't return if keys are active - we still need to issue
377  * the keys.
378  */
379 
380  if ((active <= 0) || (rollover)) {
381 
382  /* Get some info that we need for logging later */
383  status = KsmZoneNameFromId(zone_id, &zone_name);
384  if (status != 0) {
385  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
386  if (zone_name != NULL) {
387  StrFree(zone_name);
388  }
389  return(status);
390  }
391 
392  /*
393  * Step 6. If there are keys to be made active, count the number of keys
394  * in the "READY" state.
395  */
396 
397  status = KsmRequestCountReadyKey(keytype, datetime, &ready, zone_id);
398  if (status != 0) {
399  StrFree(zone_name);
400  return status;
401  }
402 
403  /*
404  * Step 7. We can only promote a key if there is at least one key in the
405  * READY state. Otherwise, just issue what we have.
406  */
407 
408  if (ready <= 0) {
409 
410  /*
411  * If this is the first pass for this zone. Then we can promote a key
412  * to active from published
413  * NB: A consequence of this is that these keys will have no "ready"
414  * time as they are never in the "ready" state.
415  */
416 
417  if (first_pass == 1) {
418  /* We have to wait until the KSK is ready before we can
419  * publish the DS record */
420  if (keytype == KSM_TYPE_KSK) {
421  /* status = KsmRequestChangeStateN(keytype, datetime, 1,
422  KSM_STATE_READY, KSM_STATE_ACTIVE, zone_id);*/
423  } else {
424  (void) MsgLog(KME_PROM_PUB, "ZSK");
425  status = KsmRequestChangeStateN(keytype, datetime, 1,
427  }
428 
429  if (status != 0) {
430  StrFree(zone_name);
431  return status;
432  }
433  }
434  else {
435  /* Move standby key from DSready to KEYPUBLISH if we can */
436  if (keytype == KSM_TYPE_KSK) {
437  status = KsmRequestChangeStateDSReadyKeyPublish(datetime, zone_id, policy_id);
438  if (status != 0) {
439  return status;
440  }
441  }
442 
443  (void) MsgLog(KME_NOREADYKEY, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name);
444  /* TODO return here? */
445  }
446  }
447  else if (manual_rollover == 1 && rollover == 0) {
448  (void) MsgLog(KME_MAN_ROLL_REQUIRED, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name);
449  }
450  /* TODO I think that this is no longer true... */
451  /* Check where we need this to happen */
452  else if (keytype == KSM_TYPE_KSK) {
453  /* A rollover should be occuring... For KSKs we just prompt for
454  * the user to submit their DS record
455  * TODO Include the keytag or cka-id in the message
456  * TODO Do we still need this? */
457  (void) MsgLog(KME_DS_SUBMISSION, zone_name);
458  }
459  else {
460 
461  /* Step 8. Make a key active. */
462  status = KsmRequestChangeStateReadyActive(keytype, datetime, 1, zone_id);
463  /*
464  * If we didn't complete due to non-backed up keys then skip the
465  * retire step; otherwise carry on.
466  */
467  if (status != KME_BACK_FATAL) {
468  if (status != 0) {
469  StrFree(zone_name);
470  return status;
471  }
472 
473  /* Step 9. ... and retire old active keys */
474  status = KsmRequestChangeStateActiveRetire(keytype, datetime, zone_id, policy_id);
475  if (status != 0) {
476  StrFree(zone_name);
477  return status;
478  }
479 
480  /* Log that a rollover has happened */
481  (void) MsgLog(KME_ROLL_ZONE, (keytype == KSM_TYPE_KSK ? "KSK" : "ZSK"), zone_name);
482  }
483  }
484  StrFree(zone_name);
485  }
486 
487  /* Step 10. Issue the keys */
488 
489  status = KsmRequestIssueKeys(keytype, callback, context, zone_id);
490 
491  return status;
492 }
493 
494 
495 
496 /*+
497  * KsmRequestSetActiveExpectedRetire - Set Expected Retire Date
498  *
499  * Description:
500  * Sets the expected retire date for active keys to the date specified.
501  * Note that this does change not the state from active - it only changes
502  * the expected retire date.
503  *
504  * Arguments:
505  * int keytype
506  * Type of keys being changed.
507  *
508  * const char* datetime
509  * Date/time for which the calculation is being done. This can be
510  * the string "NOW()".
511  *
512  * int zone_id
513  * Zone we are looking at (-1 == all zones)
514  *
515  * Returns:
516  * int
517  * Status return. 0 => success, Other => failure, in which case an
518  * error message will have been output.
519 -*/
520 
521 int KsmRequestSetActiveExpectedRetire(int keytype, const char* datetime, int zone_id)
522 {
523  int count = 0; /* Count of keys whose date will be set */
524  char* sql = NULL; /* For creating the SQL command */
525  int status = 0; /* Status return */
526  int where = 0; /* For the SQL selection */
527  int i = 0; /* A counter */
528  int j = 0; /* Another counter */
529  char* insql = NULL; /* SQL "IN" clause */
530  int* keyids; /* List of IDs of keys to promote */
531  DB_RESULT result; /* List result set */
532  KSM_KEYDATA data; /* Data for this key */
533  char buffer[32]; /* For integer conversion */
534 
535  /* Count how many keys will have the retire date set */
536 
537  sql = DqsCountInit("KEYDATA_VIEW");
538  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++);
539  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
540  if (zone_id != -1) {
541  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
542  }
543  DqsEnd(&sql);
544 
545  status = DbIntQuery(DbHandle(), &count, sql);
546  DqsFree(sql);
547 
548  if (status != 0) {
549  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
550  return status;
551  }
552 
553  if (count == 0) {
554  /* Nothing to do NO ACTIVE KEYS! */
555  return status;
556  }
557 
558  /* Allocate space for the list of key IDs */
559  keyids = MemMalloc(count * sizeof(int));
560 
561  /* Get the list of IDs */
562 
563  where = 0;
564  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
565  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++);
566  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, where++);
567  if (zone_id != -1) {
568  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
569  }
570  DqsEnd(&sql);
571 
572  status = KsmKeyInitSql(&result, sql);
573  DqsFree(sql);
574 
575  if (status == 0) {
576  while (status == 0) {
577  status = KsmKey(result, &data);
578  if (status == 0) {
579  keyids[i] = data.keypair_id;
580  i++;
581  }
582  }
583 
584  /* Convert EOF status to success */
585 
586  if (status == -1) {
587  status = 0;
588  } else {
589  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
590  StrFree(keyids);
591  return status;
592  }
593 
594  KsmKeyEnd(result);
595 
596  } else {
597  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
598  StrFree(keyids);
599  return status;
600  }
601 
602  /*
603  * Now construct the "IN" statement listing the IDs of the keys we
604  * are planning to change the state of.
605  */
606 
607  StrAppend(&insql, "(");
608  for (j = 0; j < i; ++j) {
609  if (j != 0) {
610  StrAppend(&insql, ",");
611  }
612  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
613  StrAppend(&insql, buffer);
614  }
615  StrAppend(&insql, ")");
616 
617  /*
618  * Update the keys. This is done after a status check, as the debug
619  * code may have hit a database error, in which case we won't query the
620  * database again. ("status" is initialized to success in case the debug
621  * code is not executed.)
622  */
623 
624  sql = DusInit("keypairs");
625  DusSetInt(&sql, "fixedDate", 1, 0);
626  DusSetInt(&sql, "compromisedflag", 1, 1);
627 
628  DusConditionKeyword(&sql, "ID", DQS_COMPARE_IN, insql, 0);
629  DusEnd(&sql);
630 
631  status = DbExecuteSqlNoResult(DbHandle(), sql);
632  DusFree(sql);
633 
634  /* Report any errors */
635  if (status != 0) {
636  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
637  }
638 
639  sql = DusInit("dnsseckeys");
640  DusSetString(&sql, "RETIRE", datetime, 0);
641 
642  DusConditionKeyword(&sql, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
643  /* NO ZONE_ID !!! We want to retire ALL instances of this key */
644  StrFree(insql);
645  DusEnd(&sql);
646 
647  status = DbExecuteSqlNoResult(DbHandle(), sql);
648  DusFree(sql);
649 
650  /* Report any errors */
651  if (status != 0) {
652  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
653  }
654 
655  StrFree(keyids);
656 
657  return status;
658 }
659 
660 
661 
662 /*+
663  * KsmRequestChangeStatePublishReady - Change State from PUBLISH to READY
664  * KsmRequestChangeStateActiveRetire - Change State from ACTIVE to RETIRE
665  * KsmRequestChangeStateRetireDead - Change State from RETIRE to DEAD
666  *
667  * Description:
668  * Changes the state of keys of a particular type in the given zone
669  * between two states.
670  *
671  * Arguments:
672  * int keytype
673  * Type of keys being changed.
674  *
675  * const char* datetime
676  * Date/time for which the calculation is being done. This ancan be
677  * the string "NOW()".
678  *
679  * int zone_id
680  * ID of zone that we are looking at (-1 == all zones)
681  *
682  * Returns:
683  * int
684  * Status return. 0 => success, Other => failure, in which case an
685  * error message will have been output.
686 -*/
687 
688 int KsmRequestChangeStatePublishReady(int keytype, const char* datetime, int zone_id, int policy_id, int* NewDS)
689 {
690  return KsmRequestChangeState(keytype, datetime,
691  KSM_STATE_PUBLISH, KSM_STATE_READY, zone_id, policy_id, -1, NewDS);
692 }
693 
694 int KsmRequestChangeStateDSPublishDSReady(int keytype, const char* datetime, int zone_id, int policy_id)
695 {
696  int* dummy = NULL;
697  return KsmRequestChangeState(keytype, datetime,
698  KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY, zone_id, policy_id, -1, dummy);
699 }
700 
701 int KsmRequestChangeStateDSReadyKeyPublish(const char* datetime, int zone_id, int policy_id)
702 {
703  int* dummy = NULL;
704  return KsmRequestChangeState(KSM_TYPE_KSK, datetime,
705  KSM_STATE_DSREADY, KSM_STATE_KEYPUBLISH, zone_id, policy_id, -1, dummy);
706 }
707 
708 int KsmRequestChangeStateKeyPublishActive(const char* datetime, int zone_id, int policy_id, int* NewDS)
709 {
710  return KsmRequestChangeState(KSM_TYPE_KSK, datetime,
711  KSM_STATE_KEYPUBLISH, KSM_STATE_ACTIVE, zone_id, policy_id, -1, NewDS);
712 }
713 
714 int KsmRequestChangeStateActiveRetire(int keytype, const char* datetime, int zone_id, int policy_id)
715 {
716  int* dummy = NULL;
717  return KsmRequestChangeState(keytype, datetime,
718  KSM_STATE_ACTIVE, KSM_STATE_RETIRE, zone_id, policy_id, -1, dummy);
719 }
720 
721 int KsmRequestChangeStateRetireDead(int keytype, const char* datetime, int zone_id, int policy_id, int rollover_scheme, int* NewDS)
722 {
723  return KsmRequestChangeState(keytype, datetime,
724  KSM_STATE_RETIRE, KSM_STATE_DEAD, zone_id, policy_id, rollover_scheme, NewDS);
725 }
726 
727 
728 
729 /*+
730  * KsmRequestChangeState - Change State of a Key
731  *
732  * Description:
733  * Changes the state of a key between two states if the estimated time of
734  * entering the target state is equal to or earlier than the given time.
735  * The time of entering the state is updated to the given time as well.
736  *
737  * Arguments:
738  * int keytype
739  * Type of keys being changed.
740  *
741  * const char* datetime
742  * Date/time for which the calculation is being done. This can be
743  * the string "NOW()".
744  *
745  * int src_state
746  * ID of the state that the key is moving from.
747  *
748  * int dst_state
749  * ID of the state that the key is moving to.
750  *
751  * int zone_id
752  * ID of zone that we are looking at (-1 == all zones)
753  *
754  * int policy_id
755  * ID of the policy that we are looking at
756  *
757  * int rollover_scheme
758  * what KSK rollover scheme are we using
759  *
760  * Returns:
761  * int
762  * Status return. 0 => success, Other => failure, in which case an
763  * error message will have been output.
764 -*/
765 
766 int KsmRequestChangeState(int keytype, const char* datetime,
767  int src_state, int dst_state, int zone_id, int policy_id,
768  int rollover_scheme, int* NewDS)
769 {
770  int where = 0; /* for the SELECT statement */
771  char* dst_col = NULL; /* Destination column */
772  int set = 0; /* For UPDATE */
773  char* sql = NULL; /* SQL statement (when verifying) */
774  int status = 0; /* Status return */
775  int count = 0; /* How many keys fit our select? */
776  int i = 0; /* A counter */
777  int j = 0; /* Another counter */
778  char* insql = NULL; /* SQL "IN" clause */
779  int* keyids; /* List of IDs of keys to promote */
780  DB_RESULT result; /* List result set */
781  KSM_KEYDATA data; /* Data for this key */
782  char buffer[32]; /* For integer conversion */
783  char* zone_name = NULL; /* For DS removal message, if needed */
784 
785  /* Unused parameter */
786  (void)policy_id;
787 
788  /* Create the destination column name */
789  if (dst_state == KSM_STATE_DSREADY) {
791  } else if (dst_state == KSM_STATE_KEYPUBLISH) {
793  } else {
794  dst_col = StrStrdup(KsmKeywordStateValueToName(dst_state));
795  }
796  (void) StrToUpper(dst_col);
797 
798  /* First up we need to count how many keys will move */
799  sql = DqsCountInit("KEYDATA_VIEW");
800  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++);
801  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, src_state, where++);
802  if (zone_id != -1) {
803  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
804  }
805  DqsConditionString(&sql, dst_col, DQS_COMPARE_LE, datetime, where++);
806  DqsEnd(&sql);
807 
808  status = DbIntQuery(DbHandle(), &count, sql);
809  DqsFree(sql);
810 
811  if (status != 0) {
812  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
813  StrFree(dst_col);
814  return status;
815  }
816 
817  if (count == 0) {
818  /* Nothing to do */
819  StrFree(dst_col);
820  return status;
821  }
822 
823  /* Allocate space for the list of key IDs */
824  keyids = MemMalloc(count * sizeof(int));
825 
826  /* Get the list of IDs */
827 
828  where = 0;
829  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
830  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, where++);
831  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, src_state, where++);
832  if (zone_id != -1) {
833  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, where++);
834  }
835  DqsConditionString(&sql, dst_col, DQS_COMPARE_LE, datetime, where++);
836  DqsEnd(&sql);
837 
838  status = KsmKeyInitSql(&result, sql);
839  DqsFree(sql);
840 
841  if (status == 0) {
842  while (status == 0) {
843  status = KsmKey(result, &data);
844  if (status == 0) {
845  keyids[i] = data.keypair_id;
846  i++;
847  }
848  }
849 
850  /* Convert EOF status to success */
851 
852  if (status == -1) {
853  status = 0;
854  } else {
855  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
856  StrFree(dst_col);
857  StrFree(keyids);
858  return status;
859  }
860 
861  KsmKeyEnd(result);
862 
863  } else {
864  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
865  StrFree(dst_col);
866  StrFree(keyids);
867  return status;
868  }
869 
870  /* Notify progress if debugging */
871 
873  KsmKeywordStateValueToName(src_state),
874  KsmKeywordStateValueToName(dst_state));
875 
876  /*
877  * Now construct the "IN" statement listing the IDs of the keys we
878  * are planning to change the state of.
879  */
880 
881  StrAppend(&insql, "(");
882  for (j = 0; j < i; ++j) {
883  if (j != 0) {
884  StrAppend(&insql, ",");
885  }
886  snprintf(buffer, sizeof(buffer), "%d", keyids[j]);
887  StrAppend(&insql, buffer);
888  }
889  StrAppend(&insql, ")");
890 
891  StrFree(keyids);
892 
893  /*
894  * Update the keys. This is done after a status check, as the debug
895  * code may have hit a database error, in which case we won't query the
896  * database again. ("status" is initialized to success in case the debug
897  * code is not executed.)
898  */
899 
900  sql = DusInit("dnsseckeys");
901  DusSetInt(&sql, "STATE", dst_state, set++);
902  DusSetString(&sql, dst_col, datetime, set++);
903 
904  DusConditionKeyword(&sql, "KEYPAIR_ID", DQS_COMPARE_IN, insql, 0);
905  DusConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, 1);
906  DusEnd(&sql);
907  StrFree(dst_col);
908 
909  status = DbExecuteSqlNoResult(DbHandle(), sql);
910  DusFree(sql);
911 
912  /* Report any errors */
913  if (status != 0) {
914  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
915  }
916 
917  /* See if we need to log a message about the DS records */
918  if (keytype == KSM_TYPE_KSK && ((dst_state == KSM_STATE_DEAD && rollover_scheme == KSM_ROLL_DS) || dst_state == KSM_STATE_READY))
919  {
920  /* Set our flag */
921  *NewDS = 1;
922 
923  /* Get common info we need for either message */
924  status = KsmZoneNameFromId(zone_id, &zone_name);
925  if (status != 0) {
926  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
927  if (zone_name != NULL) {
928  StrFree(insql);
929  StrFree(zone_name);
930  }
931  return(status);
932  }
933 
934  /* If we moved a KSK from retire to dead then the DS can be removed */
935  if (dst_state == KSM_STATE_DEAD && rollover_scheme == KSM_ROLL_DS) {
936  (void) MsgLog(KME_DS_REM_ZONE, zone_name);
937  }
938  else if (dst_state == KSM_STATE_READY) {
939  (void) MsgLog(KME_NEW_DS, zone_name);
940 
941  }
942  }
943  else if (keytype == KSM_TYPE_KSK && src_state == KSM_STATE_KEYPUBLISH) {
944  /* Set our flag, we are completing an emergency rollover */
945  *NewDS = 1;
946  }
947 
948  StrFree(insql);
949  StrFree(zone_name);
950 
951  return status;
952 }
953 
954 
955 
956 /*+
957  * KsmRequestChangeStateGeneratePublish - Change State from GENERATE to PUBLISH
958  * KsmRequestChangeStateGenerateDSPublish - Change State from GENERATE to DSPUBLISH
959  * KsmRequestChangeStateReadyActive - Change State from READY to ACTIVE
960  *
961  * Description:
962  * Changes the state of a number of keys from one state to another.
963  *
964  * Arguments:
965  * int keytype
966  * Type of keys being changed.
967  *
968  * const char* datetime
969  * Date/time for which this request is being made.
970  *
971  * int count
972  * Number of keys to be promoted to the publish state. There is no
973  * check as to whether that number of keys are available in the
974  * GENERATE state - it is assumed that that check has already been
975  * carried out.
976  *
977  * int zone_id
978  * ID of zone that we are looking at (-1 == all zones)
979  *
980  * Returns:
981  * int
982  * Status return. 0 => success, Other => failure, in which case an
983  * error message will have been output.
984 -*/
985 
986 int KsmRequestChangeStateGeneratePublish(int keytype, const char* datetime,
987  int count, int zone_id)
988 {
989  return KsmRequestChangeStateN(keytype, datetime, count,
991 }
992 
993 int KsmRequestChangeStateGenerateDSSub(int keytype, const char* datetime,
994  int count, int zone_id)
995 {
996  return KsmRequestChangeStateN(keytype, datetime, count,
998 }
999 
1000 int KsmRequestChangeStateReadyActive(int keytype, const char* datetime,
1001  int count, int zone_id)
1002 {
1003  return KsmRequestChangeStateN(keytype, datetime, count,
1004  KSM_STATE_READY, KSM_STATE_ACTIVE, zone_id);
1005 }
1006 
1007 
1008 /*+
1009  * KsmRequestChangeStateN - Change State of N Keys
1010  *
1011  * Description:
1012  * Changes the state of a given number of keys from one state to another.
1013  *
1014  * Arguments:
1015  * int keytype
1016  * Type of keys being changed.
1017  *
1018  * const char* datetime
1019  * Date/time for which this request is being made.
1020  *
1021  * int count
1022  * Number of keys to be promoted to the destination state. There is no
1023  * check as to whether that number of keys are available in the
1024  * state - it is assumed that that check has already been carried out.
1025  *
1026  * int src_state
1027  * State from which keys are being prompted.
1028  *
1029  * int dst_state
1030  * State to which keys are being promoted.
1031  *
1032  * int zone_id
1033  * ID of zone that we are looking at (-1 == all zones)
1034  *
1035  * Returns:
1036  * int
1037  * Status return. 0 => success, Other => failure, in which case an
1038  * error message will have been output.
1039 -*/
1040 
1041 int KsmRequestChangeStateN(int keytype, const char* datetime, int count,
1042  int src_state, int dst_state, int zone_id)
1043 {
1044  char buffer[32]; /* For integer conversion */
1045  DQS_QUERY_CONDITION condition[4]; /* Condition codes */
1046  KSM_KEYDATA data; /* Data for this key */
1047  char* dst_name = NULL; /* Dest state name uppercase */
1048  DB_RESULT result; /* List result set */
1049  int i; /* Loop counter */
1050  char* insql = NULL; /* SQL "IN" clause */
1051  int* keyids; /* List of IDs of keys to promote */
1052  int setclause = 0; /* For the "SET" clauses */
1053  char* sql1 = NULL; /* SQL statement */
1054  char* sql2 = NULL; /* SQL statement */
1055  char* sql3 = NULL; /* SQL statement */
1056  int status; /* Status return */
1057  int whereclause = 0; /* For the "WHERE" clauses */
1058  int count1 = 0; /* No. of non-backed up keys */
1059  int count2 = 0; /* No. of non-backed up keys which should be */
1060 
1061  /* Just checking */
1062  if (count <= 0) {
1063  status = MsgLog(KSM_INVARG, "Asked to move 0 keys");
1064  return status;
1065  }
1066 
1067  /* Notify progress if debugging */
1068 
1070  KsmKeywordStateValueToName(src_state),
1071  KsmKeywordStateValueToName(dst_state));
1072 
1073  /* Allocate space for the list of key IDs */
1074  keyids = MemMalloc(count * sizeof(int));
1075 
1076  /* Get the list of IDs */
1077 
1078  condition[0].code = DB_KEYDATA_KEYTYPE;
1079  condition[0].data.number = keytype;
1080  condition[0].compare = DQS_COMPARE_EQ;
1081 
1082  condition[1].code = DB_KEYDATA_STATE;
1083  condition[1].data.number = src_state;
1084  condition[1].compare = DQS_COMPARE_EQ;
1085 
1086  condition[2].compare = DQS_END_OF_LIST;
1087 
1088  if (zone_id != -1) {
1089  condition[2].code = DB_KEYDATA_ZONE_ID;
1090  condition[2].data.number = zone_id;
1091  condition[2].compare = DQS_COMPARE_EQ;
1092 
1093  condition[3].compare = DQS_END_OF_LIST;
1094  }
1095 
1096 
1097  status = KsmKeyInit(&result, condition);
1098  for (i = 0; ((i < count) && (status == 0)); ++i) {
1099  status = KsmKey(result, &data);
1100  if (status == 0) {
1101  keyids[i] = data.keypair_id;
1102  }
1103  }
1104  KsmKeyEnd(result);
1105 
1106  /* Did we get everything? */
1107 
1108  if (status == 0) {
1109 
1110  /*
1111  * Yes: construct the "IN" statement listing the IDs of the keys we
1112  * are planning to change the state of.
1113  */
1114 
1115  StrAppend(&insql, "(");
1116  for (i = 0; i < count; ++i) {
1117  if (i != 0) {
1118  StrAppend(&insql, ",");
1119  }
1120  snprintf(buffer, sizeof(buffer), "%d", keyids[i]);
1121  StrAppend(&insql, buffer);
1122  }
1123  StrAppend(&insql, ")");
1124 
1125  /* Get upper case names of the states (= names of date columns) */
1126 
1127  if (dst_state == KSM_STATE_DSSUB) {
1128  StrAppend(&dst_name, KSM_STATE_PUBLISH_STRING);
1129  } else {
1130  dst_name = StrStrdup(KsmKeywordStateValueToName(dst_state));
1131  }
1132  (void) StrToUpper(dst_name);
1133 
1134  if (dst_state == KSM_STATE_ACTIVE) {
1135  /*
1136  * We are making the key(s) active so check the backedupness of these keys,
1137  * and compare with the requirebackup flag on their repository
1138  */
1139  /*
1140  * First see if we have any which are not backed up
1141  */
1142  StrAppend(&sql1, "select count(*) from keypairs where id in ");
1143  StrAppend(&sql1, insql);
1144  StrAppend(&sql1, " and backup is null");
1145 
1146  status = DbIntQuery(DbHandle(), &count1, sql1);
1147  DqsFree(sql1);
1148 
1149  if (status != 0)
1150  {
1151  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
1152  StrFree(insql);
1153  MemFree(keyids);
1154  StrFree(dst_name);
1155  return status;
1156  }
1157 
1158  if (count1 != 0) {
1159  /*
1160  * See if any of these are supposed to be backed up
1161  */
1162 
1163  StrAppend(&sql2, "select count(*) from keypairs k, securitymodules s where s.id = k.securitymodule_id and k.id in ");
1164  StrAppend(&sql2, insql);
1165  StrAppend(&sql2, " and k.backup is null and s.requirebackup = 1");
1166 
1167  status = DbIntQuery(DbHandle(), &count2, sql2);
1168  DqsFree(sql2);
1169 
1170  if (status != 0)
1171  {
1172  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
1173  StrFree(insql);
1174  MemFree(keyids);
1175  StrFree(dst_name);
1176  return status;
1177  }
1178 
1179  if (count2 != 0) {
1180  /*
1181  * This is bad; log an error and return
1182  */
1183  status = MsgLog(KME_BACK_FATAL, (keytype == KSM_TYPE_KSK) ? "KSK" : "ZSK");
1184  StrFree(insql);
1185  MemFree(keyids);
1186  StrFree(dst_name);
1187  return status;
1188  }
1189 
1190  /*
1191  * We allow this, but with a strong warning
1192  */
1193  (void) MsgLog(KME_BACK_NON_FATAL, (keytype == KSM_TYPE_KSK) ? "KSK" : "ZSK");
1194  }
1195  }
1196 
1197  /*
1198  * Now construct the "UPDATE" statement and execute it. This relies on
1199  * the fact that the name of the state is the same as the name of
1200  * the column in KEYDATA holding the date at which the key moved to
1201  * that state.
1202  */
1203 
1204  sql3 = DusInit("dnsseckeys");
1205  DusSetInt(&sql3, "STATE", dst_state, setclause++);
1206  DusSetString(&sql3, dst_name, datetime, setclause++);
1207  StrFree(dst_name);
1208 
1209  DusConditionKeyword(&sql3, "KEYPAIR_ID", DQS_COMPARE_IN, insql, whereclause++);
1210  DusConditionInt(&sql3, "ZONE_ID", DQS_COMPARE_EQ, zone_id, whereclause++);
1211  StrFree(insql);
1212  DusEnd(&sql3);
1213 
1214  status = DbExecuteSqlNoResult(DbHandle(), sql3);
1215  DusFree(sql3);
1216 
1217  /* Report any errors */
1218 
1219  if (status != 0) {
1220  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1221  }
1222  }
1223 
1224  /* Free up resources */
1225 
1226  MemFree(keyids);
1227 
1228  return status;
1229 }
1230 
1231 /*+
1232  * KsmRequestChangeStateGenerateDSSubConditional -
1233  * Change State from Generate to DSSub
1234  *
1235  * Description:
1236  * Make sure that the zone has the correct number of standby keys.
1237  *
1238  * Arguments:
1239  * int keytype
1240  * Key type for which the request should happen.
1241  *
1242  * KSM_TYPE_KSK KSKs
1243  * KSM_TYPE_ZSK ZSKs
1244  *
1245  * const char* datetime
1246  * Date/time for which this request is taking place.
1247  *
1248  * KSM_PARCOLL* collection
1249  * Pointer to parameter collection for this zone.
1250  *
1251  * int zone_id
1252  * ID of zone that we are looking at (-1 == all zones)
1253  *
1254  * Returns:
1255  * int
1256  * Status return. 0 => success, Other => failure, in which case an
1257  * error message will have been output.
1258 -*/
1259 
1261  const char* datetime, KSM_PARCOLL* collection, int zone_id, int* NewDS)
1262 {
1263  int gencnt; /* Number of keys in generate state */
1264  int newkeys; /* New keys required */
1265  int standby; /* Number of standby keys */
1266  int reqkeys; /* Number of keys required */
1267  int status; /* Status return */
1268 
1269  /* How many standby keys we have */
1270  status = KsmRequestStandbyKSKCount(&standby, zone_id);
1271  if (status != 0) {
1272  return status;
1273  }
1274 
1275  reqkeys = KsmParameterStandbyKSKeys(collection);
1276 
1277  /*
1278  * So, if we remove "pendret" keys from the number of "available"
1279  * keys, how many are we short of the required number? This is how many
1280  * we need to promote from "generate" to "publish"
1281  */
1282 
1283  newkeys = reqkeys - standby;
1284 
1285  if (newkeys > 0) {
1286 
1287  /* Are there enough generated keys available */
1288 
1289  status = KsmRequestGenerateCount(keytype, &gencnt, zone_id);
1290  if (status == 0) {
1291  if (gencnt < newkeys) {
1292  status = MsgLog(KME_INSFGENKEY, gencnt,
1293  KsmKeywordTypeValueToName(keytype), newkeys);
1294  }
1296  KsmKeywordTypeValueToName(keytype));
1297 
1298  if (status == 0) {
1299 
1300  /* There are enough keys, so move them to "dssub" state */
1301 
1302  status = KsmRequestChangeStateGenerateDSSub(keytype,
1303  datetime, newkeys, zone_id);
1304 
1305  /* Set our flag */
1306  *NewDS = 1;
1307  }
1308  }
1309  }
1310 
1311  return 0;
1312 }
1313 
1314 /*+
1315  * KsmRequestChangeStateGeneratePublishConditional -
1316  * Change State from Generate to Pubish
1317  *
1318  * Description:
1319  * Unlike the other "Change State" functions, this is conditional. It
1320  * promotes keys in the "Generate" state to the "Publish" state to maintain
1321  * the required number of keys active/standby keys when the active keys
1322  * are retired.
1323  *
1324  * a) For the given time, work out how many "active" keys have a retire
1325  * date within this time + "publication interval". Call this number
1326  * Npr (Number pending retirement).
1327  *
1328  * This should be 1 or 0, as there is an assumption that there is only
1329  * ever one active key.
1330  *
1331  * b) Work out how many keys are in the active, publish and ready states.
1332  * Call this Nt (Number total).
1333  *
1334  * c) Now look at the difference (Nt - Npr). This is the number of keys
1335  * that will be (potentially) usable after the active key retires.
1336  * If this number is less than (1 + Ne) (where Ne is the number of
1337  * standby keys), move the difference from the generated state into
1338  * the published state.
1339  *
1340  * Arguments:
1341  * int keytype
1342  * Key type for which the request should happen.
1343  *
1344  * KSM_TYPE_KSK KSKs
1345  * KSM_TYPE_ZSK ZSKs
1346  *
1347  * const char* datetime
1348  * Date/time for which this request is taking place.
1349  *
1350  * KSM_PARCOLL* collection
1351  * Pointer to parameter collection for this zone.
1352  *
1353  * int zone_id
1354  * ID of zone that we are looking at (-1 == all zones)
1355  *
1356  * int run_interval
1357  * how frequently do we run?
1358  *
1359  * Returns:
1360  * int
1361  * Status return. 0 => success, Other => failure, in which case an
1362  * error message will have been output.
1363 -*/
1364 
1366  const char* datetime, KSM_PARCOLL* collection, int zone_id, int run_interval)
1367 {
1368  int availkeys; /* Number of availkeys keys */
1369  int gencnt; /* Number of keys in generate state */
1370  int newkeys; /* New keys required */
1371  int pendret; /* Number of keys that will be retired */
1372  int reqkeys; /* Number of keys required */
1373  int status; /* Status return */
1374 
1375  /* How many active keys will be retired in the immediate future */
1376  status = KsmRequestPendingRetireCount(keytype, datetime, collection,
1377  &pendret, zone_id, run_interval);
1378  if (status != 0) {
1379  return status;
1380  }
1381  DbgLog(DBG_M_REQUEST, KME_RETIRECNT, pendret);
1382 
1383  /* How many available keys are there */
1384 
1385  status = KsmRequestAvailableCount(keytype, datetime, collection,
1386  &availkeys, zone_id);
1387  if (status != 0) {
1388  return status;
1389  }
1390  DbgLog(DBG_M_REQUEST, KME_AVAILCNT, availkeys);
1391 
1392  /*
1393  * We need at least one active key and "number of standby keys" ready
1394  * keys at any one time.
1395  */
1396 
1397  if (keytype == KSM_TYPE_KSK) {
1398  /* For KSKs we sort out standby keys separately */
1399  reqkeys = 1; /*+ KsmParameterStandbyKSKeys(collection);*/
1400  }
1401  else if (keytype == KSM_TYPE_ZSK) {
1402  reqkeys = 1 + KsmParameterStandbyZSKeys(collection);
1403  }
1404  else {
1405  /* should not get here */
1406  return -1;
1407  }
1408 
1409  /*
1410  * So, if we remove "pendret" keys from the number of "available"
1411  * keys, how many are we short of the required number? This is how many
1412  * we need to promote from "generate" to "publish"
1413  */
1414 
1415  newkeys = reqkeys - (availkeys - pendret);
1416  /* fprintf(stderr, "%s: keytype(%d): newkeys(%d) = reqkeys(%d) - (availkeys(%d) - pendret(%d))\n", datetime, keytype, newkeys, reqkeys, availkeys, pendret); */
1417  DbgLog(DBG_M_REQUEST, KME_KEYCNTSUMM, reqkeys, newkeys);
1418 
1419  if (newkeys > 0) {
1420 
1421  /* Are there enough generated keys available */
1422 
1423  status = KsmRequestGenerateCount(keytype, &gencnt, zone_id);
1424  if (status == 0) {
1425  if (gencnt < newkeys) {
1426  status = MsgLog(KME_INSFGENKEY, gencnt,
1427  KsmKeywordTypeValueToName(keytype), newkeys);
1428  }
1430  KsmKeywordTypeValueToName(keytype));
1431 
1432  if (status == 0) {
1433 
1434  /* There are enough keys, so move them to "publish" state */
1435 
1436  status = KsmRequestChangeStateGeneratePublish(keytype,
1437  datetime, newkeys, zone_id);
1438  }
1439  }
1440  }
1441 
1442  return 0;
1443 }
1444 
1445 
1446 
1447 /*+
1448  * KsmRequestPendingRetireCount - Get Count of Keys Pending Retirement
1449  *
1450  * Description:
1451  * For the given time, works out how many "active" keys have a retire
1452  * date within this time + "publication interval".
1453  *
1454  * This should be 1 or 0, as there is an assumption that there is only
1455  * ever one active key.
1456  *
1457  * Arguments:
1458  * int keytype
1459  * Key type for which the request should happen.
1460  *
1461  * KSM_TYPE_KSK KSKs
1462  * KSM_TYPE_ZSK ZSKs
1463  *
1464  * const char* datetime
1465  * Date/time for which this request is taking place.
1466  *
1467  * KSM_PARCOLL* parameters
1468  * Parameters associated with this zone.
1469  *
1470  * int* count (returned)
1471  * Number of active keys that will retire within that period.
1472  *
1473  * int zone_id
1474  * ID of zone that we are looking at (-1 == all zones)
1475  *
1476  * Returns:
1477  * int
1478  * Status return. 0 => success, <>0 => error, in which case a message
1479  * will have been output.
1480 -*/
1481 
1482 int KsmRequestPendingRetireCount(int keytype, const char* datetime,
1483  KSM_PARCOLL* parameters, int* count, int zone_id, int interval)
1484 {
1485  char buffer[256]; /* For constructing part of the command */
1486  int clause = 0; /* Used in constructing SQL statement */
1487  size_t nchar; /* Number of characters written */
1488  char* sql; /* SQL command to be isssued */
1489  int status; /* Status return */
1490  int total_interval; /* The PublicationInterval + interval (when we will run again) */
1491 
1492  if (keytype == KSM_TYPE_ZSK)
1493  {
1494  total_interval = KsmParameterZskTtl(parameters) +
1495  KsmParameterPropagationDelay(parameters) +
1496  KsmParameterPubSafety(parameters) +
1497  interval;
1498  } else {
1499  total_interval = KsmParameterKskTtl(parameters) +
1500  KsmParameterKskPropagationDelay(parameters) +
1501  KsmParameterPubSafety(parameters) +
1502  interval;
1503  /*
1504  if (DOUBLEDNSKEY) {
1505  total_interval = KsmParameterKskTtl(parameters) +
1506  KsmParameterPropagationDelay(parameters) +
1507  KsmParameterDSTtl(parameters) +
1508  KsmParameterKskPropagationDelay(parameters) +
1509  KsmParameterPubSafety(parameters) +
1510  interval;
1511  }
1512  if (DOUBLEDS) {
1513  total_interval = KsmParameterDSTtl(parameters) +
1514  KsmParameterKskPropagationDelay(parameters) +
1515  KsmParameterPubSafety(parameters) +
1516  interval;
1517  }
1518  if (DOUBLERRSET) {
1519  temp = MAX(
1520  (KsmParameterKskTtl(parameters) + KsmParameterPropagationDelay(parameters)),
1521  (KsmParameterDSTtl(parameters) + KsmParameterKskPropagationDelay(parameters)));
1522  if (RFC5011) {
1523  temp = max(temp, 30*24*60*60);
1524  }
1525  total_interval = temp + KsmParameterPubSafety(parameters) +
1526  interval;
1527  }
1528  */
1529  }
1530  /* Create the SQL command to interrogate the database */
1531 
1532  sql = DqsCountInit("KEYDATA_VIEW");
1533  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1534  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++);
1535  if (zone_id != -1) {
1536  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1537  }
1538 
1539  /* Calculate the initial publication interval & add to query */
1540 
1541  /*
1542  * TODO is there an alternative to DATE_ADD which is more generic?
1543  */
1544 #ifdef USE_MYSQL
1545  nchar = snprintf(buffer, sizeof(buffer),
1546  "DATE_ADD('%s', INTERVAL %d SECOND)",
1547  datetime, total_interval);
1548 #else
1549  nchar = snprintf(buffer, sizeof(buffer),
1550  "DATETIME('%s', '+%d SECONDS')",
1551  datetime, total_interval);
1552 #endif /* USE_MYSQL */
1553  if (nchar >= sizeof(buffer)) {
1554  status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys");
1555  return status;
1556  }
1557 
1558 #ifdef USE_MYSQL
1559  DqsConditionKeyword(&sql, "RETIRE", DQS_COMPARE_LE, buffer, clause++);
1560 #else
1561  DqsConditionKeyword(&sql, "DATETIME(RETIRE)", DQS_COMPARE_LE, buffer, clause++);
1562 #endif /* USE_MYSQL */
1563 
1564  DqsEnd(&sql);
1565 
1566  /* Execute the query and free resources */
1567 
1568  status = DbIntQuery(DbHandle(), count, sql);
1569  DqsFree(sql);
1570 
1571  /* Report any errors */
1572 
1573  if (status != 0) {
1574  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1575  }
1576 
1577  return status;
1578 }
1579 
1580 
1581 
1582 /*+
1583  * KsmRequestAvailableCount - Get Count of Available Keys
1584  *
1585  * Description:
1586  * By "available", is the number of keys in the "published", "ready"
1587  * and "active" state.
1588  *
1589  * Arguments:
1590  * int keytype
1591  * Key type for which the request should happen.
1592  *
1593  * KSM_TYPE_KSK KSKs
1594  * KSM_TYPE_ZSK ZSKs
1595  *
1596  * const char* datetime
1597  * Date/time for which this request is taking place.
1598  *
1599  * KSM_PARCOLL* parameters
1600  * Parameters associated with this zone.
1601  *
1602  * int* count (returned)
1603  * Number of available keys.
1604  *
1605  * int zone_id
1606  * ID of zone that we are looking at (-1 == all zones)
1607  *
1608  * Returns:
1609  * int
1610  * Status return. 0 => success, <>0 => error, in which case a message
1611  * will have been output.
1612 -*/
1613 
1614 int KsmRequestAvailableCount(int keytype, const char* datetime, KSM_PARCOLL* parameters, int* count, int zone_id)
1615 {
1616  char buffer[256]; /* For constructing part of the command */
1617  int clause = 0; /* Used in constructing SQL statement */
1618  size_t nchar; /* Number of characters written */
1619  char* sql; /* SQL command to be isssued */
1620  int status; /* Status return */
1621 
1622  /* Unused parameters */
1623  (void)datetime;
1624  (void)parameters;
1625 
1626  /* Create the SQL command to interrogate the database */
1627 
1628  sql = DqsCountInit("KEYDATA_VIEW");
1629  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1630 
1631  /* Calculate the initial publication interval & add to query */
1632 
1633  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d, %d)",
1635  if (nchar >= sizeof(buffer)) {
1636  status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys");
1637  return status;
1638  }
1639  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, clause++);
1640  if (zone_id != -1) {
1641  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1642  }
1643  DqsEnd(&sql);
1644 
1645  /* Execute the query and free resources */
1646 
1647  status = DbIntQuery(DbHandle(), count, sql);
1648  DqsFree(sql);
1649 
1650  /* Report any errors */
1651 
1652  if (status != 0) {
1653  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1654  }
1655 
1656  return status;
1657 }
1658 
1659 
1660 /*+
1661  * KsmRequestGenerateCount - Return Number of Keys in Generate State
1662  *
1663  * Description:
1664  * Returns the retire time of the currently active key. If there are
1665  * multiple active keys, returns the earliest time.
1666  *
1667  * Arguments:
1668  * int keytype
1669  * Time of key to search for.
1670  *
1671  * int* count (returned)
1672  * Number of available keys.
1673  *
1674  * int zone_id
1675  * ID of zone that we are looking at (-1 == all zones)
1676  *
1677  * Returns:
1678  * int
1679  * Status return. 0 => success, Other implies error, in which case a
1680  * message will have been output.
1681 -*/
1682 
1683 int KsmRequestGenerateCount(int keytype, int* count, int zone_id)
1684 {
1685  int clause = 0; /* Clause count */
1686  char* sql = NULL; /* SQL to interrogate database */
1687  int status = 0; /* Status return */
1688 
1689  /* Create the SQL */
1690 
1691  sql = DqsCountInit("KEYDATA_VIEW");
1692  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1693  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_GENERATE, clause++);
1694  if (zone_id != -1) {
1695  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1696  }
1697  DqsEnd(&sql);
1698 
1699  /* Execute the query and free resources */
1700 
1701  status = DbIntQuery(DbHandle(), count, sql);
1702  DqsFree(sql);
1703 
1704  /* Report any errors */
1705 
1706  if (status != 0) {
1707  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1708  }
1709 
1710  return status;
1711 }
1712 
1713 /*+
1714  * KsmRequestStandbyKSKCount - Get Count of Standby Keys
1715  *
1716  * Description:
1717  * The number of keys in the "dspublished" and "dsready" states.
1718  *
1719  * Arguments:
1720  *
1721  * int* count (returned)
1722  * Number of standby keys.
1723  *
1724  * int zone_id
1725  * ID of zone that we are looking at (-1 == all zones)
1726  *
1727  * Returns:
1728  * int
1729  * Status return. 0 => success, <>0 => error, in which case a message
1730  * will have been output.
1731 -*/
1732 
1733 int KsmRequestStandbyKSKCount(int* count, int zone_id)
1734 {
1735  char buffer[256]; /* For constructing part of the command */
1736  int clause = 0; /* Used in constructing SQL statement */
1737  size_t nchar; /* Number of characters written */
1738  char* sql; /* SQL command to be isssued */
1739  int status; /* Status return */
1740 
1741  /* Create the SQL command to interrogate the database */
1742 
1743  sql = DqsCountInit("KEYDATA_VIEW");
1744  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, KSM_TYPE_KSK, clause++);
1745 
1746  /* Calculate the initial publication interval & add to query */
1747 
1748  nchar = snprintf(buffer, sizeof(buffer), "(%d, %d, %d)",
1750  if (nchar >= sizeof(buffer)) {
1751  status = MsgLog(KME_BUFFEROVF, "KsmRequestKeys");
1752  return status;
1753  }
1754  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, buffer, clause++);
1755  if (zone_id != -1) {
1756  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1757  }
1758  DqsEnd(&sql);
1759 
1760  /* Execute the query and free resources */
1761 
1762  status = DbIntQuery(DbHandle(), count, sql);
1763  DqsFree(sql);
1764 
1765  /* Report any errors */
1766 
1767  if (status != 0) {
1768  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1769  }
1770 
1771  return status;
1772 }
1773 
1774 /*
1775  * KsmRequestCheckActiveKey - Check Active Key
1776  *
1777  * Description:
1778  * Checks:
1779  *
1780  * a) If there is an active key.
1781  * b) If a key is present, what the retire time of it is. This is compared
1782  * against the specified date/time.
1783  *
1784  * A flag is returned indicating whether the key (if active) should be
1785  * replaced.
1786  *
1787  * Arguments:
1788  * int keytype
1789  * Either KSK or ZSK, depending on the key type
1790  *
1791  * const char* datetime
1792  * Date/time at which the check is being carried out.
1793  *
1794  * int* count
1795  * Number of active keys of the appropriate type and in the zone
1796  * that will be active AFTER the given date and time.
1797  *
1798  * int zone_id
1799  * ID of zone that we are looking at (-1 == all zones)
1800  *
1801  * This negative form (i.e. keys not meeting the specified condition)
1802  * is used to ensure that if there are no active keys, this fact is
1803  * reported.
1804  *
1805  * Returns:
1806  * int
1807  * Status return. 0 => success, Other => error, in which case a message
1808  * will have been output.
1809 -*/
1810 
1811 int KsmRequestCheckActiveKey(int keytype, const char* datetime, int* count, int zone_id)
1812 {
1813  int clause = 0; /* Clause counter */
1814  char* sql = NULL; /* SQL command */
1815  int status; /* Status return */
1816 #ifdef USE_MYSQL
1817 #else
1818  char buf[256]; /* For constructing part of the command */
1819 #endif /* USE_MYSQL */
1820  sql = DqsCountInit("KEYDATA_VIEW");
1821  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1822  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++);
1823  if (zone_id != -1) {
1824  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1825  }
1826 
1827 #ifdef USE_MYSQL
1828  DqsConditionString(&sql, "RETIRE", DQS_COMPARE_GT, datetime, clause++);
1829 #else
1830  snprintf(buf, sizeof(buf), "DATETIME('%s')", datetime);
1831  DqsConditionKeyword(&sql, "DATETIME(RETIRE)", DQS_COMPARE_GT, buf, clause++);
1832 #endif /* USE_MYSQL */
1833 
1834  DqsEnd(&sql);
1835 
1836  status = DbIntQuery(DbHandle(), count, sql);
1837  DqsFree(sql);
1838 
1839  if (status != 0) {
1840  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1841  }
1843  KsmKeywordTypeValueToName(keytype));
1844 
1845  return status;
1846 }
1847 
1848 
1849 
1850 /*
1851  * KsmRequestCountReadyKey - Count Keys in READY state
1852  *
1853  * Description:
1854  * Counts the number of keys in the "READY" state.
1855  *
1856  * Arguments:
1857  * int keytype
1858  * Either KSK or ZSK, depending on the key type
1859  *
1860  * const char* datetime
1861  * Date/time at which the check is being carried out.
1862  *
1863  * int* count
1864  * Number of keys meeting the condition.
1865  *
1866  * int zone_id
1867  * ID of zone that we are looking at (-1 == all zones)
1868  *
1869  * Returns:
1870  * int
1871  * Status return. 0 => success, Other => error, in which case a message
1872  * will have been output.
1873 -*/
1874 
1875 int KsmRequestCountReadyKey(int keytype, const char* datetime, int* count, int zone_id)
1876 {
1877  int clause = 0; /* Clause counter */
1878  char* sql = NULL; /* SQL command */
1879  int status; /* Status return */
1880 
1881  /* Unused parameter */
1882  (void)datetime;
1883 
1884  sql = DqsCountInit("KEYDATA_VIEW");
1885  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1886  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_READY, clause++);
1887  if (zone_id != -1) {
1888  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1889  }
1890  DqsEnd(&sql);
1891 
1892  status = DbIntQuery(DbHandle(), count, sql);
1893  DqsFree(sql);
1894 
1895  if (status != 0) {
1896  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1897  }
1899  KsmKeywordTypeValueToName(keytype));
1900 
1901  return status;
1902 }
1903 
1904 /*
1905  * KsmRequestCheckFirstPass - Work out if this zone has been processed before
1906  *
1907  * Description:
1908  * Counts the number of keys above the PUBLISH state; if this is 0 then this is
1909  * a new zone.
1910  *
1911  * Arguments:
1912  * int keytype
1913  * Either KSK or ZSK, depending on the key type
1914  *
1915  * int* first_pass_flag
1916  * Indicator as to the result
1917  *
1918  * int zone_id
1919  * ID of zone that we are looking at (-1 == all zones)
1920  *
1921  * Returns:
1922  * int
1923  * Status return. 0 => success, Other => error, in which case a message
1924  * will have been output.
1925 -*/
1926 
1927 int KsmRequestCheckFirstPass(int keytype, int* first_pass_flag, int zone_id)
1928 {
1929  int clause = 0; /* Clause counter */
1930  char* sql = NULL; /* SQL command */
1931  int status; /* Status return */
1932  int count = 0; /* Number of matching keys */
1933 
1934  sql = DqsCountInit("KEYDATA_VIEW");
1935  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1936  DqsConditionInt(&sql, "STATE", DQS_COMPARE_GE, KSM_STATE_PUBLISH, clause++);
1937  if (zone_id != -1) {
1938  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1939  }
1940  DqsEnd(&sql);
1941 
1942  status = DbIntQuery(DbHandle(), &count, sql);
1943  DqsFree(sql);
1944 
1945  if (status != 0) {
1946  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
1947  }
1948 
1949  if (count == 0) {
1950  /* No "ready, active, retired or dead" keys */
1951  *first_pass_flag = 1;
1952  }
1953  else {
1954  *first_pass_flag = 0;
1955  }
1956 
1957  return status;
1958 }
1959 
1960 /*
1961  * KsmRequestCheckCompromisedFlag - Work out if this zone is rolling
1962  *
1963  * Description:
1964  * Counts the number of "compromised" active keys, if > 0 then force
1965  * the zone to roll if we can.
1966  *
1967  * Arguments:
1968  * int keytype
1969  * Either KSK or ZSK, depending on the key type
1970  *
1971  * int zone_id
1972  * ID of zone that we are looking at (-1 == all zones)
1973  *
1974  * int* comp_flag
1975  * Force rollover behaviour if the active key is marked as compromised
1976  *
1977  * Returns:
1978  * int
1979  * Status return. 0 => success, Other => error, in which case a message
1980  * will have been output.
1981 -*/
1982 
1983 int KsmRequestCheckCompromisedFlag(int keytype, int zone_id, int* comp_flag)
1984 {
1985  int clause = 0; /* Clause counter */
1986  char* sql = NULL; /* SQL command */
1987  int status; /* Status return */
1988  int count = 0; /* Number of matching keys */
1989 
1990  sql = DqsCountInit("KEYDATA_VIEW");
1991  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
1992  DqsConditionInt(&sql, "STATE", DQS_COMPARE_EQ, KSM_STATE_ACTIVE, clause++);
1993  if (zone_id != -1) {
1994  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
1995  }
1996  DqsConditionInt(&sql, "compromisedflag", DQS_COMPARE_EQ, 1, clause++);
1997  DqsEnd(&sql);
1998 
1999  status = DbIntQuery(DbHandle(), &count, sql);
2000  DqsFree(sql);
2001 
2002  if (status != 0) {
2003  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
2004  }
2005 
2006  if (count == 0) {
2007  /* No "compromised" keys; i.e. keys waiting to roll */
2008  /* We actually don't need to do this as it can only be 0 already */
2009  *comp_flag = 0;
2010  }
2011  else {
2012  *comp_flag = 1;
2013  }
2014 
2015  return status;
2016 }
2017 
2018 /*+
2019  * KsmRequestIssueKeys - Issue Keys
2020  *
2021  * Description:
2022  * Done as the last step in the "REQUEST KEYS" operation, this actually
2023  * issues the keys that should be in the current zone file. All keys in
2024  * the "publish", "ready", "active" and "retire" states are included.
2025  *
2026  * Arguments:
2027  * int keytype
2028  * Type of keys required.
2029  *
2030  * KSM_REQUEST_CALLBACK callback
2031  * Callback function called for every key that will be issued.
2032  *
2033  * void* context
2034  * Context argument passed uninterpreted to the callback function.
2035  *
2036  * int zone_id
2037  * ID of zone that we are looking at (-1 == all zones)
2038  *
2039  * Returns:
2040  * int
2041  * Status return. 0 => success, <>0 => error (in which case a message
2042  * will have been output).
2043 -*/
2044 
2045 int KsmRequestIssueKeys(int keytype, KSM_REQUEST_CALLBACK callback,
2046  void* context, int zone_id)
2047 {
2048  int clause = 0; /* For the WHERE clause */
2049  KSM_KEYDATA data; /* Data for this key */
2050  DB_RESULT result; /* Result set from query */
2051  char in[128]; /* Easily large enought for four keys */
2052  size_t nchar; /* Number of output characters */
2053  char* sql = NULL; /* SQL statement to get listing */
2054  int status; /* Status return */
2055 
2056  /*
2057  * Construct the "IN" statement listing the states of the keys that
2058  * are included in the output.
2059  */
2060 
2061  nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d)",
2063  if (nchar >= sizeof(in)) {
2064  status = MsgLog(KME_BUFFEROVF, "KsmRequestIssueKeys");
2065  return status;
2066  }
2067 
2068  /* Create the SQL command to interrogate the database */
2069 
2070  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
2071  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
2072  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, in, clause++);
2073  if (zone_id != -1) {
2074  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
2075  }
2076  DqsEnd(&sql);
2077 
2078  /* Now iterate round the keys meeting the condition and print them */
2079 
2080  status = KsmKeyInitSql(&result, sql);
2081  if (status == 0) {
2082  status = KsmKey(result, &data);
2083  while (status == 0) {
2084  status = (*callback)(context, &data);
2085  if (status == 0) {
2086  status = KsmKey(result, &data);
2087  }
2088  }
2089 
2090  /* Convert EOF status to success */
2091 
2092  if (status == -1) {
2093  status = 0;
2094  }
2095 
2096  KsmKeyEnd(result);
2097  }
2098 
2099  DqsFree(sql);
2100  return status;
2101 }
2102 
2103 
2104 
2105 /*+
2106  * KsmRequestPrintKey - Print Key Data
2107  *
2108  * Description:
2109  * Suitable callback function for KsmRequest, this prints a summary of the
2110  * key information to stdout.
2111  *
2112  * Arguments:
2113  * void* context
2114  * Context passed to KsmUpdate. This is unused.
2115  *
2116  * KSM_KEYDATA* data
2117  * Data about the key to be isssued.
2118  *
2119  * Returns:
2120  * int
2121  * Always 0.
2122 -*/
2123 
2124 int KsmRequestPrintKey(void* context, KSM_KEYDATA* data)
2125 {
2126  /* Unused parameter */
2127  (void)context;
2128 
2129  printf("%s %lu %d %d %s\n", KsmKeywordStateValueToName(data->state),
2130  data->keypair_id, data->keytype, data->algorithm, data->location);
2131 
2132  return 0;
2133 }