OpenDNSSEC-enforcer 1.3.0
|
00001 /* 00002 * $Id: ksm_key.c 5320 2011-07-12 10:42:26Z jakob $ 00003 * 00004 * Copyright (c) 2008-2009 Nominet UK. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00029 /*+ 00030 * KsmKey - Manipulation of Key Information 00031 * 00032 * Description: 00033 * Holds the functions needed to manipulate the KEYDATA table. 00034 * 00035 * N.B. The table is the KEYDATA table - rather than the KEY table - as 00036 * KEY is a reserved word in SQL. 00037 -*/ 00038 00039 #include <assert.h> 00040 #include <stdio.h> 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <time.h> 00044 00045 #include "ksm/database.h" 00046 #include "ksm/database_statement.h" 00047 #include "ksm/datetime.h" 00048 #include "ksm/db_fields.h" 00049 #include "ksm/debug.h" 00050 #include "ksm/kmedef.h" 00051 #include "ksm/ksm.h" 00052 #include "ksm/ksmdef.h" 00053 #include "ksm/ksm_internal.h" 00054 #include "ksm/message.h" 00055 #include "ksm/string_util.h" 00056 #include "ksm/string_util2.h" 00057 00058 /*+ 00059 * KsmKeyPairCreate - Create Entry in the KeyPairs table 00060 * (i.e. key creation in the HSM) 00061 * 00062 * Description: 00063 * Creates a key in the database. 00064 * 00065 * Arguments: 00066 * policy_id 00067 * policy that the key is created for 00068 * HSMKeyID 00069 * ID the key is refered to in the HSM 00070 * smID 00071 * security module ID 00072 * size 00073 * size of key 00074 * alg 00075 * algorithm used 00076 * generate 00077 * timestamp of generation 00078 * 00079 * DB_ID* id (returned) 00080 * ID of the created entry. This will be undefined on error. 00081 * 00082 * Returns: 00083 * int 00084 * Status return. 0=> Success, non-zero => error. 00085 -*/ 00086 int KsmKeyPairCreate(int policy_id, const char* HSMKeyID, int smID, int size, int alg, const char* generate, DB_ID* id) 00087 { 00088 unsigned long rowid; /* ID of last inserted row */ 00089 int status = 0; /* Status return */ 00090 char* sql = NULL; /* SQL Statement */ 00091 00092 /* Check arguments */ 00093 if (id == NULL) { 00094 return MsgLog(KSM_INVARG, "NULL id"); 00095 } 00096 00097 sql = DisSpecifyInit("keypairs", "policy_id, HSMkey_id, securitymodule_id, size, algorithm, generate"); 00098 DisAppendInt(&sql, policy_id); 00099 DisAppendString(&sql, HSMKeyID); 00100 DisAppendInt(&sql, smID); 00101 DisAppendInt(&sql, size); 00102 DisAppendInt(&sql, alg); 00103 DisAppendString(&sql, generate); 00104 DisEnd(&sql); 00105 00106 /* Execute the statement */ 00107 00108 status = DbExecuteSqlNoResult(DbHandle(), sql); 00109 DisFree(sql); 00110 00111 if (status == 0) { 00112 00113 /* Succcess, get the ID of the inserted record */ 00114 00115 status = DbLastRowId(DbHandle(), &rowid); 00116 if (status == 0) { 00117 *id = (DB_ID) rowid; 00118 } 00119 } 00120 00121 return status; 00122 } 00123 00124 /*+ 00125 * KsmDnssecKeyCreate - Create Entry in Dnsseckeys table 00126 * (i.e. when a key is assigned to a policy/zone) 00127 * 00128 * Description: 00129 * Allocates a key in the database. 00130 * 00131 * Arguments: 00132 * KSM_KEY* data 00133 * Data to insert into the database. The ID argument is ignored. 00134 * 00135 * DB_ID* id (returned) 00136 * ID of the created entry. This will be undefined on error. 00137 * 00138 * Returns: 00139 * int 00140 * Status return. 0=> Success, non-zero => error. 00141 -*/ 00142 00143 int KsmDnssecKeyCreate(int zone_id, int keypair_id, int keytype, int state, const char* time, DB_ID* id) 00144 { 00145 unsigned long rowid; /* ID of last inserted row */ 00146 int status = 0; /* Status return */ 00147 char* sql = NULL; /* SQL Statement */ 00148 char* columns = NULL; /* what columns are we setting */ 00149 00150 /* Check arguments */ 00151 if (id == NULL) { 00152 return MsgLog(KSM_INVARG, "NULL id"); 00153 } 00154 00155 StrAppend(&columns, "zone_id, keypair_id, keytype, state"); 00156 if (state != KSM_STATE_GENERATE) { 00157 StrAppend(&columns, ", "); 00158 StrAppend(&columns, KsmKeywordStateValueToName(state)); 00159 } 00160 00161 sql = DisSpecifyInit("dnsseckeys", columns); 00162 DisAppendInt(&sql, zone_id); 00163 DisAppendInt(&sql, keypair_id); 00164 DisAppendInt(&sql, keytype); 00165 DisAppendInt(&sql, state); 00166 if (state != KSM_STATE_GENERATE) { 00167 DisAppendString(&sql, time); 00168 } 00169 DisEnd(&sql); 00170 00171 /* Execute the statement */ 00172 00173 status = DbExecuteSqlNoResult(DbHandle(), sql); 00174 DisFree(sql); 00175 StrFree(columns); 00176 00177 if (status == 0) { 00178 00179 /* Succcess, get the ID of the inserted record */ 00180 00181 status = DbLastRowId(DbHandle(), &rowid); 00182 if (status == 0) { 00183 *id = (DB_ID) rowid; 00184 } 00185 } 00186 00187 return status; 00188 } 00189 00190 /*+ 00191 * KsmKeyInitSql - Query for Key Information With Sql Query 00192 * 00193 * Description: 00194 * Performs a query for keys in the keydata table that match the given 00195 * conditions. 00196 * 00197 * Arguments: 00198 * DB_RESULT* result 00199 * Pointer to a result to be used for information retrieval. Will 00200 * be NULL on error. 00201 * 00202 * const char* sql 00203 * SQL statement to select keys. 00204 * 00205 * (Actually, the statement could be anything, but it is assumed 00206 * that it is an SQL statement starting "SELECT xxx FROM KEYDATA".) 00207 * 00208 * Returns: 00209 * int 00210 * Status return. 0 on success. 00211 -*/ 00212 00213 int KsmKeyInitSql(DB_RESULT* result, const char* sql) 00214 { 00215 return DbExecuteSql(DbHandle(), sql, result); 00216 } 00217 00218 00219 00220 00221 /*+ 00222 * KsmKeyInit - Query for Key Information 00223 * 00224 * Description: 00225 * Performs a query for keys in the keydata table that match the given 00226 * conditions. 00227 * 00228 * Arguments: 00229 * DB_RESULT* result 00230 * Pointer to a result to be used for information retrieval. Will 00231 * be NULL on error. 00232 * 00233 * DQS_QUERY_CONDITION* condition 00234 * Array of condition objects, each defining a condition. The 00235 * conditions are ANDed together. The array should end with an object 00236 * with a condition code of 0. 00237 * 00238 * If NULL, all objects are selected. 00239 * 00240 * Returns: 00241 * int 00242 * Status return. 0 on success. 00243 -*/ 00244 00245 int KsmKeyInit(DB_RESULT* result, DQS_QUERY_CONDITION* condition) 00246 { 00247 int i; /* Condition index */ 00248 char* sql = NULL; /* SQL query */ 00249 int status = 0; /* Status return */ 00250 00251 /* Construct the query */ 00252 00253 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 00254 if (condition) { 00255 for (i = 0; condition[i].compare != DQS_END_OF_LIST; ++i) { 00256 switch (condition[i].code) { 00257 case DB_KEYDATA_ALGORITHM: 00258 DqsConditionInt(&sql, "ALGORITHM", condition[i].compare, 00259 condition[i].data.number, i); 00260 break; 00261 00262 case DB_KEYDATA_ID: 00263 DqsConditionInt(&sql, "ID", condition[i].compare, 00264 condition[i].data.number, i); 00265 break; 00266 00267 case DB_KEYDATA_KEYTYPE: 00268 DqsConditionInt(&sql, "KEYTYPE", condition[i].compare, 00269 condition[i].data.number, i); 00270 break; 00271 00272 case DB_KEYDATA_STATE: 00273 DqsConditionInt(&sql, "STATE", condition[i].compare, 00274 condition[i].data.number, i); 00275 break; 00276 00277 case DB_KEYDATA_ZONE_ID: 00278 DqsConditionInt(&sql, "ZONE_ID", condition[i].compare, 00279 condition[i].data.number, i); 00280 break; 00281 00282 default: 00283 00284 /* Warn about unrecognised condition code */ 00285 00286 MsgLog(KME_UNRCONCOD, condition[i].code); 00287 } 00288 } 00289 } 00290 DqsEnd(&sql); 00291 00292 /* Execute query and free up the query string */ 00293 00294 status = KsmKeyInitSql(result, sql); 00295 DqsFree(sql); 00296 00297 return status; 00298 } 00299 00300 00301 00302 /*+ 00303 * KsmKeyInitId - Query for Key Information by ID 00304 * 00305 * Description: 00306 * Performs a query for a key in the zone table that matches the 00307 * given ID. 00308 * 00309 * Arguments: 00310 * DB_RESULT* result 00311 * Pointer to a result to be used for information retrieval. Will 00312 * be NULL on error. 00313 * 00314 * DB_ID id 00315 * ID of the object. 00316 * 00317 * Returns: 00318 * int 00319 * Status return. 0 on success. 00320 -*/ 00321 00322 int KsmKeyInitId(DB_RESULT* result, DB_ID id) 00323 { 00324 DQS_QUERY_CONDITION condition[2]; /* Condition for query */ 00325 00326 /* Initialize */ 00327 00328 condition[0].code = DB_KEYDATA_ID; 00329 condition[0].compare = DQS_COMPARE_EQ; 00330 condition[0].data.number = (int) id; 00331 00332 condition[1].compare = DQS_END_OF_LIST; 00333 00334 return KsmKeyInit(result, condition); 00335 } 00336 00337 00338 00339 /*+ 00340 * KsmKey - Return Key Information 00341 * 00342 * Description: 00343 * Returns information about the next key in the result set. 00344 * 00345 * Arguments: 00346 * DB_RESULT result 00347 * Handle from KsmKeyInit 00348 * 00349 * KSM_KEYDATA* data 00350 * Data is returned in here. 00351 * 00352 * Returns: 00353 * int 00354 * Status return: 00355 * 0 success 00356 * -1 end of record set reached 00357 * non-zero some error occurred and a message has been output. 00358 * 00359 * If the status is non-zero, the returned data is meaningless. 00360 -*/ 00361 00362 int KsmKey(DB_RESULT result, KSM_KEYDATA* data) 00363 { 00364 DB_ROW row = NULL; /* Row data */ 00365 int status = 0; /* Return status */ 00366 00367 /* Check arguments */ 00368 if (data == NULL) { 00369 return MsgLog(KSM_INVARG, "NULL data"); 00370 } 00371 00372 /* Initialize */ 00373 00374 memset(data, 0, sizeof(KSM_KEYDATA)); 00375 00376 /* Get the next row from the data and copy data across */ 00377 00378 status = DbFetchRow(result, &row); 00379 00380 if (status == 0) { 00381 status = DbUnsignedLong(row, DB_KEYDATA_ID, &(data->keypair_id)); 00382 } 00383 00384 if (status == 0) { 00385 status = DbInt(row, DB_KEYDATA_STATE, &(data->state)); 00386 } 00387 00388 if (status == 0) { 00389 status = DbStringBuffer(row, DB_KEYDATA_GENERATE, 00390 data->generate, sizeof(data->generate)); 00391 } 00392 00393 if (status == 0) { 00394 status = DbStringBuffer(row, DB_KEYDATA_PUBLISH, 00395 data->publish, sizeof(data->publish)); 00396 } 00397 00398 if (status == 0) { 00399 status = DbStringBuffer(row, DB_KEYDATA_READY, 00400 data->ready, sizeof(data->ready)); 00401 } 00402 00403 if (status == 0) { 00404 status = DbStringBuffer(row, DB_KEYDATA_ACTIVE, 00405 data->active, sizeof(data->active)); 00406 } 00407 00408 if (status == 0) { 00409 status = DbStringBuffer(row, DB_KEYDATA_RETIRE, 00410 data->retire, sizeof(data->retire)); 00411 } 00412 00413 if (status == 0) { 00414 status = DbStringBuffer(row, DB_KEYDATA_DEAD, 00415 data->dead, sizeof(data->dead)); 00416 } 00417 00418 if (status == 0) { 00419 status = DbInt(row, DB_KEYDATA_KEYTYPE, &(data->keytype)); 00420 } 00421 00422 if (status == 0) { 00423 status = DbInt(row, DB_KEYDATA_ALGORITHM, &(data->algorithm)); 00424 } 00425 00426 /* if (status == 0) { 00427 status = DbInt(row, DB_KEYDATA_SIGLIFETIME, &(data->siglifetime)); 00428 } 00429 */ 00430 if (status == 0) { 00431 status = DbStringBuffer(row, DB_KEYDATA_LOCATION, 00432 data->location, sizeof(data->location)); 00433 } 00434 00435 if (status == 0) { 00436 status = DbInt(row, DB_KEYDATA_ZONE_ID, &(data->zone_id)); 00437 } 00438 00439 if (status == 0) { 00440 status = DbInt(row, DB_KEYDATA_FIXED_DATE, &(data->fixedDate)); 00441 } 00442 00443 DbFreeRow(row); 00444 00445 return status; 00446 } 00447 00448 00449 /*+ 00450 * KsmKeyEnd - End Key Information 00451 * 00452 * Description: 00453 * Called at the end of a ksm_key cycle, frees up the stored 00454 * result set. 00455 * 00456 * N.B. This does not clear stored error information, so allowing it 00457 * to be called after a failure return from KsmKey to free up database 00458 * context whilst preserving the reason for the error. 00459 * 00460 * Arguments: 00461 * DB_RESULT result 00462 * Handle from KsmKeyInit 00463 -*/ 00464 00465 void KsmKeyEnd(DB_RESULT result) 00466 { 00467 DbFreeResult(result); 00468 } 00469 00470 00471 00472 /*+ 00473 * KsmKeyData - Return Data for Key 00474 * 00475 * Description: 00476 * Returns data for the named Key. 00477 * 00478 * Arguments: 00479 * DB_ID id 00480 * Name/ID of the Key. 00481 * 00482 * KSM_GROUP* data 00483 * Data for the Key. 00484 * 00485 * Returns: 00486 * int 00487 * Status return. One of: 00488 * 00489 * 0 Success 00490 * -1 Key not found 00491 * Other Error 00492 -*/ 00493 00494 int KsmKeyData(DB_ID id, KSM_KEYDATA* data) 00495 { 00496 DB_RESULT result; /* Handle to the data */ 00497 int status; /* Status return code */ 00498 00499 status = KsmKeyInitId(&result, id); 00500 if (status == 0) { 00501 00502 /* Retrieve the key data */ 00503 00504 status = KsmKey(result, data); 00505 (void) KsmKeyEnd(result); 00506 } 00507 /* 00508 * else { 00509 * On error, a message will have been output 00510 * } 00511 */ 00512 00513 return status; 00514 } 00515 00516 /*+ 00517 * KsmKeyPredict - predict how many keys are needed 00518 * 00519 * Description: 00520 * Given a policy and a keytype work out how many keys will be required 00521 * during the timeinterval specified (in seconds). 00522 * 00523 * We assume no emergency rollover and that a key has just been published 00524 * 00525 * Dt = interval 00526 * Sp = safety margin 00527 * Lk = lifetime of the key (either KSK or ZSK) 00528 * Ek = no of standby keys 00529 * 00530 * no of keys = ( (Dt + Sp)/Lk ) + Ek 00531 * 00532 * (rounded up) 00533 * 00534 * Arguments: 00535 * int policy_id 00536 * The policy in question 00537 * KSM_TYPE key_type 00538 * KSK or ZSK 00539 * int shared_keys 00540 * 0 if keys not shared between zones 00541 * int interval 00542 * timespan (in seconds) 00543 * int *count 00544 * (OUT) the number of keys (-1 on error) 00545 * int rollover_scheme 00546 * KSK rollover scheme in use 00547 * int zone_count 00548 * Number of zones on this policy 00549 * 00550 * Returns: 00551 * int 00552 * Status return. One of: 00553 * 00554 * 0 Success 00555 * Other Error 00556 -*/ 00557 00558 int KsmKeyPredict(int policy_id, int keytype, int shared_keys, int interval, int *count, int rollover_scheme, int zone_count) 00559 { 00560 int status = 0; /* Status return */ 00561 KSM_PARCOLL coll; /* Parameters collection */ 00562 00563 /* Check arguments */ 00564 if (count == NULL) { 00565 return MsgLog(KSM_INVARG, "NULL count"); 00566 } 00567 00568 /* make sure that we have at least one zone */ 00569 if (zone_count == 0) { 00570 *count = 0; 00571 return status; 00572 } 00573 00574 /* Check that we have a valid key type */ 00575 if ((keytype != KSM_TYPE_KSK) && (keytype != KSM_TYPE_ZSK)) { 00576 status = MsgLog(KME_UNKEYTYPE, keytype); 00577 return status; 00578 } 00579 00580 /* Get list of parameters */ 00581 status = KsmParameterCollection(&coll, policy_id); 00582 if (status != 0) { 00583 *count = -1; 00584 return status; 00585 } 00586 00587 /* We should have the policy now */ 00588 if (keytype == KSM_TYPE_KSK) 00589 { 00590 if (coll.ksklife == 0) { 00591 *count = coll.standbyksks + 1; 00592 } 00593 else if (rollover_scheme == KSM_ROLL_DNSKEY) { 00594 *count = ((interval + coll.pub_safety + coll.propdelay + coll.kskttl)/coll.ksklife) + coll.standbyksks + 1; 00595 } 00596 else if (rollover_scheme == KSM_ROLL_DS) { 00597 *count = ((interval + coll.pub_safety + coll.kskpropdelay + coll.dsttl)/coll.ksklife) + coll.standbyksks + 1; 00598 } 00599 /* else if (rollover_scheme == KSM_ROLL_RRSET) { 00600 temp = MAX((propdelay + kskttl), (kskpropdelay + dsttl)); 00601 if (RFC5011) { 00602 temp = max(temp, 30*24*60*60); 00603 } 00604 *count = ((interval + coll.pub_safety + temp)/coll.ksklife) + coll.standbyksks + 1; 00605 } */ 00606 00607 } 00608 else if (keytype == KSM_TYPE_ZSK) 00609 { 00610 if (coll.zsklife == 0) { 00611 *count = coll.standbyzsks + 1; 00612 } else { 00613 *count = ((interval + coll.pub_safety)/coll.zsklife) + coll.standbyzsks + 1; 00614 } 00615 } 00616 00617 if (shared_keys == KSM_KEYS_NOT_SHARED) { 00618 *count *= zone_count; 00619 } 00620 00621 return status; 00622 } 00623 00624 /*+ 00625 * KsmKeyCountQueue - Return Number of Keys in the queue before active state 00626 * 00627 * Description: 00628 * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH, 00629 * KSM_STATE_READY and KSM_STATE_ACTIVE state. 00630 * (plus KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY 00631 * for standby KSKs) 00632 * 00633 * Arguments: 00634 * int keytype 00635 * Key type, KSK or ZSK 00636 * 00637 * int* count (returned) 00638 * Number of keys in the que. 00639 * 00640 * int zone_id 00641 * ID of zone that we are looking at (-1 == all zones) 00642 * 00643 * Returns: 00644 * int 00645 * Status return. 0 => success, Other implies error, in which case a 00646 * message will have been output. 00647 -*/ 00648 00649 int KsmKeyCountQueue(int keytype, int* count, int zone_id) 00650 { 00651 int clause = 0; /* Clause count */ 00652 char* sql = NULL; /* SQL to interrogate database */ 00653 int status = 0; /* Status return */ 00654 char in[128]; /* Easily large enought for 7 keys */ 00655 size_t nchar; /* Number of output characters */ 00656 00657 /* Create the SQL command to interrogate the database */ 00658 00659 nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)", 00660 KSM_STATE_GENERATE, KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY); 00661 if (nchar >= sizeof(in)) { 00662 status = MsgLog(KME_BUFFEROVF, "KsmKeyCountQueue"); 00663 return status; 00664 } 00665 00666 sql = DqsCountInit("KEYDATA_VIEW"); 00667 DqsConditionInt(&sql, "KEYTYPE", DQS_COMPARE_EQ, keytype, clause++); 00668 DqsConditionKeyword(&sql, "STATE", DQS_COMPARE_IN, in, clause++); 00669 if (zone_id != -1) { 00670 DqsConditionInt(&sql, "ZONE_ID", DQS_COMPARE_EQ, zone_id, clause++); 00671 } 00672 DqsEnd(&sql); 00673 00674 /* Execute the query and free resources */ 00675 00676 status = DbIntQuery(DbHandle(), count, sql); 00677 DqsFree(sql); 00678 00679 /* Report any errors */ 00680 00681 if (status != 0) { 00682 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00683 } 00684 00685 return status; 00686 } 00687 00688 /*+ 00689 * KsmKeyCountStillGood - Return Number of Keys that will still be usable at a particular 00690 * time given a number of parameters 00691 * 00692 * Description: 00693 * Returns the number of keys in the KSM_STATE_GENERATE, KSM_STATE_PUBLISH, 00694 * KSM_STATE_READY, KSM_STATE_ACTIVE (or KSM_STATE_DSSUB, 00695 * KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY for standby KSKs) state after 00696 * the given interval. 00697 * 00698 * Arguments: 00699 * int policy_id 00700 * id of the policy for which they key must have been created 00701 * (-1 == all policies) 00702 * int sm 00703 * id of security module 00704 * (-1 == all modules) 00705 * int bits 00706 * size of key desired 00707 * (-1 == all sizes) 00708 * int algorithm 00709 * algorithm of key desired 00710 * (-1 == all algorithms`) 00711 * int interval 00712 * how many seconds in the future we are talking about 00713 * const char* datetime 00714 * string describing when this calculation is being run 00715 * 00716 * int* count (returned) 00717 * Number of keys in the que. 00718 * 00719 * int keytype 00720 * Key type, KSK or ZSK 00721 * 00722 * Returns: 00723 * int 00724 * Status return. 0 => success, Other implies error, in which case a 00725 * message will have been output. 00726 -*/ 00727 00728 int KsmKeyCountStillGood(int policy_id, int sm, int bits, int algorithm, int interval, const char* datetime, int *count, int keytype) 00729 { 00730 int where = 0; /* WHERE clause value */ 00731 char* sql = NULL; /* SQL to interrogate database */ 00732 int status = 0; /* Status return */ 00733 char in[128]; /* Easily large enought for three keys */ 00734 char buffer[512]; /* For constructing part of the command */ 00735 size_t nchar; /* Number of output characters */ 00736 int total_interval; /* interval plus retirement time */ 00737 KSM_PARCOLL collection; /* Parameters collection */ 00738 00739 /* 00740 * Construct the "IN" statement listing the states of the keys that 00741 * are included in the output. 00742 */ 00743 00744 /* Get list of parameters */ 00745 status = KsmParameterCollection(&collection, policy_id); 00746 if (status != 0) { 00747 return status; 00748 } 00749 00750 if (keytype == KSM_TYPE_ZSK) 00751 { 00752 total_interval = KsmParameterZskTtl(&collection) + 00753 KsmParameterPropagationDelay(&collection) + 00754 KsmParameterPubSafety(&collection) + 00755 interval; 00756 } else { 00757 total_interval = KsmParameterKskTtl(&collection) + 00758 KsmParameterKskPropagationDelay(&collection) + 00759 KsmParameterPubSafety(&collection) + 00760 interval; 00761 } 00762 00763 nchar = snprintf(in, sizeof(in), "(%d, %d, %d, %d, %d, %d, %d)", 00764 KSM_STATE_GENERATE, KSM_STATE_PUBLISH, KSM_STATE_READY, KSM_STATE_ACTIVE, KSM_STATE_DSSUB, KSM_STATE_DSPUBLISH, KSM_STATE_DSREADY); 00765 if (nchar >= sizeof(in)) { 00766 status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood"); 00767 return status; 00768 } 00769 00770 /* 00771 * TODO is there an alternative to DATE_ADD which is more generic? 00772 */ 00773 #ifdef USE_MYSQL 00774 nchar = snprintf(buffer, sizeof(buffer), 00775 "DATE_ADD('%s', INTERVAL %d SECOND)", datetime, total_interval); 00776 #else 00777 nchar = snprintf(buffer, sizeof(buffer), 00778 "DATETIME('%s', '+%d SECONDS')", datetime, total_interval); 00779 #endif /* USE_MYSQL */ 00780 if (nchar >= sizeof(buffer)) { 00781 status = MsgLog(KME_BUFFEROVF, "KsmKeyCountStillGood"); 00782 return status; 00783 } 00784 00785 /* Create the SQL command to interrogate the database */ 00786 00787 sql = DqsCountInit("KEYDATA_VIEW"); 00788 if (policy_id != -1) { 00789 DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++); 00790 } 00791 if (sm != -1) { 00792 DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++); 00793 } 00794 if (bits != -1) { 00795 DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++); 00796 } 00797 if (algorithm != -1) { 00798 DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++); 00799 } 00800 00801 DqsConditionKeyword(&sql, "(STATE", DQS_COMPARE_IN, in, where++); 00802 StrAppend(&sql, " or STATE is NULL)"); 00803 00804 /* Can't use our generic functions for this aggregated clause */ 00805 #ifdef USE_MYSQL 00806 StrAppend(&sql, " and (RETIRE > "); 00807 #else 00808 StrAppend(&sql, " and (DATETIME(RETIRE) > "); 00809 #endif /* USE_MYSQL */ 00810 StrAppend(&sql, buffer); 00811 StrAppend(&sql, " or RETIRE is NULL)"); 00812 00813 /*DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++);*/ 00814 DqsEnd(&sql); 00815 00816 /* Execute the query and free resources */ 00817 00818 status = DbIntQuery(DbHandle(), count, sql); 00819 DqsFree(sql); 00820 00821 /* Report any errors */ 00822 00823 if (status != 0) { 00824 status = MsgLog(KME_SQLFAIL, DbErrmsg(DbHandle())); 00825 } 00826 00827 return status; 00828 } 00829 00830 /*+ 00831 * KsmKeyGetUnallocated 00832 * 00833 * Description: 00834 * Given a set of policy values get the next unallocated keypair 00835 * Executes: 00836 * select min(id) from keydata 00837 * where policy_id = policy_id 00838 * and securitymodule_id = sm 00839 * and size = bits 00840 * and algorithm = algorithm 00841 * and state is KSM_STATE_GENERATE 00842 * 00843 * Arguments: 00844 * int policy_id 00845 * id of the policy for which they key must have been created 00846 * int sm 00847 * id of security module 00848 * int bits 00849 * size of key desired 00850 * int algorithm 00851 * algorithm of key desired 00852 * int zone_id 00853 * zone we are allocating to 00854 * int share_keys 00855 * 0 if keys are not shared; 1 if they are 00856 * int *keypair_id (out) 00857 * id of next keypair 00858 * 00859 * Returns: 00860 * int 00861 * Status return. 0=> Success, non-zero => error. 00862 * -1 == no free keys on that policy 00863 */ 00864 00865 int KsmKeyGetUnallocated(int policy_id, int sm, int bits, int algorithm, int zone_id, int share_keys, int *keypair_id) 00866 { 00867 00868 int where = 0; /* WHERE clause value */ 00869 char* sql = NULL; /* SQL query */ 00870 DB_RESULT result; /* Handle converted to a result object */ 00871 DB_ROW row = NULL; /* Row data */ 00872 int status = 0; /* Status return */ 00873 char in_sql[1024]; 00874 char in_sql2[1024]; 00875 00876 if (share_keys == KSM_KEYS_NOT_SHARED) { 00877 /* Construct the query */ 00878 sql = DqsSpecifyInit("KEYDATA_VIEW","min(id)"); 00879 DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++); 00880 DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++); 00881 DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++); 00882 DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++); 00883 DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++); 00884 } else { 00885 snprintf(in_sql, 1024, "(select id from KEYALLOC_VIEW where zone_id = %d)", zone_id); 00886 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); 00887 00888 /* Construct the query */ 00889 sql = DqsSpecifyInit("KEYALLOC_VIEW","min(id)"); 00890 DqsConditionInt(&sql, "policy_id", DQS_COMPARE_EQ, policy_id, where++); 00891 DqsConditionInt(&sql, "securitymodule_id", DQS_COMPARE_EQ, sm, where++); 00892 DqsConditionInt(&sql, "size", DQS_COMPARE_EQ, bits, where++); 00893 DqsConditionInt(&sql, "algorithm", DQS_COMPARE_EQ, algorithm, where++); 00894 DqsConditionKeyword(&sql, "zone_id", DQS_COMPARE_IS, "NULL", where++); 00895 DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql, where++); 00896 DqsConditionKeyword(&sql, "id", DQS_COMPARE_NOT_IN, in_sql2, where++); 00897 } 00898 /* Execute query and free up the query string */ 00899 status = DbExecuteSql(DbHandle(), sql, &result); 00900 DqsFree(sql); 00901 00902 if (status != 0) 00903 { 00904 status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle())); 00905 DbFreeResult(result); 00906 return status; 00907 } 00908 00909 /* Get the next row from the data */ 00910 status = DbFetchRow(result, &row); 00911 if (status == 0) { 00912 DbInt(row, DB_KEYDATA_ID, keypair_id); 00913 } 00914 else if (status == -1) {} 00915 /* No rows to return (but no DB error) */ 00916 else { 00917 status = MsgLog(KSM_SQLFAIL, DbErrmsg(DbHandle())); 00918 } 00919 00920 DbFreeRow(row); 00921 DbFreeResult(result); 00922 return status; 00923 } 00924 00925 /*+ 00926 * KsmMarkKeysAsDead - When deleting zones we may need to indicate that keys are now dead 00927 * (i.e. when keysharing is turned off or if we removed is the last zone on a policy) 00928 * 00929 * Description: 00930 * Marks selected keys as dead in the database. 00931 * 00932 * Arguments: 00933 * int zone_id 00934 * ID of the zone (-1 if all zones are being removed) 00935 * 00936 * Returns: 00937 * int 00938 * Status return. 0=> Success, non-zero => error. 00939 -*/ 00940 00941 int KsmMarkKeysAsDead(int zone_id) 00942 { 00943 int status = 0; 00944 00945 DB_RESULT result; /* Result of query */ 00946 KSM_KEYDATA data; /* key information */ 00947 char* sql = NULL; /* SQL query */ 00948 int clause = 0; 00949 00950 /* Find all the keys which are on that zone but are not already dead */ 00951 sql = DqsSpecifyInit("KEYDATA_VIEW", DB_KEYDATA_FIELDS); 00952 DqsConditionInt(&sql, "state", DQS_COMPARE_LT, KSM_STATE_DEAD, clause++); 00953 DqsConditionInt(&sql, "state", DQS_COMPARE_GT, KSM_STATE_GENERATE, clause++); 00954 if (zone_id != -1) { 00955 DqsConditionInt(&sql, "zone_id", DQS_COMPARE_EQ, zone_id, clause++); 00956 } 00957 DqsEnd(&sql); 00958 00959 /* Now iterate round the keys meeting the condition and print them */ 00960 00961 status = KsmKeyInitSql(&result, sql); 00962 if (status == 0) { 00963 status = KsmKey(result, &data); 00964 while (status == 0) { 00965 00966 /* Kill the Key */ 00967 status = KsmKillKey(data.keypair_id); 00968 if (status == 0) { 00969 status = KsmKey(result, &data); 00970 } 00971 } 00972 00973 /* Convert EOF status to success */ 00974 00975 if (status == -1) { 00976 status = 0; 00977 } 00978 00979 KsmKeyEnd(result); 00980 } 00981 00982 return 0; 00983 } 00984 00985 /*+ 00986 * KsmKillKey - Update key status to "dead" 00987 * 00988 * Description: 00989 * Changes a keys status to dead (from any state) 00990 * 00991 * Arguments: 00992 * int keypair_id 00993 * Which key to process 00994 * 00995 * Returns: 00996 * int 00997 * Status return. 0=> Success, non-zero => error. 00998 -*/ 00999 01000 int KsmKillKey(int keypair_id) 01001 { 01002 int status = 0; /* Status return */ 01003 char* sql = NULL; /* SQL Statement */ 01004 int set = 0; 01005 char* now = DtParseDateTimeString("now"); 01006 01007 /* Check datetime in case it came back NULL */ 01008 if (now == NULL) { 01009 printf("Couldn't turn \"now\" into a date, quitting...\n"); 01010 exit(1); 01011 } 01012 01013 sql = DusInit("dnsseckeys"); 01014 DusSetInt(&sql, "STATE", KSM_STATE_DEAD, set++); 01015 DusSetString(&sql, "DEAD", now, set++); 01016 DusConditionInt(&sql, "ID", DQS_COMPARE_EQ, keypair_id, 0); 01017 DusEnd(&sql); 01018 01019 /* Execute the statement */ 01020 01021 status = DbExecuteSqlNoResult(DbHandle(), sql); 01022 DusFree(sql); 01023 01024 StrFree(now); 01025 01026 return status; 01027 } 01028