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