OpenDNSSEC-enforcer  1.4.3
ksm_key.c
Go to the documentation of this file.
1 /*
2  * $Id: ksm_key.c 7221 2013-08-19 14:37:53Z sara $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*+
30  * KsmKey - Manipulation of Key Information
31  *
32  * Description:
33  * Holds the functions needed to manipulate the KEYDATA table.
34  *
35  * N.B. The table is the KEYDATA table - rather than the KEY table - as
36  * KEY is a reserved word in SQL.
37 -*/
38 
39 #include <assert.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 
45 #include "ksm/database.h"
46 #include "ksm/database_statement.h"
47 #include "ksm/datetime.h"
48 #include "ksm/db_fields.h"
49 #include "ksm/debug.h"
50 #include "ksm/kmedef.h"
51 #include "ksm/ksm.h"
52 #include "ksm/ksmdef.h"
53 #include "ksm/ksm_internal.h"
54 #include "ksm/message.h"
55 #include "ksm/string_util.h"
56 #include "ksm/string_util2.h"
57 
58 /*+
59  * KsmKeyPairCreate - Create Entry in the KeyPairs table
60  * (i.e. key creation in the HSM)
61  *
62  * Description:
63  * Creates a key in the database.
64  *
65  * Arguments:
66  * policy_id
67  * policy that the key is created for
68  * HSMKeyID
69  * ID the key is refered to in the HSM
70  * smID
71  * security module ID
72  * size
73  * size of key
74  * alg
75  * algorithm used
76  * generate
77  * timestamp of generation
78  *
79  * DB_ID* id (returned)
80  * ID of the created entry. This will be undefined on error.
81  *
82  * Returns:
83  * int
84  * Status return. 0=> Success, non-zero => error.
85 -*/
86 int KsmKeyPairCreate(int policy_id, const char* HSMKeyID, int smID, int size, int alg, const char* generate, DB_ID* id)
87 {
88  unsigned long rowid; /* ID of last inserted row */
89  int status = 0; /* Status return */
90  char* sql = NULL; /* SQL Statement */
91 
92  /* Check arguments */
93  if (id == NULL) {
94  return MsgLog(KSM_INVARG, "NULL id");
95  }
96 
97  sql = DisSpecifyInit("keypairs", "policy_id, HSMkey_id, securitymodule_id, size, algorithm, generate");
98  DisAppendInt(&sql, policy_id);
99  DisAppendString(&sql, HSMKeyID);
100  DisAppendInt(&sql, smID);
101  DisAppendInt(&sql, size);
102  DisAppendInt(&sql, alg);
103  DisAppendString(&sql, generate);
104  DisEnd(&sql);
105 
106  /* Execute the statement */
107 
108  status = DbExecuteSqlNoResult(DbHandle(), sql);
109  DisFree(sql);
110 
111  if (status == 0) {
112 
113  /* Succcess, get the ID of the inserted record */
114 
115  status = DbLastRowId(DbHandle(), &rowid);
116  if (status == 0) {
117  *id = (DB_ID) rowid;
118  }
119  }
120 
121  return status;
122 }
123 
124 /*+
125  * KsmDnssecKeyCreate - Create Entry in Dnsseckeys table
126  * (i.e. when a key is assigned to a policy/zone)
127  *
128  * Description:
129  * Allocates a key in the database.
130  *
131  * Arguments:
132  * KSM_KEY* data
133  * Data to insert into the database. The ID argument is ignored.
134  *
135  * DB_ID* id (returned)
136  * ID of the created entry. This will be undefined on error.
137  *
138  * Returns:
139  * int
140  * Status return. 0=> Success, non-zero => error.
141 -*/
142 
143 int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, const char* time, const char* retTime, DB_ID* id)
144 {
145  unsigned long rowid; /* ID of last inserted row */
146  int status = 0; /* Status return */
147  char* sql = NULL; /* SQL Statement */
148  char* columns = NULL; /* what columns are we setting */
149 
150  /* Check arguments */
151  if (id == NULL) {
152  return MsgLog(KSM_INVARG, "NULL id");
153  }
154 
155  StrAppend(&columns, "zone_id, keypair_id, keytype, state");
156  if (state != KSM_STATE_GENERATE) {
157  StrAppend(&columns, ", ");
158  StrAppend(&columns, KsmKeywordStateValueToName(state));
159  }
160  if (state == KSM_STATE_ACTIVE && (retTime != NULL && retTime[0] != '\0')) {
161  StrAppend(&columns, ", retire");
162  }
163 
164  sql = DisSpecifyInit("dnsseckeys", columns);
165  DisAppendInt(&sql, zone_id);
166  DisAppendInt(&sql, keypair_id);
167  DisAppendInt(&sql, keytype);
168  DisAppendInt(&sql, state);
169  if (state != KSM_STATE_GENERATE) {
170  DisAppendString(&sql, time);
171  }
172  if (state == KSM_STATE_ACTIVE && (retTime != NULL && retTime[0] != '\0')) {
173  DisAppendString(&sql, retTime);
174  }
175  DisEnd(&sql);
176 
177  /* Execute the statement */
178 
179  status = DbExecuteSqlNoResult(DbHandle(), sql);
180  DisFree(sql);
181  StrFree(columns);
182 
183  if (status == 0) {
184 
185  /* Succcess, get the ID of the inserted record */
186 
187  status = DbLastRowId(DbHandle(), &rowid);
188  if (status == 0) {
189  *id = (DB_ID) rowid;
190  }
191  }
192 
193  return status;
194 }
195 
196 /*+
197  * KsmKeyInitSql - Query for Key Information With Sql Query
198  *
199  * Description:
200  * Performs a query for keys in the keydata table that match the given
201  * conditions.
202  *
203  * Arguments:
204  * DB_RESULT* result
205  * Pointer to a result to be used for information retrieval. Will
206  * be NULL on error.
207  *
208  * const char* sql
209  * SQL statement to select keys.
210  *
211  * (Actually, the statement could be anything, but it is assumed
212  * that it is an SQL statement starting "SELECT xxx FROM KEYDATA".)
213  *
214  * Returns:
215  * int
216  * Status return. 0 on success.
217 -*/
218 
219 int KsmKeyInitSql(DB_RESULT* result, const char* sql)
220 {
221  return DbExecuteSql(DbHandle(), sql, result);
222 }
223 
224 
225 
226 
227 /*+
228  * KsmKeyInit - Query for Key Information
229  *
230  * Description:
231  * Performs a query for keys in the keydata table that match the given
232  * conditions.
233  *
234  * Arguments:
235  * DB_RESULT* result
236  * Pointer to a result to be used for information retrieval. Will
237  * be NULL on error.
238  *
239  * DQS_QUERY_CONDITION* condition
240  * Array of condition objects, each defining a condition. The
241  * conditions are ANDed together. The array should end with an object
242  * with a condition code of 0.
243  *
244  * If NULL, all objects are selected.
245  *
246  * Returns:
247  * int
248  * Status return. 0 on success.
249 -*/
250 
251 int KsmKeyInit(DB_RESULT* result, DQS_QUERY_CONDITION* condition)
252 {
253  int i; /* Condition index */
254  char* sql = NULL; /* SQL query */
255  int status = 0; /* Status return */
256 
257  /* Construct the query */
258 
259  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
260  if (condition) {
261  for (i = 0; condition[i].compare != DQS_END_OF_LIST; ++i) {
262  switch (condition[i].code) {
264  DqsConditionInt(&sql, "ALGORITHM", condition[i].compare,
265  condition[i].data.number, i);
266  break;
267 
268  case DB_KEYDATA_ID:
269  DqsConditionInt(&sql, "ID", condition[i].compare,
270  condition[i].data.number, i);
271  break;
272 
273  case DB_KEYDATA_KEYTYPE:
274  DqsConditionInt(&sql, "KEYTYPE", condition[i].compare,
275  condition[i].data.number, i);
276  break;
277 
278  case DB_KEYDATA_STATE:
279  DqsConditionInt(&sql, "STATE", condition[i].compare,
280  condition[i].data.number, i);
281  break;
282 
283  case DB_KEYDATA_ZONE_ID:
284  DqsConditionInt(&sql, "ZONE_ID", condition[i].compare,
285  condition[i].data.number, i);
286  break;
287 
288  default:
289 
290  /* Warn about unrecognised condition code */
291 
292  MsgLog(KME_UNRCONCOD, condition[i].code);
293  }
294  }
295  }
296  DqsEnd(&sql);
297 
298  /* Execute query and free up the query string */
299 
300  status = KsmKeyInitSql(result, sql);
301  DqsFree(sql);
302 
303  return status;
304 }
305 
306 
307 
308 /*+
309  * KsmKeyInitId - Query for Key Information by ID
310  *
311  * Description:
312  * Performs a query for a key in the zone table that matches the
313  * given ID.
314  *
315  * Arguments:
316  * DB_RESULT* result
317  * Pointer to a result to be used for information retrieval. Will
318  * be NULL on error.
319  *
320  * DB_ID id
321  * ID of the object.
322  *
323  * Returns:
324  * int
325  * Status return. 0 on success.
326 -*/
327 
328 int KsmKeyInitId(DB_RESULT* result, DB_ID id)
329 {
330  DQS_QUERY_CONDITION condition[2]; /* Condition for query */
331 
332  /* Initialize */
333 
334  condition[0].code = DB_KEYDATA_ID;
335  condition[0].compare = DQS_COMPARE_EQ;
336  condition[0].data.number = (int) id;
337 
338  condition[1].compare = DQS_END_OF_LIST;
339 
340  return KsmKeyInit(result, condition);
341 }
342 
343 
344 
345 /*+
346  * KsmKey - Return Key Information
347  *
348  * Description:
349  * Returns information about the next key in the result set.
350  *
351  * Arguments:
352  * DB_RESULT result
353  * Handle from KsmKeyInit
354  *
355  * KSM_KEYDATA* data
356  * Data is returned in here.
357  *
358  * Returns:
359  * int
360  * Status return:
361  * 0 success
362  * -1 end of record set reached
363  * non-zero some error occurred and a message has been output.
364  *
365  * If the status is non-zero, the returned data is meaningless.
366 -*/
367 
368 int KsmKey(DB_RESULT result, KSM_KEYDATA* data)
369 {
370  DB_ROW row = NULL; /* Row data */
371  int status = 0; /* Return status */
372 
373  /* Check arguments */
374  if (data == NULL) {
375  return MsgLog(KSM_INVARG, "NULL data");
376  }
377 
378  /* Initialize */
379 
380  memset(data, 0, sizeof(KSM_KEYDATA));
381 
382  /* Get the next row from the data and copy data across */
383 
384  status = DbFetchRow(result, &row);
385 
386  if (status == 0) {
387  status = DbUnsignedLong(row, DB_KEYDATA_ID, &(data->keypair_id));
388  }
389 
390  if (status == 0) {
391  status = DbInt(row, DB_KEYDATA_STATE, &(data->state));
392  }
393 
394  if (status == 0) {
395  status = DbStringBuffer(row, DB_KEYDATA_GENERATE,
396  data->generate, sizeof(data->generate));
397  }
398 
399  if (status == 0) {
400  status = DbStringBuffer(row, DB_KEYDATA_PUBLISH,
401  data->publish, sizeof(data->publish));
402  }
403 
404  if (status == 0) {
405  status = DbStringBuffer(row, DB_KEYDATA_READY,
406  data->ready, sizeof(data->ready));
407  }
408 
409  if (status == 0) {
410  status = DbStringBuffer(row, DB_KEYDATA_ACTIVE,
411  data->active, sizeof(data->active));
412  }
413 
414  if (status == 0) {
415  status = DbStringBuffer(row, DB_KEYDATA_RETIRE,
416  data->retire, sizeof(data->retire));
417  }
418 
419  if (status == 0) {
420  status = DbStringBuffer(row, DB_KEYDATA_DEAD,
421  data->dead, sizeof(data->dead));
422  }
423 
424  if (status == 0) {
425  status = DbInt(row, DB_KEYDATA_KEYTYPE, &(data->keytype));
426  }
427 
428  if (status == 0) {
429  status = DbInt(row, DB_KEYDATA_ALGORITHM, &(data->algorithm));
430  }
431 
432 /* if (status == 0) {
433  status = DbInt(row, DB_KEYDATA_SIGLIFETIME, &(data->siglifetime));
434  }
435 */
436  if (status == 0) {
437  status = DbStringBuffer(row, DB_KEYDATA_LOCATION,
438  data->location, sizeof(data->location));
439  }
440 
441  if (status == 0) {
442  status = DbInt(row, DB_KEYDATA_ZONE_ID, &(data->zone_id));
443  }
444 
445  if (status == 0) {
446  status = DbInt(row, DB_KEYDATA_FIXED_DATE, &(data->fixedDate));
447  }
448 
449  DbFreeRow(row);
450 
451  return status;
452 }
453 
454 
455 /*+
456  * KsmKeyEnd - End Key Information
457  *
458  * Description:
459  * Called at the end of a ksm_key cycle, frees up the stored
460  * result set.
461  *
462  * N.B. This does not clear stored error information, so allowing it
463  * to be called after a failure return from KsmKey to free up database
464  * context whilst preserving the reason for the error.
465  *
466  * Arguments:
467  * DB_RESULT result
468  * Handle from KsmKeyInit
469 -*/
470 
471 void KsmKeyEnd(DB_RESULT result)
472 {
473  DbFreeResult(result);
474 }
475 
476 
477 
478 /*+
479  * KsmKeyData - Return Data for Key
480  *
481  * Description:
482  * Returns data for the named Key.
483  *
484  * Arguments:
485  * DB_ID id
486  * Name/ID of the Key.
487  *
488  * KSM_GROUP* data
489  * Data for the Key.
490  *
491  * Returns:
492  * int
493  * Status return. One of:
494  *
495  * 0 Success
496  * -1 Key not found
497  * Other Error
498 -*/
499 
501 {
502  DB_RESULT result; /* Handle to the data */
503  int status; /* Status return code */
504 
505  status = KsmKeyInitId(&result, id);
506  if (status == 0) {
507 
508  /* Retrieve the key data */
509 
510  status = KsmKey(result, data);
511  (void) KsmKeyEnd(result);
512  }
513  /*
514  * else {
515  * On error, a message will have been output
516  * }
517  */
518 
519  return status;
520 }
521 
522 /*+
523  * KsmKeyPredict - predict how many keys are needed
524  *
525  * Description:
526  * Given a policy and a keytype work out how many keys will be required
527  * during the timeinterval specified (in seconds).
528  *
529  * We assume no emergency rollover and that a key has just been published
530  *
531  * Dt = interval
532  * Sp = safety margin
533  * Lk = lifetime of the key (either KSK or ZSK)
534  * Ek = no of standby keys
535  *
536  * no of keys = ( (Dt + Sp)/Lk ) + Ek
537  *
538  * (rounded up)
539  *
540  * Arguments:
541  * int policy_id
542  * The policy in question
543  * KSM_TYPE key_type
544  * KSK or ZSK
545  * int shared_keys
546  * 0 if keys not shared between zones
547  * int interval
548  * timespan (in seconds)
549  * int *count
550  * (OUT) the number of keys (-1 on error)
551  * int rollover_scheme
552  * KSK rollover scheme in use
553  * int zone_count
554  * Number of zones on this policy
555  *
556  * Returns:
557  * int
558  * Status return. One of:
559  *
560  * 0 Success
561  * Other Error
562 -*/
563 
564 int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
565 {
566  int status = 0; /* Status return */
567  KSM_PARCOLL coll; /* Parameters collection */
568 
569  /* Check arguments */
570  if (count == NULL) {
571  return MsgLog(KSM_INVARG, "NULL count");
572  }
573 
574  /* make sure that we have at least one zone */
575  if (zone_count == 0) {
576  *count = 0;
577  return status;
578  }
579 
580  /* Check that we have a valid key type */
581  if ((keytype != KSM_TYPE_KSK) && (keytype != KSM_TYPE_ZSK)) {
582  status = MsgLog(KME_UNKEYTYPE, keytype);
583  return status;
584  }
585 
586  /* Get list of parameters */
587  status = KsmParameterCollection(&coll, policy_id);
588  if (status != 0) {
589  *count = -1;
590  return status;
591  }
592 
593  /* We should have the policy now */
594  if (keytype == KSM_TYPE_KSK)
595  {
596  if (coll.ksklife == 0) {
597  *count = coll.standbyksks + 1;
598  }
599  else if (rollover_scheme == KSM_ROLL_DNSKEY) {
600  *count = ((interval + coll.pub_safety + coll.propdelay + coll.kskttl)/coll.ksklife) + coll.standbyksks + 1;
601  }
602  else if (rollover_scheme == KSM_ROLL_DS) {
603  *count = ((interval + coll.pub_safety + coll.kskpropdelay + coll.dsttl)/coll.ksklife) + coll.standbyksks + 1;
604  }
605 /* else if (rollover_scheme == KSM_ROLL_RRSET) {
606  temp = MAX((propdelay + kskttl), (kskpropdelay + dsttl));
607  if (RFC5011) {
608  temp = max(temp, 30*24*60*60);
609  }
610  *count = ((interval + coll.pub_safety + temp)/coll.ksklife) + coll.standbyksks + 1;
611  } */
612 
613  }
614  else if (keytype == KSM_TYPE_ZSK)
615  {
616  if (coll.zsklife == 0) {
617  *count = coll.standbyzsks + 1;
618  } else {
619  *count = ((interval + coll.pub_safety)/coll.zsklife) + coll.standbyzsks + 1;
620  }
621  }
622 
623  if (shared_keys == KSM_KEYS_NOT_SHARED) {
624  *count *= zone_count;
625  }
626 
627  return status;
628 }
629 
630 /*+
631  * KsmKeyCountQueue - Return Number of Keys in the queue before active state
632  *
633  * Description:
634  * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH,
635  * KSM_STATE_READY and KSM_STATE_ACTIVE state.
636  * (plus KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY
637  * for standby KSKs)
638  *
639  * Arguments:
640  * int keytype
641  * Key type, KSK or ZSK
642  *
643  * int* count (returned)
644  * Number of keys in the que.
645  *
646  * int zone_id
647  * ID of zone that we are looking at (-1 == all zones)
648  *
649  * Returns:
650  * int
651  * Status return. 0 => success, Other implies error, in which case a
652  * message will have been output.
653 -*/
654 
655 int KsmKeyCountQueue(int keytype, int* count, int zone_id)
656 {
657  int clause = 0; /* Clause count */
658  char* sql = NULL; /* SQL to interrogate database */
659  int status = 0; /* Status return */
660  char in[128]; /* Easily large enought for 7 keys */
661  size_t nchar; /* Number of output characters */
662 
663  /* Create the SQL command to interrogate the database */
664 
665  nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)",
667  if (nchar >= sizeof(in)) {
668  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountQueue");
669  return status;
670  }
671 
672  sql = DqsCountInit("KEYDATA_VIEW");
673  DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++);
674  DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, in, clause++);
675  if (zone_id != -1) {
676  DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++);
677  }
678  DqsEnd(&sql);
679 
680  /* Execute the query and free resources */
681 
682  status = DbIntQuery(DbHandle(), count, sql);
683  DqsFree(sql);
684 
685  /* Report any errors */
686 
687  if (status != 0) {
688  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
689  }
690 
691  return status;
692 }
693 
694 /*+
695  * KsmKeyCountStillGood - Return Number of Keys that will still be usable at a particular
696  * time given a number of parameters
697  *
698  * Description:
699  * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH,
700  * KSM_STATE_READY, KSM_STATE_ACTIVE (or KSM_STATE_DSSUB,
701  * KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY for standby KSKs) state after
702  * the given interval.
703  *
704  * Arguments:
705  * int policy_id
706  * id of the policy for which they key must have been created
707  * (-1 == all policies)
708  * int sm
709  * id of security module
710  * (-1 == all modules)
711  * int bits
712  * size of key desired
713  * (-1 == all sizes)
714  * int algorithm
715  * algorithm of key desired
716  * (-1 == all algorithms`)
717  * int interval
718  * how many seconds in the future we are talking about
719  * const char* datetime
720  * string describing when this calculation is being run
721  *
722  * int* count (returned)
723  * Number of keys in the que.
724  *
725  * int keytype
726  * Key type, KSK or ZSK
727  *
728  * Returns:
729  * int
730  * Status return. 0 => success, Other implies error, in which case a
731  * message will have been output.
732 -*/
733 
734 int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char* datetime, int *count, int keytype)
735 {
736  int where = 0; /* WHERE clause value */
737  char* sql = NULL; /* SQL to interrogate database */
738  int status = 0; /* Status return */
739  char in[128]; /* Easily large enought for three keys */
740  char buffer[512]; /* For constructing part of the command */
741  size_t nchar; /* Number of output characters */
742  int total_interval; /* interval plus retirement time */
743  KSM_PARCOLL collection; /* Parameters collection */
744 
745  /*
746  * Construct the "IN" statement listing the states of the keys that
747  * are included in the output.
748  */
749 
750  /* Get list of parameters */
751  status = KsmParameterCollection(&collection, policy_id);
752  if (status != 0) {
753  return status;
754  }
755 
756  if (keytype == KSM_TYPE_ZSK)
757  {
758  total_interval = KsmParameterZskTtl(&collection) +
759  KsmParameterPropagationDelay(&collection) +
760  KsmParameterPubSafety(&collection) +
761  interval;
762  } else {
763  total_interval = KsmParameterKskTtl(&collection) +
764  KsmParameterKskPropagationDelay(&collection) +
765  KsmParameterPubSafety(&collection) +
766  interval;
767  }
768 
769  nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)",
771  if (nchar >= sizeof(in)) {
772  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood");
773  return status;
774  }
775 
776  /*
777  * TODO is there an alternative to DATE_ADD which is more generic?
778  */
779 #ifdef USE_MYSQL
780  nchar = snprintf(buffer, sizeof(buffer),
781  "DATE_ADD('%s', INTERVAL %d SECOND)", datetime, total_interval);
782 #else
783  nchar = snprintf(buffer, sizeof(buffer),
784  "DATETIME('%s', '+%d SECONDS')", datetime, total_interval);
785 #endif /* USE_MYSQL */
786  if (nchar >= sizeof(buffer)) {
787  status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood");
788  return status;
789  }
790 
791  /* Create the SQL command to interrogate the database */
792 
793  /* Use 'distinct location' here so we don't count multiple entries for zones which share keys*/
794  sql = StrStrdup("SELECT COUNT(DISTINCT location) FROM KEYDATA_VIEW");
795  if (policy_id != -1) {
796  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
797  }
798  if (sm != -1) {
799  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
800  }
801  if (bits != -1) {
802  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
803  }
804  if (algorithm != -1) {
805  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
806  }
807 
808  DqsConditionKeyword(&sql, "(STATE", DQS_COMPARE_IN, in, where++);
809  StrAppend(&sql, " or STATE is NULL)");
810 
811  /* Can't use our generic functions for this aggregated clause */
812 #ifdef USE_MYSQL
813  StrAppend(&sql, " and (RETIRE > ");
814 #else
815  StrAppend(&sql, " and (DATETIME(RETIRE) > ");
816 #endif /* USE_MYSQL */
817  StrAppend(&sql, buffer);
818  StrAppend(&sql, " or RETIRE is NULL)");
819 
820  /*DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);*/
821  DqsEnd(&sql);
822 
823  /* Execute the query and free resources */
824 
825  status = DbIntQuery(DbHandle(), count, sql);
826  DqsFree(sql);
827 
828  /* Report any errors */
829 
830  if (status != 0) {
831  status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle()));
832  }
833 
834  return status;
835 }
836 
837 /*+
838  * KsmKeyGetUnallocated
839  *
840  * Description:
841  * Given a set of policy values get the next unallocated keypair
842  * Executes:
843  * select min(id) from keydata
844  * where policy_id = policy_id
845  * and securitymodule_id = sm
846  * and size = bits
847  * and algorithm = algorithm
848  * and state is KSM_STATE_GENERATE
849  *
850  * Arguments:
851  * int policy_id
852  * id of the policy for which they key must have been created
853  * int sm
854  * id of security module
855  * int bits
856  * size of key desired
857  * int algorithm
858  * algorithm of key desired
859  * int zone_id
860  * zone we are allocating to
861  * int share_keys
862  * 0 if keys are not shared; 1 if they are
863  * int *keypair_id (out)
864  * id of next keypair
865  *
866  * Returns:
867  * int
868  * Status return. 0=> Success, non-zero => error.
869  * -1 == no free keys on that policy
870  */
871 
872 int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
873 {
874 
875  int where = 0; /* WHERE clause value */
876  char* sql = NULL; /* SQL query */
877  DB_RESULT result; /* Handle converted to a result object */
878  DB_ROW row = NULL; /* Row data */
879  int status = 0; /* Status return */
880  char in_sql[1024];
881  char in_sql2[1024];
882 
883  if (share_keys == KSM_KEYS_NOT_SHARED) {
884  /* Construct the query */
885  sql = DqsSpecifyInit("KEYDATA_VIEW","min(id)");
886  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
887  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
888  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
889  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
890  DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);
891  } else {
892  snprintf(in_sql, 1024, "(select id from KEYALLOC_VIEW where zone_id = %d)", zone_id);
893  snprintf(in_sql2, 1024, "(select distinct id from KEYDATA_VIEW where policy_id = %d and state in (%d, %d))", policy_id, KSM_STATE_RETIRE, KSM_STATE_DEAD);
894 
895  /* Construct the query */
896  sql = DqsSpecifyInit("KEYALLOC_VIEW","min(id)");
897  DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++);
898  DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++);
899  DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++);
900  DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++);
901  DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);
902  DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql, where++);
903  DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql2, where++);
904  }
905  /* Execute query and free up the query string */
906  status = DbExecuteSql(DbHandle(), sql, &result);
907  DqsFree(sql);
908 
909  if (status != 0)
910  {
911  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
912  DbFreeResult(result);
913  return status;
914  }
915 
916  /* Get the next row from the data */
917  status = DbFetchRow(result, &row);
918  if (status == 0) {
919  DbInt(row, DB_KEYDATA_ID, keypair_id);
920  }
921  else if (status == -1) {}
922  /* No rows to return (but no DB error) */
923  else {
924  status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle()));
925  }
926 
927  DbFreeRow(row);
928  DbFreeResult(result);
929  return status;
930 }
931 
932 /*+
933  * KsmMarkKeysAsDead - When deleting zones we may need to indicate that keys are now dead
934  * (i.e. when keysharing is turned off or if we removed is the last zone on a policy)
935  *
936  * Description:
937  * Marks selected keys as dead in the database.
938  *
939  * Arguments:
940  * int zone_id
941  * ID of the zone (-1 if all zones are being removed)
942  *
943  * Returns:
944  * int
945  * Status return. 0=> Success, non-zero => error.
946 -*/
947 
948 int KsmMarkKeysAsDead(int zone_id)
949 {
950  int status = 0;
951 
952  DB_RESULT result; /* Result of query */
953  KSM_KEYDATA data; /* key information */
954  char* sql = NULL; /* SQL query */
955  int clause = 0;
956 
957  /* Find all the keys which are on that zone but are not already dead */
958  sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS);
959  DqsConditionInt(&sql, "state", DQS_COMPARE_LT, KSM_STATE_DEAD, clause++);
960  DqsConditionInt(&sql, "state", DQS_COMPARE_GT, KSM_STATE_GENERATE, clause++);
961  if (zone_id != -1) {
962  DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, clause++);
963  }
964  DqsEnd(&sql);
965 
966  /* Now iterate round the keys meeting the condition and print them */
967 
968  status = KsmKeyInitSql(&result, sql);
969  if (status == 0) {
970  status = KsmKey(result, &data);
971  while (status == 0) {
972 
973  /* Kill the Key */
974  status = KsmKillKey(data.keypair_id, zone_id);
975  if (status == 0) {
976  status = KsmKey(result, &data);
977  }
978  }
979 
980  /* Convert EOF status to success */
981 
982  if (status == -1) {
983  status = 0;
984  }
985 
986  KsmKeyEnd(result);
987  }
988 
989  DqsFree(sql);
990  return 0;
991 }
992 
993 /*+
994  * KsmKillKey - Update key status to "dead"
995  *
996  * Description:
997  * Changes a keys status to dead (from any state)
998  *
999  * Arguments:
1000  * int keypair_id
1001  * Which key to process
1002  * int zone_id
1003  * Which zone to process
1004  *
1005  * Returns:
1006  * int
1007  * Status return. 0=> Success, non-zero => error.
1008 -*/
1009 
1010 int KsmKillKey(int keypair_id, int zone_id)
1011 {
1012  int status = 0; /* Status return */
1013  char* sql = NULL; /* SQL Statement */
1014  int set = 0;
1015  char* now = DtParseDateTimeString("now");
1016 
1017  /* Check datetime in case it came back NULL */
1018  if (now == NULL) {
1019  printf("Couldn't turn \"now\" into a date, quitting...\n");
1020  exit(1);
1021  }
1022 
1023  sql = DusInit("dnsseckeys");
1024  DusSetInt(&sql, "STATE", KSM_STATE_DEAD, set++);
1025  DusSetString(&sql, "DEAD", now, set++);
1026  DusConditionInt(&sql, "KEYPAIR_ID", DQS_COMPARE_EQ, keypair_id, 0);
1027  if (zone_id != -1) {
1028  DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, 1);
1029  }
1030  DusEnd(&sql);
1031 
1032  /* Execute the statement */
1033 
1034  status = DbExecuteSqlNoResult(DbHandle(), sql);
1035  DusFree(sql);
1036 
1037  StrFree(now);
1038 
1039  return status;
1040 }
1041 
void DbFreeResult(DB_RESULT result)
#define DB_KEYDATA_ACTIVE
Definition: db_fields.h:64
int zone_id
Definition: ksm.h:117
char ready[KSM_TIME_LENGTH]
Definition: ksm.h:109
char dead[KSM_TIME_LENGTH]
Definition: ksm.h:106
#define DB_KEYDATA_PUBLISH
Definition: db_fields.h:62
#define KSM_TYPE_ZSK
Definition: ksm.h:359
#define StrFree(x)
Definition: string_util.h:68
#define KSM_INVARG
Definition: ksmdef.h:68
int DbFetchRow(DB_RESULT result, DB_ROW *row)
#define KSM_SQLFAIL
Definition: ksmdef.h:69
#define KSM_STATE_DEAD
Definition: ksm.h:372
int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char *datetime, int *count, int keytype)
Definition: ksm_key.c:734
union DQS_QUERY_CONDITION::@0 data
char * DqsSpecifyInit(const char *table, const char *fields)
Definition: dq_string.c:119
#define KSM_STATE_ACTIVE
Definition: ksm.h:368
int kskttl
Definition: ksm.h:481
char location[KSM_NAME_LENGTH]
Definition: ksm.h:111
int pub_safety
Definition: ksm.h:484
int KsmKillKey(int keypair_id, int zone_id)
Definition: ksm_key.c:1010
#define DB_KEYDATA_ID
Definition: db_fields.h:59
#define KSM_STATE_READY
Definition: ksm.h:366
int KsmParameterZskTtl(KSM_PARCOLL *collection)
#define KSM_ROLL_DS
Definition: ksm.h:399
int state
Definition: ksm.h:101
int KsmParameterCollection(KSM_PARCOLL *data, int policy_id)
#define KSM_KEYS_NOT_SHARED
Definition: ksm.h:392
void DusFree(char *sql)
Definition: du_string.c:225
DQS_COMPARISON compare
char retire[KSM_TIME_LENGTH]
Definition: ksm.h:110
void DqsConditionKeyword(char **query, const char *field, DQS_COMPARISON compare, const char *value, int index)
Definition: dq_string.c:253
int dsttl
Definition: ksm.h:488
char * DisSpecifyInit(const char *table, const char *cols)
Definition: di_string.c:101
#define DB_KEYDATA_ZONE_ID
Definition: db_fields.h:70
int MsgLog(int status,...)
Definition: message.c:337
int KsmKeyPairCreate(int policy_id, const char *HSMKeyID, int smID, int size, int alg, const char *generate, DB_ID *id)
Definition: ksm_key.c:86
void DusSetInt(char **sql, const char *field, int data, int clause)
Definition: du_string.c:99
void DqsFree(char *query)
Definition: dq_string.c:322
#define KSM_ROLL_DNSKEY
Definition: ksm.h:397
int ksklife
Definition: ksm.h:471
int KsmParameterKskTtl(KSM_PARCOLL *collection)
void DusConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int clause)
Definition: du_string.c:172
const char * KsmKeywordStateValueToName(int value)
Definition: ksm_keyword.c:244
char * DqsCountInit(const char *table)
Definition: dq_string.c:92
int KsmMarkKeysAsDead(int zone_id)
Definition: ksm_key.c:948
DB_HANDLE DbHandle(void)
int KsmParameterKskPropagationDelay(KSM_PARCOLL *collection)
char * StrStrdup(const char *string)
Definition: string_util.c:126
int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count)
Definition: ksm_key.c:564
void DqsConditionInt(char **query, const char *field, DQS_COMPARISON compare, int value, int index)
Definition: dq_string.c:226
#define DB_KEYDATA_READY
Definition: db_fields.h:63
char * DtParseDateTimeString(const char *string)
Definition: datetime.c:617
#define KSM_STATE_DSPUBLISH
Definition: ksm.h:376
#define DB_KEYDATA_STATE
Definition: db_fields.h:60
int DbLastRowId(DB_HANDLE handle, DB_ID *id)
int KsmKeyInitSql(DB_RESULT *result, const char *sql)
Definition: ksm_key.c:219
unsigned long DB_ID
Definition: database.h:80
#define DB_KEYDATA_FIELDS
Definition: db_fields.h:58
const char * DbErrmsg(DB_HANDLE handle)
void DisAppendString(char **sql, const char *what)
Definition: di_string.c:144
int propdelay
Definition: ksm.h:474
#define DB_KEYDATA_FIXED_DATE
Definition: db_fields.h:71
void DbFreeRow(DB_ROW row)
int KsmParameterPropagationDelay(KSM_PARCOLL *collection)
int KsmKeyCountQueue(int keytype, int *count, int zone_id)
Definition: ksm_key.c:655
#define DB_KEYDATA_GENERATE
Definition: db_fields.h:61
int DbExecuteSql(DB_HANDLE handle, const char *stmt_str, DB_RESULT *result)
int keytype
Definition: ksm.h:102
void DisEnd(char **sql)
Definition: di_string.c:172
int DbStringBuffer(DB_ROW row, int field_index, char *buffer, size_t buflen)
#define KME_SQLFAIL
Definition: kmedef.h:69
int KsmKeyInitId(DB_RESULT *result, DB_ID id)
Definition: ksm_key.c:328
void StrAppend(char **str1, const char *str2)
Definition: string_util2.c:78
int fixedDate
Definition: ksm.h:118
int algorithm
Definition: ksm.h:103
void DusEnd(char **sql)
Definition: du_string.c:204
int DbIntQuery(DB_HANDLE handle, int *value, const char *query)
int KsmKeyInit(DB_RESULT *result, DQS_QUERY_CONDITION *condition)
Definition: ksm_key.c:251
char generate[KSM_TIME_LENGTH]
Definition: ksm.h:107
#define KSM_STATE_RETIRE
Definition: ksm.h:370
#define KSM_STATE_PUBLISH
Definition: ksm.h:364
int DbUnsignedLong(DB_ROW row, int field_index, unsigned long *value)
char * DusInit(const char *table)
Definition: du_string.c:62
int KsmParameterPubSafety(KSM_PARCOLL *collection)
int standbyzsks
Definition: ksm.h:473
DB_ID keypair_id
Definition: ksm.h:100
void DisFree(char *sql)
Definition: di_string.c:193
int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, const char *time, const char *retTime, DB_ID *id)
Definition: ksm_key.c:143
int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id)
Definition: ksm_key.c:872
int kskpropdelay
Definition: ksm.h:482
#define KME_BUFFEROVF
Definition: kmedef.h:50
#define DB_KEYDATA_RETIRE
Definition: db_fields.h:65
#define DB_KEYDATA_KEYTYPE
Definition: db_fields.h:67
int KsmKeyData(DB_ID id, KSM_KEYDATA *data)
Definition: ksm_key.c:500
char publish[KSM_TIME_LENGTH]
Definition: ksm.h:108
int zsklife
Definition: ksm.h:479
#define KSM_STATE_DSSUB
Definition: ksm.h:374
#define KME_UNRCONCOD
Definition: kmedef.h:71
#define KSM_TYPE_KSK
Definition: ksm.h:357
int DbInt(DB_ROW row, int field_index, int *value)
#define DB_KEYDATA_DEAD
Definition: db_fields.h:66
void DisAppendInt(char **sql, int what)
Definition: di_string.c:133
#define DB_KEYDATA_ALGORITHM
Definition: db_fields.h:68
#define KSM_STATE_DSREADY
Definition: ksm.h:378
int standbyksks
Definition: ksm.h:472
#define KME_UNKEYTYPE
Definition: kmedef.h:70
int KsmKey(DB_RESULT result, KSM_KEYDATA *data)
Definition: ksm_key.c:368
#define KSM_STATE_GENERATE
Definition: ksm.h:362
void DusSetString(char **sql, const char *field, const char *data, int clause)
Definition: du_string.c:115
void DqsEnd(char **query)
Definition: dq_string.c:301
int DbExecuteSqlNoResult(DB_HANDLE handle, const char *stmt_str)
void KsmKeyEnd(DB_RESULT result)
Definition: ksm_key.c:471
#define DB_KEYDATA_LOCATION
Definition: db_fields.h:69
char active[KSM_TIME_LENGTH]
Definition: ksm.h:105